- RewireAllIPv6() began with `if !IPv6Enabled() { return nil }`, so in none
mode — the mode that carries an extra prefix — it did nothing at all: the
boot unit and `vps ipv6-reapply` never set net.ipv6.conf.all.forwarding,
all.proxy_ndp or <ext_if>.proxy_ndp, and without them Incus could not install
the routed NIC's proxy_ndp entry, so every create failed
- give that branch its plumbing: forwarding, kernel proxy_ndp, the NDP rules
and the whole-/64 routes
- ensure forwarding + proxy_ndp at create time, before the routed NIC exists,
so a create no longer depends on a prior install / ipv6-reapply
- a clone or launch failure now calls cleanup() and removes the partial
instance; the leftover used to hold the name, so every retry was refused with
"already exists (orphan?)"
- the installer persists the name-free sysctls (all.proxy_ndp always,
all.forwarding when vpsmgr relays container v6) and uninstall resets
all.proxy_ndp again
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Docker sets iptables FORWARD policy to DROP, which blocks forwarded traffic
from incusbr0 (both IPv4, and IPv6 when Docker's experimental/ipv6 is enabled).
This caused container apt and outbound traffic to time out during image build
and container runtime on hosts where Docker is installed.
- allow incusbr0 traffic in DOCKER-USER for iptables and ip6tables
- install docker.service.d/vpsmgr.conf drop-in so rules persist across Docker restarts
- clean up the drop-in and rules on uninstall
- document Docker compatibility in docs/architecture.md
- host sysctl (20-network.sh): tcp_rmem/tcp_wmem max, rmem_max and
wmem_max all go from 4194304 to 8388608
- image builds (50/60/70/80/90 + eol-debian11): tcp_rmem/tcp_wmem max
bumped the same way
- autotune defaults (262144) and the min values are untouched
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
The panel now fronts user domains with HAProxy 3.4 LTS (official performance
packages) instead of Traefik: about 100 MB of RSS and 200 MB of disk saved for
a feature set that never used more than Host routing on :80 and SNI passthrough
on :443.
- hpx: publish the proxy configuration as immutable GENERATIONS. Every domain
mutation renders the whole set from the DB, validates it with the pinned
`haproxy -c`, and only then repoints the `current` symlink, so a rejected
candidate leaves the running proxy untouched and a stale domain can never
survive into a later generation. Routing is carried by two map files
(Host -> backend, SNI -> backend): per-domain frontend rules cannot work from
a second file because HAProxy rejects duplicate section names since 3.3 and
attaches bare directives to the section opened last.
- mgr: republish and reload (SIGUSR2, i.e. `systemctl reload`) after every
domain change, so a change takes effect without dropping established HTTP or
TLS connections. Rollback semantics (DB first, then publish) are unchanged.
- cfg,db: `net.traefik` is renamed to `net.haproxy` with identical values. A
pre-rename config.yaml key and the legacy VPSMGR_TRAEFIK env var are still
read (new name wins), and schema migration v18 moves the settings mirror from
`traefik` to `haproxy`, keeping a newer value when both rows exist.
- 30-haproxy.sh: install the pinned branch from the vendor repository and
migrate a Traefik host in one run — install and validate HAProxy first, then
remove Traefik's binary, unit, service account and dynamic rules (only its
config file is kept, inert). No fallback keeps both proxies alive.
- upgrade-haproxy.sh: follow the pinned branch to its newest patch, with a
configuration check and a graceful reload; `install.sh --update` runs it.
- tests: generation publish/rollback, map rendering, config-key and settings
migrations, plus real-binary tests (skipped unless
VPSMGR_TEST_HAPROXY_BIN is set) that run the generated configuration through
`haproxy -c` and start it in a network namespace.
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
- 10-incus.sh replaces 10-lxd.sh: adds the Zabbly incus lts-7.0 apt
repo (key fingerprint verified), installs the incus package, creates
the vpsmgr pool (ZFS/spare/loop-file, dir fallback) and lxdbr0 via
`incus admin init --preseed`, and keeps dns.mode=none.
- 00-check.sh targets Debian 12/13 + Ubuntu 22.04/24.04/26.04, drops
snapd, checks incus instead of the lxd snap.
- 50/60-image scripts use `incus` (was `lxc`).
- Service naming unified to vps.*: vps.service (panel),
vps-nft.service, vps-ipv6.service. `systemctl restart vps` is now the
one command operators need. unit After= incus.service.
- uninstall.sh stops vps.* units and removes the Incus package on
--purge.
- sudoers whitelist for the unprivileged panel (configs/sudoers.d/vps).
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
The panel now talks to Incus over its Unix socket REST API
(/var/lib/incus/unix.socket, group incus-admin) exclusively:
- internal/lx: exec moved from the `lxc` CLI to the API websocket
transport (Exec/ExecSH/RunInitScript); EnsureImage pulls a
remote-qualified fallback (images:debian/13) before Launch since the
API cannot auto-fetch it inside the create call; per-container df
probe in mgr/batch.go uses the same API path.
- cfg: config key renamed lxd.* -> incus.* (image, image_fallback,
pool, bridge, socket); DefaultSocket is the Debian-package path.
- mgr: container disk probe and image handling updated; comment sweep
from LXD to Incus.
- deps: add gorilla/websocket for the exec transport.
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>