Commit Graph
211 Commits
Author SHA1 Message Date
bluebluesodaandCommandCodeBot e6bf390da0 feat(panel): add grouped multi-container users
- group sibling users by the username-number convention
- synchronize group credentials, colors, and session rotation
- add group switching and destructive-action warnings
- keep group updates transactional and validate names server-side

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-09 07:21:02 +00:00
bluebluesodaandCommandCodeBot 6856e510a4 feat(addon): add container transparent proxy templates
- add sing-box, nftables, and systemd deployment templates
- document external GeoIP rule-set setup

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-08 13:17:14 +00:00
bluebluesodaandCommandCodeBot a64df2ac96 feat(panel): show build version in user footer
- add configurable user footer visibility
- render the injected release or local-build version

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-08 13:15:58 +00:00
bluebluesodaandCommandCodeBot 9b68d7b7b6 fix(panel+admin): checkbox color clash and over-wide IPv6 column
- user/admin password rule checklists no longer reuse the global .ok
  button class (whose background turned whole rows green); ticks now use
  a dedicated .done state that only recolors the item text and mark
- admin user table in IPv6-pool mode shows 有/无 (Yes/No) instead of the
  full address, keeping the column narrow like the other two modes

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 12:52:54 +00:00
bluebluesodaandCommandCodeBot 602544c7bb feat(passwd+admin): real-time rule checks; usernames fold to lowercase
- pw.Validate now requires >=10 chars with an uppercase, a lowercase and a
  digit; messages and templates updated to match
- Change-password forms (user panel + admin) show a live checklist that
  ticks each rule off as the user types
- mgr.Add and `vps add` lowercase the username before validating and
  checking duplicates, so uppercase input is accepted and stored lowercase
- Create-user form folds the username to lowercase live and reports rule
  and duplicate problems before submit
- drop the wordy password-rule hints added in the last passwd commit

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 12:18:27 +00:00
bluebluesodaandCommandCodeBot e012352b31 feat(passwd): require >=10 chars with letters and digits on password change
Shared pw.Validate rule replaces the per-panel 14-char checks; user and
admin change-password handlers, templates and i18n messages all updated.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 10:03:31 +00:00
bluebluesodaandCommandCodeBot 7e87cfd373 fix(admin): reset-password modal login-as posts a blank name; panel borders 2px
- The modal "log in as this user" form carries class=inline, and the CSS
  rule form.inline{display:inline} overrides the hidden attribute, so the
  button was visible in every modal. It posted the stale/empty name input
  and failed with "user not found". Add form.inline[hidden]{display:none}
- Reset-panel-pass now attaches the username to the flash (kind
  user_created), so the reset modal's login-as button is shown only for
  that user and logs in correctly instead of submitting a blank name
- User panel: component borders (cards, buttons, inputs, quick-stat
  tiles, modal, spinner; login card and input) go from 1px back to 2px
- Tests: login-as form must render hidden + CSS guard present; reset flash
  must carry the username

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 06:14:03 +00:00
bluebluesodaandCommandCodeBot ba3d23af82 fix(panel): restore gray-blue light bg; bold port block; v4-off notice
- Restore the light-mode page background to the gray-blue #e6ebf1 (with
  white cards) that predates the all-white change, in the user overview,
  login page and the themed override, so light mode keeps its contrast
- Port-forwarding card: bold the three-digit block number and render the
  00/99 tails at the same size, un-bolded and faded (opacity only)
- When IPv4 forwarding is off the card now says "IPv4 转发已关闭 / IPv4
  forwarding is off" instead of leaving the slot empty
- Update tests for the new markup, v4-off notice and restored background

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 05:59:52 +00:00
bluebluesodaandCommandCodeBot c0ce7a422d fix(panel): style port block like IPs; hide it when v4 forwarding is off
- Render the port block in the same yellow code style as IP addresses,
  dropping the bold; de-emphasize the trailing 00/99 with a smaller,
  faded span
- Only advertise the port block while v4 forwarding is on — with it off
  (IPv6-only host) there is nothing to forward to, so the card hides it
- Update tests: v4-off renders no port-block line even when a start_port
  exists; zh/en assert the de-emphasized tails

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 05:43:48 +00:00
bluebluesodaandCommandCodeBot 9dc133f99a feat(panel): rework user overview connectivity UI
- Drop the "available ports" cell from the overview table; the IPV4 row
  now carries just the public IP across the row
- Rename the SSH row label to "SSH 端口" in zh (SSH port unchanged)
- Rename the Domains card to "端口转发 / Port forwarding": it now shows
  the user's port block (Available: <b>103</b>00-103<b>99</b>, block
  number bolded) followed by a "域名转发 / Domain forwarding" section
  with the existing domain table and add form unchanged
- pageData: replace the unused PortsShort with PortsPrefix (whole-hundred
  block number); update tests for the new layout and zh labels

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 05:21:53 +00:00
bluebluesodaandCommandCodeBot b46bd0a901 fix(panel): theme color only on admin impersonation; thin borders back to 1px
- Per-user accent color now tints the user panel only for operator
  impersonation sessions (handleOverview clears ThemeColor otherwise);
  users logging in with their own password see the default theme
- Restore 1px borders on user-panel cards, buttons, inputs, quick stats,
  modals and spinner, and on the login card/input (was 3px)
- Update docs and tests; add HTTP-level test covering both session kinds

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-06 04:52:37 +00:00
bluebluesodaandCommandCodeBot 01869464cb fix(panel): responsive layout for sticky notes on narrow screens
Stack the notes list above the editor below 640px instead of squeezing
the fixed 28% sidebar alongside the textarea; let the toolbar buttons
wrap so save/lock/delete no longer overflow on mobile.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-05 15:44:40 +00:00
bluebluesodaandCommandCodeBot b1d40a1107 chore(notes): halve sticky-notes plaintext cap to 256 KiB
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-05 08:27:23 +00:00
bluebluesodaandCommandCodeBot 48d8cafe2f fix(install): skip 50-image when incus.image is a custom alias
Reinstall/upgrade with incus.image set to anything other than the
default vpsmgr/debian-sshd now skips the Debian 13 sshd image build —
a custom image operator does not launch the stock one, so pulling
Debian 13 and rebuilding it is wasted work (even when the default
image is missing).

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-04 13:33:12 +00:00
bluebluesodaandCommandCodeBot a8bc34a325 feat(admin): drop the plan-preset hint line
The explanation line above the S/M/L preset cards is unnecessary
chrome; remove it and its CSS/JS/labels.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-04 12:30:47 +00:00
bluebluesodaandCommandCodeBot 817b23c922 feat(admin): add S/M/L plan presets to the create-user form
Three fixed preset cards sit above the create form; each stores a
customizable name plus cpu/mem/disk/bandwidth specs in localStorage
(pure front-end, no backend change). "Edit" opens a modal, "Apply"
overwrites the current form values.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-04 12:22:07 +00:00
bluebluesoda f2d3eee4d8 fix(install): fall back to IPv4 when go.dev download fails over IPv6
Some hosts resolve go.dev/dl through an IPv6 path that serves the site and
manifest fine but returns 404 for the tarball CDN (dl.google.com). curl
prefers IPv6 by default, so ensure_go's download loop failed on every
candidate and aborted the local build.

- add curl_retry: fetch with the default address family, fall back to
  'curl -4' on failure; use it for both the manifest and the tarball
- the IPv4 fallback is a pure retry — hosts with working IPv6 are
  unaffected, and pure-IPv4 hosts were never broken
- drop an unused 'latest' variable in the download loop
2026-09-04 08:53:34 +00:00
bluebluesoda e25e729de7 fix(ipv6): disable npd6 alongside ndppd to avoid competing NAs
The in-tree NDP responder relies on being the only NDP proxy on the host.
main.go already disabled ndppd.service at install; npd6 (an alternative
distro NDP proxy daemon) was left running, so a host that happened to have
npd6 installed would answer Neighbor Solicitations with a competing
link-local-source NA and break the global-address fix.

- main.go: also `systemctl disable --now npd6.service` at install
- uninstall.sh: also stop/disable npd6 in the IPv6 cleanup path
- docs: note both daemons are disabled (ipv6-ndp-responder.md, ipv6.md)
2026-09-04 08:47:36 +00:00
bluebluesoda c9b18ffee5 Merge remote-tracking branch 'origin/dev-ndp'
# Conflicts:
#	src/internal/admin/handlers.go
2026-09-04 08:33:56 +00:00
bluebluesoda 69f79187c8 feat(ports): replace net.slot_range with net.user_ports; probe SSH ports at add time
net.slot_range required operators to reason about IPv4 last-octet slots to
control the host's reserved port span. Replace it with net.user_ports, a
direct comma-separated set of user-port ranges (default 10000-29999) that a
new container's whole-hundred block is drawn from, auto-aligned to whole
hundreds and merged. Only-new-users effect; existing containers keep their
ports.

- cfg: ParseUserPorts/CanonicalUserPorts/UserPortRanges/UserPortCount/
  UserPortBlockStarts; legacy slot_range is migrated once on Load and the
  old key stays in the file, ignored, no longer editable.
- db: migration v13 adds a UNIQUE index on users.start_port (port blocks are
  no longer derived from idx, so uniqueness must be enforced directly);
  UsedStartPorts() feeds the allocator.
- mgr: port blocks are allocated independently of the IPv4 idx via
  allocUserPortBlock; admin capacity readout follows UserPortCount.
- installer: 00-ip-ask.sh asks for port ranges (default = no confirm, a
  changed value echoes capacity and asks Y/n) and converts legacy slot_range;
  00-check.sh scans only the effective user-port ranges.
- ssh: allocSSHPort now probes the host (bind test) before picking a port,
  reassigning on conflict; the install no longer hard-fails on an occupied
  30000-31999 port.
2026-09-04 08:32:13 +00:00
bluebluesoda 3fdb946baa Update 80-debian-dev-image.sh 2026-09-02 23:30:25 +08:00
bluebluesoda fd6448bd27 Update handlers.go 2026-09-02 19:04:21 +08:00
bluebluesoda 2f43b95b0f Update overview.html 2026-09-02 13:23:03 +08:00
bluebluesoda 888cf09a95 Update install.sh 2026-09-02 13:02:13 +08:00
bluebluesoda 3f5fffc961 Update README.md 2026-09-02 11:22:47 +08:00
bluebluesoda 430d6f77c4 feat(install): warn on a release install from a non-main branch
A plain ./install.sh downloads the prebuilt RELEASE binary, which always
comes from main regardless of the checked-out branch. If this is a real
git checkout on a non-main branch, prompt for confirmation before
continuing. Tarball / one-click pipe installs have no .git directory and
skip the check. The branch is read directly from .git/HEAD so git(1) is
not required; a detached HEAD is treated as non-main.
2026-08-31 23:53:01 +08:00
bluebluesoda 5f154728af feat(install): warn on a release install from a non-main branch
A plain ./install.sh downloads the prebuilt RELEASE binary, which always
comes from main regardless of the checked-out branch. If this is a real
git checkout on a non-main branch, prompt for confirmation before
continuing. Tarball / one-click pipe installs have no .git directory and
skip the check. The branch is read directly from .git/HEAD so git(1) is
not required; a detached HEAD is treated as non-main.
2026-08-31 23:52:51 +08:00
bluebluesoda 83f9214b72 fix(install): stop vps-ipv6.service too before replacing the binary
On the dev-ndp branch the prefix-mode boot unit vps-ipv6.service runs a
long-lived `vps ipv6-proxy` process that maps /usr/local/bin/vps, so
stopping only vps.service left the binary held and 40-panel.sh failed to
overwrite it with ETXTBSY ("Text file busy"). Stop every vpsmgr unit that
keeps the binary mapped (vps.service and vps-ipv6.service) before copying,
in both the local-build and prebuilt paths. Verified live: cp fails while
the panel runs, succeeds once it is stopped.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 22:04:42 +08:00
bluebluesoda da3f8b2105 fix(install): stop vps-ipv6.service too before replacing the binary
On the dev-ndp branch the prefix-mode boot unit vps-ipv6.service runs a
long-lived `vps ipv6-proxy` process that maps /usr/local/bin/vps, so
stopping only vps.service left the binary held and 40-panel.sh failed to
overwrite it with ETXTBSY ("Text file busy"). Stop every vpsmgr unit that
keeps the binary mapped (vps.service and vps-ipv6.service) before copying,
in both the local-build and prebuilt paths. Verified live: cp fails while
the panel runs, succeeds once it is stopped.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 22:04:31 +08:00
bluebluesoda 0548b50eb2 Merge main into dev-ndp
Bring in the two v6-unrelated features committed on main: the snapshot
size column in the time-machine modal, and tab-completion for `vps config
set`.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 21:55:07 +08:00
bluebluesoda 31143f2cf8 feat(cli): tab-complete config keys for vps config set
Typing a config key by hand was tedious, so `vps config set <TAB>` now
completes just the keys `vps config set` accepts. The completion script
(dropped into /usr/share/bash-completion/completions by 40-panel.sh) pulls
candidates live from a hidden `vps config completions` subcommand, which
returns EditableKeys() from the registry — so offered keys never drift from
what set actually enforces. Also completes top-level commands, config
subcommands and (for del/power/quota/passwd) container names.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 21:54:19 +08:00
bluebluesoda 4bc161c379 feat(panel): show snapshot disk usage in a wider time-machine modal
Incus's snapshot API already returns each snapshot's size, so the overview
now renders a Size column (via a newly exported HumanBytes) and the time
machine modal is bumped from 420px to the wide layout. The per-row value is
greeted only when snapshots exist; the header ships in the template.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 21:54:12 +08:00
bluebluesoda a3a81d943f docs: note how the NDP responder coexists with the isolation layer
Clarify that security.port_isolation + ipv4/ipv6_filtering gate east-west
traffic on the bridge while the responder handles north-south NA replies on
the upstream NIC, and document the gateway-neighbour pinning that plans
around the isolation filter's deliberate side effect on fe80::1 NDP.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 21:39:21 +08:00
bluebluesoda 9696752d25 docs: explain the in-tree NDP responder design and scale-test checklist
Add docs/ipv6-ndp-responder.md: why prefix mode replaced the distro ndppd
daemon with a project-owned responder (some providers drop link-local-source
NAs), the data-plane correctness guarantees, the A/B design hardening, what
changed on dev-ndp, and an 8-point checklist for wide-scale testing. Link it
from docs/README.md.
2026-08-31 17:51:14 +08:00
bluebluesoda 062cf9c4f5 feat(ipv6): in-tree NDP responder for global-address NA source
Some upstream IPv6 providers reject NDP replies whose source is a
link-local address (what ndppd and Linux proxy_ndp emit) and require the
advertised global address. Replace the distro ndppd prefix-mode data
plane with an in-tree raw AF_PACKET responder whose NA source is the
target's global address, re-reading a panel-writable rules file while it
runs so vps add/del never restarts it.

- add internal/ndp: minimal NDP responder (NS->NA, DAD handling, correct
  ICMPv6 checksum/hop-limit/flags); only answers for target blocks inside
  the operator's routed prefix (confines the root responder's trust surface)
- main: ipv6-proxy unit (prefix mode) + ipv6-proxy command + ethernetMAC
  pre-check at install so a broken ext_if never hot-loops under Restart=always
- ipv6.go: write ndppd.conf atomically (temp+rename), drop all ndppd daemon
  management and its sudoers grants
- mgr/routed_ipv6.go: configure guest v6 before publishing the NDP rule;
  pin fe80::1 gateway neighbor, UseGateway=false, local /112 route +
  vpsmgr-ipv6.service helper in the guest
- 50-image.sh/80-debian-dev-image.sh: bake UseGateway=false into [IPv6AcceptRA]
2026-08-31 17:45:24 +08:00
bluebluesoda f79ccb09f0 feat(install): add btrfs storage backend (native subvolume or loop file)
- VPSMGR_STORAGE now accepts btrfs alongside zfs and dir. On a btrfs root the
  pool is created as a native subvolume at /var/lib/incus/storage-pools/vpsmgr
  (Incus only allows that source path and requires it NOT to pre-exist); on any
  other host it becomes a sparse loop-file pool sized exactly like ZFS.
- install.sh asks for an explicit beta confirmation up front when the btrfs
  backend is selected (default yes — on a btrfs host there is no ZFS fallback).
  Non-interactive installs proceed; non-btrfs/default-zfs installs are
  unchanged.
- btrfs swap: on a btrfs root the swapfile is created with
  `btrfs filesystem mkswapfile` (btrfs-progs >= 6.1), falling back to
  truncate + chattr +C + dd for older tools — the generic fallocate+mkswap path
  fails on btrfs (swap must be NODATACOW and preallocated). Non-btrfs hosts
  keep the existing fallocate path.
- 00-check.sh installs btrfs-progs and skips the ZFS DKMS/kernel-header
  toolchain for btrfs and dir alike; 10-incus.sh verifies the final driver.
- Panel Go code is untouched: container management is storage-driver-
  transparent, and lx.EnsureZFSRemoveSnapshots is a no-op off ZFS.
- Docs (architecture, configuration, READMEs, AGENTS) updated for the new
  backend, including snapshot-restore semantics (btrfs keeps later snapshots).

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 17:00:03 +08:00
bluebluesoda 6eafac3274 fix(install): don't start traefik when IPv4 forwarding is off
30-traefik.sh enabled traefik whenever the adopted net.traefik was true, even
on an IPv6-only box (net.v4_forward false). The domain proxy is only served
while BOTH v4 ingress and net.traefik are on, so traefik must stay installed
but DISABLED (no start, no boot autostart) when v4 forwarding is off, regardless
of the kept net.traefik value; re-enabling v4 later restores it. The start
branch is now gated on VPSMGR_V4_FORWARD first, matching the panel's own
ApplyTraefikState (V4Forward && Traefik).

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 07:26:32 +00:00
bluebluesoda e0dd123dc1 feat(name): allow hyphens in usernames, require letter start+end
- Usernames may now contain hyphens (lowercase letters/digits/hyphens), but a
  new name must both start and end with a lowercase letter, max 31 unchanged.
  This drops digit-terminated names like "a1"/"vps12345678" at creation.
- The strict rule is enforced only when CREATING a user (ValidateName in
  Add/userAdd and the admin add-user form's pattern). An existing-user
  operation (del / quota / passwd) now uses ValidateExistingName, which accepts
  every historically-valid shape, so a legacy digit-ending username stays
  operable rather than being locked out by the new creation rule.
- Tests cover the strict rule, its new rejects, and the legacy-compatible
  existing-name check.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 07:06:59 +00:00
bluebluesoda 6fcc97b81b docs: document the snapshot "time machine" semantics
- architecture.md: new bullet under Users and resources explaining that
  restoring to an older checkpoint discards the later ones, done as a single
  Incus call via zfs.remove_snapshots on the ZFS root volume (recursive
  rollback), applied at add/reinstall and refreshed on every `vps install`
  (incl. --update), with the delete-and-retry fallback and the reinstall
  checkpoint-count warning.
- configuration.md: snapshots.limit row now notes that restoring to an older
  checkpoint auto-deletes the newer ones.
- README / README.en: list the time-machine (checkpoint) feature in the user
  panel feature lists.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-31 06:58:11 +00:00
bluebluesoda 2ff2144e1b feat(snapshot): one-call "time machine" restore via zfs.remove_snapshots
- A restore to an older checkpoint now relies on zfs.remove_snapshots set on
  the container root volume, so a single Incus restore auto-discards the later
  snapshots instead of failing with "subsequent snapshot(s)" and leaving a
  partially-executed rollback.
- The volume option is set at Add/Reinstall (on the fresh root volume) and by
  a new ApplyZFSRemoveSnapshotsToAll pass run during `vps install`, so a host
  updated via install.sh --update gets the behaviour immediately without
  reinstalling containers. ZFS-only: non-ZFS (dir test) pools are skipped, as
  they have no snapshots.
- SnapshotRestore keeps a fallback that deletes the newer snapshots by
  creation time and retries once, for a volume that somehow lacks the option.
- User panel adopts the time-machine metaphor: the button is now
  "时光机"/Time machine, individual snapshots are "检查点"/checkpoints, the
  reinstall modal warns with the exact checkpoint count, and the admin audit
  labels + success toasts use the same terms. Adds unit tests for the
  newer-snapshot selection and timestamp parsing.
2026-08-31 06:56:29 +00:00
bluebluesoda 366ceff41e Update 00-ip-ask.sh 2026-08-31 14:13:46 +08:00
bluebluesoda 8a74607bcf Update README.en.md 2026-08-30 19:46:40 +08:00
bluebluesoda 840dc52aac Update README.md 2026-08-30 19:46:17 +08:00
bluebluesoda 6e8dd6c4f8 feat(install): echo slot-range capacity + ports hint, don't prompt on upgrade
- ask_range now prints one line right after the slot range is finalized
  (env / adoption / non-interactive / interactive alike) with the computed
  container capacity and the usable user-port span it reserves, so the
  operator sees the effect immediately.
- An existing config WITHOUT a slot_range key (an upgrade from a
  pre-slot-range version) no longer prompts: it keeps the default 2-201
  (which the panel applies anyway) and returns, so a one-click upgrade of
  an already-deployed panel is never interrupted by the new question.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-30 09:43:44 +00:00
bluebluesoda fa151eaee4 feat(install): configurable slot range + auto-off Traefik on 80/443 conflict
Add net.slot_range, a shrinkable container slot range (read as the IPv4
last octet a new container may take; idx = octet-1) that bounds how many
containers can be created and, consequently, how much of the user-port
block 10000-29999 a host reserves. Default 2-201 = 200 slots; must always
be a sub-range of 2-201 (only-shrink rule). Affects ONLY new containers —
existing ones keep their slot/ports.

- cfg: add net.slot_range with strict ParseSlotRange validation
  (exactly one '-', both ends integers in 2..201, lo<=hi), SlotCount/
  SlotIdxBounds helpers, and VPSMGR_SLOT_RANGE env handling in FillAuto.
  Register net.slot_range as operator / next-add in the config registry.
- db/mgr: NextFreeIdx now picks from a caller-supplied [idxMin,idxMax]
  window instead of the fixed 1..cfg.MaxUsers; mgr.Add feeds it from the
  configured range. Existing users outside a narrowed range keep their
  slots.
- admin panel: capacity readout follows SlotCount() instead of a fixed
  200 (honestly shows over-capacity when pre-existing users fall outside
  a shrunken range).
- installer: 00-checklist asks the slot range right after the subnet
  octet (env/adoption/non-interactive branches, validated). The
  port-occupancy check now scans only the range's user-port span rather
  than the whole 10000-29999.
- 80/443 handling: if either is already bound by a non-vpsmgr process,
  the install no longer fails — it proceeds with Traefik installed but
  DISABLED (net.traefik false, no autostart). 00-check writes a marker
  that install.sh turns into VPSMGR_TRAEFIK=0 for 30-traefik and the
  panel. A belt-and-suspenders guard skips the force-off when our own
  traefik.service is already active (update/adoption). SSH 30000-31999
  and the user-port span remain hard failures.
- traefik: bump pinned version to 3.7.12 and rewrite 30-traefik's
  enable/disable decision to respect the effective net.traefik (forced
  env > adopted config > default), so a disabled traefik is never
  briefly started.
- docs: README(s), config example, architecture and configuration docs
  updated; tests added for slot-range parsing and the FillAuto env vars.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-30 09:36:29 +00:00
bluebluesoda 25758a6590 feat(install): swap prompt offers 1:1 RAM size via y
- prompt now shows [<RAM> GiB/y/N] with the auto size computed from
  host memory; answering y creates a swap file of RAM × 1:1
- custom sizes in GiB are still accepted, N/Enter aborts as before

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-30 08:30:53 +00:00
bluebluesoda 1b564a9900 feat(install): use container-only incus-base instead of full incus
- new installs pull incus-base (Zabbly lts-7.0) which ships the same
  incusd daemon without the QEMU/SPICE/Ceph VM stack (~240 MiB less
  download, 500 MiB+ less disk)
- leave hosts that already carry the full `incus` package untouched
- uninstall --purge now also removes the full-incus VM dependencies,
  guarded by an installed reverse-dependency check (never blanket autoremove)
- update the dev docs install snippet to incus-base

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-30 08:19:19 +00:00
bluebluesoda 07dedf9e9f Update 00-ip-ask.sh 2026-08-30 08:46:58 +08:00
bluebluesoda 4c0d1750a3 Update 00-ip-ask.sh 2026-08-30 08:44:36 +08:00
bluebluesoda 1158eb96da feat(config): add independent Traefik toggle
- add runtime net.traefik switch with live DB state\n- stop and disable Traefik when IPv4 forwarding is off\n- block new domains while Traefik is disabled
2026-08-29 14:34:47 +00:00