The spreadsheet usually fails quietly. Someone assigns 10.20.5.40 to a new label printer, forgets to add a row, and six weeks later a hypervisor host comes up on the same address after a rebuild. Nobody broke a rule; the sheet simply stopped matching the wire. This guide walks through moving that record into phpIPAM, the GPLv3 self-hosted IPAM, in a way that keeps the recorded plan and the live network in agreement instead of copying old mistakes into a new tool.
The goal is not “import the sheet”. The goal is a record you can trust, plus a scheduled check that tells you when it drifts.
Before you start
You need a Linux host (VM or container) with a web server, PHP and MySQL or MariaDB. The current 1.8.x branch supports PHP 7.2 through 8.5 according to the project’s repository; MySQL 8.0+ or MariaDB 10.2.1+ is recommended because newer queries use common table expressions. Follow the installation notes on the project’s own site, whether you prefer a classic LAMP install or container images. Plan for the scan scripts to run on a host that can actually reach every subnet you intend to track: a phpIPAM box stuck in a DMZ will report half your network as offline.
Step 1: Freeze and clean the spreadsheet
- Announce a short freeze: for the migration window, new assignments go into a single “pending” tab, not scattered across the sheet.
- Make one row per address. Merged cells, colour-coded meaning and “see Dave” comments do not survive any import.
- Normalize the columns to something close to what phpIPAM stores per address: IP address, hostname, description, MAC, owner, device, note.
- Split the data by subnet. phpIPAM imports addresses into a subnet, so a file per subnet keeps each import small and easy to check.
- Remove the obvious fiction: rows for hardware you know was retired, duplicate rows for the same IP, and ranges typed as “10.20.5.100-150 DHCP” (the DHCP pool is a range, not 51 host records).
A minimal per-subnet CSV might look like this:
ip_addr,hostname,description,mac,owner,note
10.20.5.1,gw-branch1,Core switch SVI,,netops,VLAN 5 gateway
10.20.5.10,fs01,File server,00:15:5d:0a:11:02,infra,
10.20.5.40,prn-2f-east,Label printer 2nd floor,,facilities,Moved from .39 in March
Step 2: Build the hierarchy before importing anything
- Create sections that mirror how you think about the network (for example “HQ”, “Branches”, “DMZ”). Sections are just top-level containers with their own permissions.
- If you reuse RFC 1918 space across sites or customers, create VRFs first so overlapping 10.0.0.0/8 ranges don’t collide in the record.
- Add VLANs in the VLAN management area so each subnet can reference its VLAN ID.
- Create the subnets with the correct mask, VLAN and description. Nest smaller subnets under a larger supernet if that matches your addressing plan.
- On each subnet you want monitored, enable host status checks and, where you want unknown hosts reported, host discovery. These per-subnet switches are what the cron scripts in Step 4 look at.
Getting this skeleton right matters more than the import itself. A /23 accidentally created as a /24 will reject half the addresses you try to load.
Step 3: Import the addresses
- Open a subnet and use its import action; phpIPAM accepts XLS and CSV files.
- Map your columns to phpIPAM fields in the import dialog and review the preview. Rows outside the subnet’s range or duplicates of existing entries should be flagged rather than silently written.
- Import one subnet, spot-check five or six entries against reality, then continue.
- Tag DHCP pools and reserved ranges using address states or custom fields instead of creating a record for every dynamic address.
Step 4: Turn on scheduled reconciliation
This is where the spreadsheet never could compete. phpIPAM ships two scripts in functions/scripts/: pingCheck.php updates the “last seen” status of addresses already in the record, and discoveryCheck.php looks for live hosts that are not in the record. Both are meant to run from cron, using the scan method configured under administration (ping, pear ping or fping; fping is faster because it threads internally).
# status of known addresses every 15 minutes
*/15 * * * * /usr/bin/php /var/www/phpipam/functions/scripts/pingCheck.php > /dev/null 2>&1
# discovery of unknown hosts once an hour
0 * * * * /usr/bin/php /var/www/phpipam/functions/scripts/discoveryCheck.php > /dev/null 2>&1
Adjust the PHP path and install directory to your system (which php tells you the first). The method can also be pinned in config.php with $config['ping_check_method'] and $config['discovery_check_method']. Scan only networks you own or are authorized to monitor, and tell the security team first so an ICMP sweep from a new host doesn’t trigger an incident.
Step 5: Work the first diff
After a day of scans you will have two lists worth reading:
- Recorded but never seen. Either the device is off, it blocks ICMP (common on Windows hosts with the default firewall profile), or the row is stale. Check before deleting.
- Seen but not recorded. These are your undocumented statics. Identify each one, then either adopt it into the record or move the device to a proper assignment.
Treat this first pass as the real migration. The import got the data in; the diff makes it correct. Later, if you want a second opinion on a single subnet, a desktop scanner such as Angry IP Scanner is handy for a quick sweep, as covered in finding genuinely free addresses.
Common mistakes
- Importing the DHCP pool as static hosts. You end up with hundreds of rows that change owner every lease cycle. Record the pool as a range and keep reservations as separate, named entries (see DHCP reservations vs static IPs).
- Leaving the spreadsheet writable. Two sources of truth quickly become zero. Make the old file read-only and put a link to phpIPAM at the top.
- Treating “offline” as “free”. A host that ignores ping still owns its address. Confirm with ARP from the same segment before reusing anything.
- Running scans from the wrong vantage point. Firewalls between the phpIPAM host and remote sites make whole subnets look empty.
- Skipping permissions. Give the helpdesk read access and a narrow set of editors write access; otherwise the new tool inherits the sheet’s “everyone edits everything” habit.
Where to go next
If you are still choosing a platform, compare the options on the IPAM software category page, and read phpIPAM vs NetBox if you also need to model racks, devices and cabling. For planning the subnets you will create in Step 2, see planning subnets and VLANs for a new branch office. Always obtain phpIPAM from the project’s own site or repository; our where to get the software page explains how to check what you fetched.