▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ░▒▓█ rapid1337.com █▓▒░ ╓──────────────────────────────────────────╖ ║One Box, One IP — Proxmox VE + ISPConfig 3║ ╟──────────────────────────────────────────╢ ║ Full walkthrough — bare metal to a ║ ║ mail/web/DNS control panel in an LXC ║ ╟──────────────────────────────────────────╢ ║·· sysadmin/proxmox-ispconfig-single-ip.ht║ ╙──────────────────────────────────────────╜ ============================================================================ Title ..: One Box, One IP — Proxmox VE + ISPConfig 3 the Right Way Author .: staff Date ...: 2026-07-15 Section : Sysadmin ============================================================================ Rented dedicated servers come with one public IPv4 and a bill for every extra address. You don't need the extras. One IP is enough to run a full hosting stack — web, mail, FTP, DNS, control panel — as long as you put a NAT layer between the wire and the workload. This is the whole trick: ```text the internet | | 203.0.113.10 (your one public IP) +------+------+ | vmbr0 | Proxmox VE host | | sshd :22, GUI :8006 | iptables | | DNAT+MASQ | | | | vmbr1 | 10.10.10.1/24 (private bridge) +------+------+ | | 10.10.10.100 +------+------+ | CT 100 | Debian 12 LXC | ISPConfig | apache mariadb postfix | | dovecot bind pureftpd +-------------+ ``` The host owns the public IP and keeps ports 22 and 8006 for itself. Everything else gets forwarded into the container. The container thinks it's a normal server; the internet thinks your one IP is a hosting company. Nobody is lying, exactly. Versions used here: Proxmox VE 9.2 (Debian 13 base) and ISPConfig 3.3 via the official auto-installer, in a Debian 12 container. Commands are current as of July 2026. ## Part 1: Get Proxmox VE Grab the ISO from https://www.proxmox.com/en/downloads — you want "Proxmox VE 9.2 ISO Installer", about 1.7 GB. Verify it. Always verify it; you're about to make this thing PID 1 of your empire. ```bash sha256sum proxmox-ve_9.2-1.iso # compare against the checksum published on the download page ``` Write it to a USB stick (any machine, any OS — this is a raw image, not a "bootable USB creator" situation): ```bash dd if=proxmox-ve_9.2-1.iso of=/dev/sdX bs=4M status=progress oflag=sync ``` On a rented box you obviously can't walk over and plug in a stick. Two routes: - **IPMI / KVM console** — every serious provider (Hetzner, OVH, etc.) will attach a remote console with virtual media on request. Mount the ISO, boot from it, install as if you were standing in the DC. - **Debian first, Proxmox on top** — install plain Debian 13 with the provider's installer, then follow the official wiki page "Install Proxmox VE on Debian 13 (Trixie)". Same result, no console needed. The installer itself asks very little: accept the EULA, pick the target disk (ext4/LVM default is fine; ZFS if you have mirrored disks and the RAM to feed it), set country/timezone/keyboard, a root password and email, then the network screen. Give it your public IP, gateway, DNS, and a real FQDN hostname (e.g. `pve.example.com`). Reboot. ## Part 2: Post-install — repos and updates Fresh installs point at the enterprise repository, which 401s without a subscription. Easiest fix is in the GUI: browse to `https://203.0.113.10:8006`, log in as root@pam, then *node → Updates → Repositories* — disable the two enterprise entries and *Add → No-Subscription*. Or do it by hand. PVE 9 uses deb822 sources; drop this in `/etc/apt/sources.list.d/proxmox.sources`: ```text Types: deb URIs: http://download.proxmox.com/debian/pve Suites: trixie Components: pve-no-subscription Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg ``` and set `Enabled: false` in `pve-enterprise.sources` (and the ceph one). Then: ```bash apt update && apt full-upgrade -y reboot ``` > The "no valid subscription" nag on GUI login is cosmetic. Ignore it or > buy a subscription — the no-subscription repo is the same software, > just less tested. ## Part 3: One IP, two bridges This is the part that makes single-IP hosting work, and it's ten lines of config. `vmbr0` already exists — the installer created it and gave it your public IP. You add `vmbr1`, a bridge connected to nothing physical, which becomes the private LAN your containers live on. The host NATs between the two, exactly like the router on your desk at home. Edit `/etc/network/interfaces` — leave the `lo`, physical NIC, and `vmbr0` stanzas alone, and append: ```text auto vmbr1 iface vmbr1 inet static address 10.10.10.1/24 bridge-ports none bridge-stp off bridge-fd 0 post-up echo 1 > /proc/sys/net/ipv4/ip_forward post-up iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE post-down iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE ``` Apply without rebooting: ```bash ifreload -a ``` `MASQUERADE` gives everything on 10.10.10.0/24 outbound internet through the public IP. Inbound comes later, in part 6 — deliberately in this same file, so the firewall state and the bridge that needs it live and die together. ## Part 4: The container ISPConfig wants a full distro with systemd, not a scratch image. Fetch the Debian 12 LXC template — 12 rather than 13 because it's the safest target for ISPConfig stable (13 works too, but the auto-installer pulls the development branch on it until 3.3.1 goes final): ```bash pveam update pveam available --section system | grep debian-12 pveam download local debian-12-standard_12.12-1_amd64.tar.zst ``` (Use whatever version string `pveam available` actually lists.) Create the container. GUI works, but the CLI shows every decision in one place: ```bash pct create 100 local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst \ --hostname panel.example.com \ --unprivileged 1 \ --features nesting=1 \ --cores 4 --memory 4096 --swap 1024 \ --rootfs local-lvm:40 \ --net0 name=eth0,bridge=vmbr1,ip=10.10.10.100/24,gw=10.10.10.1 \ --nameserver 9.9.9.9 \ --onboot 1 pct start 100 pct enter 100 ``` The choices that matter: - `--hostname panel.example.com` — ISPConfig **requires** a proper FQDN. Not `panel`, not `localhost`. Pick the name now; it becomes your mail server's HELO and your panel URL. - `--features nesting=1` — systemd inside a container needs it. Without this, half the services fail in ways that will waste your evening. - `--unprivileged 1` — no reason to run privileged in 2026. - `bridge=vmbr1` with a static IP on the private net. The `.100` here is the address every forwarding rule in part 6 points at. Inside the container, make sure the hostname resolves to itself: ```bash hostnamectl set-hostname panel.example.com echo "10.10.10.100 panel.example.com panel" >> /etc/hosts hostname -f # must print panel.example.com ``` ## Part 5: ISPConfig, the auto-install way The days of the forty-page "Perfect Server" manual are over — the official auto-installer does the whole stack. Inside the container: ```bash apt update && apt -y upgrade apt -y install curl wget gnupg wget -O - https://get.ispconfig.org | sh -s -- \ --use-ftp-ports=40110-40210 --unattended-upgrades ``` It warns you it's about to take over the machine; that's the point — say yes. Twenty-odd minutes later you have Apache, MariaDB, PHP (several versions), Postfix, Dovecot, rspamd, BIND, Pure-FTPd, Jailkit and fail2ban, all wired into the ISPConfig panel. Flags worth knowing (`--help` lists them all): `--use-nginx` swaps Apache for nginx, `--no-mail` / `--no-dns` skip whole subsystems if you only want web hosting, `--use-php=8.2,8.3` pins PHP versions. The `--use-ftp-ports` range above is not optional decoration — it's the passive-FTP window we forward in part 6, so keep the numbers matching. **The installer prints the admin password and the MySQL root password at the end of the run. It will not tell you twice.** Save both before you close the terminal. > Order-of-operations tip: if you want the installer's Let's Encrypt > certificate for the panel to succeed on the first try, have your DNS > A record (`panel.example.com → 203.0.113.10`) and the part 6 port > forwards in place *before* running it — the acme challenge has to > reach port 80 inside the container. Otherwise it falls back to a > self-signed cert and you re-issue later. No harm either way. ## Part 6: Forwarding — one IP, many ports Now punch the holes. The host answers on the public IP and DNATs each service port to 10.10.10.100. The split: ```text port(s) service goes to ------- ------- ------- 22, 8006 host ssh, PVE GUI stays on the host 80, 443 http/https CT 100 8080, 8081 ISPConfig panel/apps CT 100 25, 465, 587 smtp/smtps/submission CT 100 110, 995, 143, 993 pop3(s)/imap(s) CT 100 21, 40110-40210 ftp + passive range CT 100 53 tcp+udp dns (only if BIND CT 100 serves your zones) 2222 -> 22 ssh into the CT CT 100 ``` Same file as before, `/etc/network/interfaces`, extending the `vmbr1` stanza — rules and bridge live together, survive reboots, and need no extra persistence packages: ```text post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp -m multiport \ --dports 21,25,80,110,143,443,465,587,993,995,8080,8081 \ -j DNAT --to 10.10.10.100 post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 40110:40210 -j DNAT --to 10.10.10.100 post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 2222 -j DNAT --to 10.10.10.100:22 post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp -m multiport \ --dports 21,25,80,110,143,443,465,587,993,995,8080,8081 \ -j DNAT --to 10.10.10.100 post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 40110:40210 -j DNAT --to 10.10.10.100 post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 2222 -j DNAT --to 10.10.10.100:22 ``` Hosting your own DNS zones from ISPConfig's BIND? Add 53: ```text post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 53 -j DNAT --to 10.10.10.100 post-up iptables -t nat -A PREROUTING -i vmbr0 -p udp --dport 53 -j DNAT --to 10.10.10.100 ``` (most people let their registrar's DNS do this job — skip it if so, one less thing listening). Apply and inspect: ```bash ifreload -a iptables -t nat -L -n -v --line-numbers ``` The counters in that listing are your friend: hit the public IP on a forwarded port and watch the packet count tick. ## Part 7: Smoke test and the gotchas nobody mentions Point a browser at `https://203.0.113.10:8080` (or the panel FQDN once DNS propagates). ISPConfig login: `admin` plus the password from part 5. Create a client, a website, an FTP user, a mailbox — the full tour. Let's Encrypt certs on hosted sites just work, because 80 and 443 land in the container. Then the fine print, learned the hard way so you don't have to: - **Reverse DNS.** Set the PTR record for your IP to the container's FQDN in the provider's panel. Mismatched forward/reverse DNS is the #1 reason a fresh mail server lands in spam. Add SPF, DKIM (rspamd signs, key is in the panel), and DMARC records while you're in the DNS editor. - **Outbound port 25** is blocked by default at many providers. There's usually a form to unblock it; fill it in before you wonder why mail queues but never leaves. - **Hairpin NAT.** From inside the private net, `203.0.113.10:80` won't loop back — the DNAT rule matches `-i vmbr0` only. Test from outside, or split-horizon your DNS. Don't burn an hour on this like everyone does once. - **Disk quota is the one real casualty of LXC.** Linux filesystem quotas don't work inside a container, so ISPConfig's per-site quota enforcement is advisory only here. If hard quotas are a requirement, use a KVM VM instead of a CT — everything else in this article applies unchanged, bridge and forwards included. - **Lock down what stayed on the host.** 8006 and 22 face the world; at minimum fail2ban them or restrict by source IP in the PVE firewall. The panel gives you a whole firewall GUI — use it. - **Backups.** `vzdump 100 --mode snapshot` from the host, cron it, ship it somewhere that isn't this machine. A hosting box with no off-site backup is a countdown timer. That's the whole build: one rented box, one IPv4, a hypervisor you can snapshot, and a hosting panel that thinks it owns the world. Add a second container on vmbr1 tomorrow — a game server, a build box, a BBS — and it costs you nothing but ports. Knowledge is the weapon. Go host something. ---------------------------------------------------------------------------- -- rapid1337.com -- The dumping ground for all things tech // knowledge is the weapon --