Skip to content

Network Configuration

The Network Configuration page (Settings → Network) lets an admin change the server’s IP address, gateway, DNS, and netmask from the panel UI — without SSH, without manually editing /etc/netplan/, and without risking locking yourself out of a remote VPS thanks to a 60-second test mode.

It’s the same approach TrueNAS uses: apply the new config in a non-persistent way, run a confirmation timer, and revert if the admin doesn’t click “Confirm” before the timer expires.

ScenarioThis page handles it
Convert a DHCP VPS to static IP (vital — license server doesn’t like DHCP)Yes
Change DNS resolvers (e.g. to NextDNS or Cloudflare)Yes
Add a secondary interface (additional IP on eth1)Partial — multi-NIC display works; multi-IP-per-NIC needs manual netplan edit
Change IPv6 settingsYes
Change hostnameNo — use Settings → System
Routing tables / extra static routesNo — manual /etc/netplan/ edit

The API container has privileged: true, pid: "host", and /etc/netplan bind-mounted from the host. That lets it:

  • Read live interface state from the host’s PID namespace via nsenter -t 1 -m -u -i -n -- ip addr show.
  • Write /etc/netplan/50-cloud-init.yaml directly to the host filesystem.
  • Run netplan apply in the host network namespace.
┌────────────────────────┐ ┌────────────────────────┐
│ proxpanel-api │ nsenter │ Host │
│ (privileged + pid:host)│ ──────▶ │ /etc/netplan/*.yaml │
│ │ │ ip / netplan binaries│
└────────────────────────┘ └────────────────────────┘

/api/network/interfaces returns the host’s interfaces minus the Docker noise. Specifically excluded:

  • lo (loopback)
  • docker0, br-* (Docker bridges)
  • veth* (Docker per-container endpoints)
  • Anything containing @if (PEER markers like eth0@if12)

What remains is your real physical or virtual NICs: eth0, ens3, enp1s0, eno1, etc. The UI dropdown shows the name, current IP (CIDR), MAC, and link state. Multi-interface servers see all of them.

On page load, the API reads /etc/netplan/50-cloud-init.yaml. If it contains dhcp4: true for the active interface, the UI shows:

This server uses DHCP. Your IP can change at any time, breaking RADIUS, license activation, and customer DNS. Switch to a static IP to avoid disruption.

The submit button changes from Apply to Convert DHCP → Static so it’s clear what’s happening. The new static IP is pre-filled with the current DHCP-assigned IP — most operators just confirm.

This is one of the most common support tickets: “my panel went offline” turns out to be “my VPS gave me a new IP via DHCP after a reboot”. Switching to static fixes it permanently.

This is the headline safety feature. Submitting changes does not write to /etc/netplan/ immediately.

  1. Admin fills in interface / IP / gateway / DNS, clicks Test Network.

  2. The API:

    • Backs up the current netplan to /opt/proxpanel/network-backup.conf.
    • Applies the new config temporarily with ip addr add, ip route add, and writes a temp resolv.conf.
    • Forks a background process that sleeps 60 seconds and reverts if a flag file isn’t written.
    • Records the background process PID in /opt/proxpanel/network-revert.pid.
  3. The UI shows a 60-second countdown: “Test mode active. Click Confirm Apply to keep these settings, or do nothing — settings revert in 47 seconds.

  4. If the admin loses connectivity (wrong IP, wrong gateway, wrong DNS) they can’t click Confirm. After 60 seconds the background process restores the netplan backup and the server is back on its old IP.

  5. If the admin clicks Confirm Apply, the API:

    • Kills the revert PID.
    • Deletes /opt/proxpanel/network-revert.pid and network-backup.conf.
    • Writes the new config to /etc/netplan/50-cloud-init.yaml for persistence across reboots.
    • Runs netplan apply in the host namespace one more time to make sure.

This is why you must use a different network to test (e.g. your home laptop, not a Cloud Shell session originating from the same VPS provider’s network). If you test from a session that gets dropped at the network change, you have 60 seconds to refresh the page on the new IP and click Confirm — otherwise it reverts and you keep your old config.

The netplan template writes both v4 and v6 if provided:

network:
version: 2
ethernets:
eth0:
addresses:
- 192.0.2.10/24
- 2001:db8::10/64
routes:
- to: default
via: 192.0.2.1
- to: ::/0
via: 2001:db8::1
nameservers:
addresses:
- 1.1.1.1
- 2606:4700:4700::1111

The UI exposes one address row per interface but does write IPv6 if the input has a :. Multi-NIC setups (e.g. eth0 for WAN, eth1 for MikroTik management) are handled by selecting the right interface in the dropdown and configuring each separately — the previous interface’s settings are preserved.

Two options, exposed as a “DNS Method” dropdown:

MethodWhere DNS livesSurvives reboot?
netplan (default)Inside netplan YAML; systemd-resolved managedYes
resolvWritten directly to /etc/resolv.confNo — systemd-resolved will rewrite it. Use only for testing.

Use netplan in production. The resolv option exists for cases where systemd-resolved is disabled (rare).

Terminal window
# Current applied config
cat /etc/netplan/50-cloud-init.yaml
# Live interface state (this is what the panel reads via nsenter)
ip addr show
# Active routes
ip route show
# Active resolvers
resolvectl status # or `cat /etc/resolv.conf` if systemd-resolved is off
# Verify the revert background process is gone after a confirmed apply
ls -la /opt/proxpanel/network-revert.pid
# → No such file (good)
  • “Test Network” button does nothing, no countdown. API container doesn’t have iproute2 installed or doesn’t have /etc/netplan mounted. Verify with docker exec proxpanel-api which ip and docker exec proxpanel-api ls /etc/netplan. The install script since v1.0.229 always installs iproute2 and mounts /etc/netplan.
  • Apply succeeds but the change doesn’t survive reboot. You used DNS Method = resolv, which is non-persistent. Re-apply with netplan.
  • Confirm Apply returns 500 “Failed to write netplan config”. /etc/netplan/50-cloud-init.yaml is read-only or the bind-mount is missing. Confirm docker inspect proxpanel-api | grep netplan shows the mount.
  • Revert never fires when the admin closes the browser. The 60-second countdown is server-side — based on the background PID, not the browser. So closing the tab does not cancel the revert. Good — that’s the point.
  • DHCP warning persists after switching to static. netplan still has dhcp4: true somewhere. cat /etc/netplan/*.yaml and verify only your new file remains. Old cloud-init files (50-cloud-init.yaml, 99-disable-cloud-init.cfg) sometimes leave stale DHCP entries.
  • Multiple netplan files conflict. Netplan merges all *.yaml files in /etc/netplan/. If the cloud provider’s 50-cloud-init.yaml re-asserts DHCP at boot, disable cloud-init networking with echo 'network: {config: disabled}' > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg.

There are two paths from the UI:

PathBehaviour
Test NetworkTemporary — applies in-memory, starts 60 s revert timer. You should always use this first on a remote server.
Apply Network Configuration (direct)Permanent — writes netplan, runs netplan apply. No revert. Use only when you’re sitting at the console of the server, or when you’ve already confirmed the test mode works.

A common mistake: clicking Apply directly with new settings, then losing connectivity, then having no recourse but a hardware-console / KVM-over-IP visit to the VPS. Always test first.

If you’re operating a panel on a private LAN, with a console you can fall back to, direct Apply is fine. If you’re operating a remote VPS over the public internet, treat Test as mandatory.

The panel doesn’t expose adding custom static routes (e.g. “10.10.0.0/16 via 192.168.1.254”). For that, edit /etc/netplan/50-cloud-init.yaml directly:

network:
version: 2
ethernets:
eth0:
addresses: [192.0.2.10/24]
routes:
- to: default
via: 192.0.2.1
- to: 10.10.0.0/16 # custom — added by hand
via: 192.168.1.254
nameservers:
addresses: [1.1.1.1]

Apply with netplan apply. The panel’s “Apply” button will preserve your customisation as long as you don’t change the same interface from the UI — but if you do, the UI overwrites the file. Make a backup before editing.

The persistent config lands in /etc/netplan/50-cloud-init.yaml. Permissions: 0600 (root-only). Any other YAML files in /etc/netplan/ are merged by netplan in lexical order — files starting with 99- win. If your distro shipped a 90-something.yaml, it may conflict.

Standard install puts everything in the single 50-cloud-init.yaml. You can verify the only-one-file invariant with ls /etc/netplan/.

The combination of privileged: true, pid: "host", and a script that bash -cs user input is the most dangerous endpoint in the panel. validateNetworkRequest() enforces:

  • Interface name: ^[a-zA-Z0-9@._-]{1,32}$ (no shell metacharacters).
  • IP address: must parse as net.ParseIP or net.ParseCIDR.
  • Gateway, DNS1, DNS2: must parse as net.ParseIP.
  • DNS method: enum (netplan or resolv).

Any failure returns HTTP 400 with the field name. Do not relax these checks. Adding a new field requires adding it to validateNetworkRequest first.

The route is protected by RequirePermission("settings.edit"). Resellers cannot reach it.

settings.view to load the page, settings.edit to apply changes. Admin-only by default — most operators leave it that way.

If you’re confident in your config and want to avoid the 60-second dance, skip the UI and edit netplan directly over SSH:

Terminal window
sudo vim /etc/netplan/50-cloud-init.yaml
sudo netplan try # tests for 120 s, reverts if no confirmation
sudo netplan apply # commits

netplan try is Ubuntu’s built-in version of the panel’s Test mode — same idea, longer default timer. The panel’s 60-second test is just easier when you’re already in the UI.

  • Remote Support / SSH Tunnel — uses the same nsenter privilege escalation pattern.
  • HA Cluster — IP changes break replication; update primary_conninfo and pg_hba.conf after any IP change on the main.
  • Boot Security — netplan changes do not affect LUKS / boot security.