Phpipam Configuration

This role populates phpIPAM with the homelab network infrastructure via the phpIPAM REST API.

ARA Ansible Bash Docker Grafana HTTPS MariaDB MySQL

phpIPAM Configuration Role

Overview

This role populates phpIPAM with the homelab network infrastructure via the phpIPAM REST API. It creates sections, VLANs, subnets, device types, devices, and IP addresses with full interface and switch port metadata. The role uses “App code with SSL” authentication and is fully idempotent.

Purpose

  • IP Address Management: Register all static IPs in phpIPAM
  • Device Inventory: Create devices with types, descriptions, and management IPs
  • Network Documentation: Store interface names, switch port numbers, tagged/untagged info
  • VLAN/Subnet Mapping: Associate subnets with VLANs under a dedicated section
  • Gateway Tracking: Mark gateway addresses (OPNsense interfaces, ISP router)
  • Code as Configuration: Define the entire network infrastructure in YAML
  • Idempotent: Safe to run multiple times - existing resources are skipped

Requirements

  • Ansible 2.9 or higher
  • phpIPAM instance with API access enabled
  • API application created with “App code with SSL” authentication
  • API token stored in Ansible Vault as vault_phpipam_configuration_api_token
  • Network connectivity to the phpIPAM instance
  • Valid SSL certificate on phpIPAM (or set validate_certs: false)

Role Variables

Required Variables

VariableRequiredDescription
vault_phpipam_configuration_api_tokenYesphpIPAM API token (in vault)
phpipam_configuration_vlansYesList of VLANs and subnets (loaded from vars/vlans.yml)
phpipam_configuration_device_typesYesList of device types (loaded from vars/device_types.yml)
phpipam_configuration_devicesYesList of devices and their addresses (loaded from vars/devices.yml)

Optional Variables

VariableDefaultDescription
phpipam_configuration_api_urlhttps://server.homelab/apiphpIPAM API base URL
phpipam_configuration_api_app_idansiblephpIPAM API application ID
phpipam_configuration_section_nameHomelabSection name in phpIPAM
phpipam_configuration_section_descriptionHomelab infrastructureSection description

Variable Details

phpipam_configuration_vlans

List of VLANs and their associated subnets. Defined in vars/vlans.yml.

Structure:

phpipam_configuration_vlans:
  - name: "VLAN10"
    number: 10
    description: "Management network"
    subnet: "192.168.x.x"
    mask: 24

Field descriptions:

FieldRequiredDescription
nameYesVLAN display name (used as key for idempotency and subnet association)
numberYes802.1Q VLAN ID (0 for non-VLAN networks like Wireguard)
descriptionYesHuman-readable description of the network purpose
subnetYesNetwork address of the subnet
maskYesCIDR prefix length

phpipam_configuration_device_types

List of device types to create. Defined in vars/device_types.yml.

Structure:

phpipam_configuration_device_types:
  - name: "Server"
    description: "Server / Virtual machine"

Field descriptions:

FieldRequiredDescription
nameYesDevice type name (must match the type field in devices)
descriptionYesHuman-readable description of the device category

Note: phpIPAM ships with built-in types (Switch, Router, Firewall, Hub, Wireless, Database, Workstation, Laptop, Other). Existing types are skipped automatically.

phpipam_configuration_devices

List of devices with their IP addresses and metadata. Defined in vars/devices.yml.

Structure:

phpipam_configuration_devices:
  - hostname: "grafana"
    type: "Server"
    description: "Grafana monitoring server"
    management_ip: "{{ hostvars['grafana']['ip_vlan10'] }}"
    addresses:
      - ip: "{{ hostvars['grafana']['ip_vlan10'] }}"
        vlan: "VLAN10"
        interface: "ens19"
      - ip: "{{ hostvars['grafana']['ip_vlan12'] }}"
        vlan: "VLAN12"
        interface: "ens18"

Device field descriptions:

FieldRequiredDescription
hostnameYesDevice hostname (used as key for idempotency)
typeYesDevice type name (must match an entry in device_types.yml)
descriptionYesHuman-readable description (stored on the device record)
management_ipYesPrimary management IP (used as ip_addr in phpIPAM)
addressesYesList of IP addresses to register for this device

Address field descriptions:

FieldRequiredDefaultDescription
ipYes-IP address to register
vlanYes-VLAN name (must match an entry in vlans.yml)
interfaceYes-Network interface name (stored in phpIPAM port field)
is_gatewayNofalseMark as gateway address
noteNo""Free text (switch port, tagged/untagged, trunk info)

IP sources: IPs from inventory hosts use hostvars lookups. IPs for devices not in inventory are hardcoded directly.

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • phpIPAM instance running and accessible
  • API application with “App code with SSL” authentication
  • Ansible Vault for storing the API token
  • Inventory must be loaded before running (for hostvars lookups)

Workflow

  1. Create section: Create the “Homelab” section if it doesn’t exist
  2. Create VLANs: Create VLANs that don’t already exist (matched by name)
  3. Create subnets: Create subnets linked to their VLANs and section (matched by subnet address)
  4. Create device types: Create device types that don’t already exist (matched by name)
  5. Create devices: Create devices with management IP, type, and description (matched by hostname)
  6. Create IP addresses: Register IPs linked to devices, with interface, note, and gateway flag (matched by IP)

All steps are idempotent: existing resources are skipped.

Example Playbook

---
- name: Configure phpIPAM with homelab infrastructure
  hosts: mint-vm
  gather_facts: false

  pre_tasks:
    - name: Load VLANs configuration
      ansible.builtin.include_vars:
        file: "{{ playbook_dir }}/../roles/phpipam_configuration/vars/vlans.yml"

    - name: Load device types configuration
      ansible.builtin.include_vars:
        file: "{{ playbook_dir }}/../roles/phpipam_configuration/vars/device_types.yml"

    - name: Load devices configuration
      ansible.builtin.include_vars:
        file: "{{ playbook_dir }}/../roles/phpipam_configuration/vars/devices.yml"

  roles:
    - role: phpipam_configuration

phpIPAM API Endpoints

Sections

GET  /api/{app_id}/sections/         - List all sections
POST /api/{app_id}/sections/         - Create a section

VLANs

GET  /api/{app_id}/vlan/             - List all VLANs
POST /api/{app_id}/vlan/             - Create a VLAN

Note: VLAN IDs are returned as vlanId (not id).

Subnets

GET  /api/{app_id}/subnets/          - List all subnets
POST /api/{app_id}/subnets/          - Create a subnet

Device Types

GET  /api/{app_id}/tools/device_types/  - List all device types
POST /api/{app_id}/tools/device_types/  - Create a device type

Note: Device type fields use tname, tdescription, and tid (not name, description, id).

Devices

GET  /api/{app_id}/devices/          - List all devices
POST /api/{app_id}/devices/          - Create a device

Addresses

GET  /api/{app_id}/addresses/        - List all addresses
POST /api/{app_id}/addresses/        - Create an address

Address fields used: ip, subnetId, hostname, description, deviceId, port (interface name), note, is_gateway.

Note: The description field on addresses has a character limit in MariaDB. The role uses the device hostname as description to stay within this limit.

Idempotency

The role is idempotent:

  • Sections: Matched by name, skipped if exists
  • VLANs: Matched by name, skipped if exists
  • Subnets: Matched by subnet address, skipped if exists
  • Device types: Matched by tname, skipped if exists
  • Devices: Matched by hostname, skipped if exists
  • IP addresses: Matched by IP, skipped if exists

First run: Creates all resources, reports changed

Subsequent runs: No changes, reports ok

Security Considerations

  • API Token: Stored in Ansible Vault, never in plaintext
  • HTTPS: All API calls use SSL/TLS
  • Token Authentication: Uses phpIPAM “App code with SSL” method
  • validate_certs: Enabled by default, validates SSL certificates

File Structure

roles/phpipam_configuration/
├── README.md                  # This file
├── defaults/main.yml          # API config, section name, empty list defaults
├── tasks/main.yml             # API tasks with idempotency checks
└── vars/
    ├── vlans.yml              # VLANs and subnets definitions
    ├── device_types.yml       # Device type definitions
    └── devices.yml            # Devices with IP addresses and metadata

Troubleshooting

”Data too long for column ‘description’” error

Cause: Device descriptions that are too long are passed to the address description field, which has a column length limit in MariaDB.

Solution: The role uses the device hostname as the address description. Long descriptions should only be on the device record, not addresses.

”object of type ‘dict’ has no attribute ‘id’” error

Cause: phpIPAM API uses non-standard field names for IDs.

Solution: Use the correct field names:

  • VLANs: vlanId (not id)
  • Device types: tid (not id)
  • Subnets and sections: id (standard)

Device types skipped during creation

Cause: phpIPAM ships with built-in device types (Switch, Router, Firewall, etc.).

Solution: This is expected. The role only creates types that don’t already exist.

Fresh install required

To start clean, drop and recreate the phpIPAM database:

docker exec -it <mariadb_container> mysql -u root -p -e "
DROP DATABASE phpipam;
CREATE DATABASE phpipam;
GRANT ALL PRIVILEGES ON phpipam.* TO 'phpipam_db_user'@'%';
FLUSH PRIVILEGES;
"
docker restart <phpipam_container>

Then redo the initial phpIPAM setup (admin password, API app creation) before re-running the role.

License

MIT

Author

Created for homelab infrastructure management.