diff --git a/README.en.md b/README.en.md index 556ecac..88cdb32 100644 --- a/README.en.md +++ b/README.en.md @@ -21,6 +21,8 @@ A lightweight Incus container hosting panel for small VPS instances and low-memo Ubuntu 24.04 is recommended; Ubuntu 22+ and Debian 12+ also work. Debian requires a kernel-module build and takes longer to install. +Unless you have checked the existing services and network configuration, treat the installer as a fresh, dedicated-host installer. Do not run it directly on a personal host that already serves other workloads. It installs and configures Incus, ZFS (by default), nftables, Traefik, systemd units, and a container bridge; with IPv4 inbound forwarding enabled it also requires ports `80/443`, `10000-29999`, and `30000-31999` to be available, and may disable conflicting UFW configuration. The installer does not uninstall your applications, but its ports, bridge, and firewall policy can conflict with existing services. + Recommended minimum: 1 CPU core, 1 GB RAM, 15 GB of free disk space, and root access. Both amd64 and arm64 are supported; testing has focused mainly on amd64. ```sh @@ -33,6 +35,14 @@ sudo ./install.sh # download the latest prebuilt binary The installer first downloads the prebuilt binary from GitHub Releases. If that fails, it falls back to a local build. `--local-build` always rebuilds from source. If `--update` cannot download the release, the existing binary is left untouched. +If the host already runs other public services and you only need IPv6 inbound access, without IPv4 SSH/port forwarding, use: + +```sh +sudo ./install.sh --disable-v4forward +``` + +This option asks for confirmation at the beginning. Once confirmed, it writes `net.v4_forward=false`, skips vpsmgr's reserved-port check, and only needs one randomly selected panel entry port. Traefik is still installed but remains stopped. IPv4 inbound forwarding can later be restored with `vps config set net.v4_forward true`. + ZFS is the default storage backend. For disposable test machines, you can explicitly choose the `dir` backend. It does not provide ZFS quotas, snapshots, or cloning: ```sh diff --git a/README.md b/README.md index d54d6ef..642ee38 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ 推荐使用 Ubuntu 24.04。Ubuntu 22+ / Debian 12+ 均可使用;Debian 需要编译内核模块,安装时间较长。 +除非你明确检查过现有服务与网络配置,否则请把安装器视为“全新、专用主机”安装器,不要直接在正在运行其他业务的自用主机上执行。安装器会安装并配置 Incus、ZFS(默认)、nftables、Traefik、systemd 服务和容器网桥;启用 v4 入站转发时还要求 `80/443`、`10000-29999`、`30000-31999` 端口可用,并可能停用冲突的 UFW 配置。安装器不会卸载你的业务程序,但端口、网桥和防火墙策略可能与已有服务冲突。 + 最低建议:1 核、1 GB 内存、15 GB 可用磁盘空间,以及 root 权限。amd64 和 arm64 均支持,主要在 amd64 上测试。 **从预编译安装** @@ -38,6 +40,14 @@ git clone --depth 1 https://github.com/bluebluesoda/vpsmgr.git && cd vpsmgr sudo ./install.sh --local-build ``` +如果这台主机已有其他公网服务,且你只需要 IPv6 入站、不需要 v4 SSH/端口转发,可以使用: + +```sh +sudo ./install.sh --disable-v4forward +``` + +该参数会在安装开始时要求确认;确认后写入 `net.v4_forward=false`,跳过 vpsmgr 保留端口检查,只随机选择一个面板入口端口。Traefik 仍会安装但不会启动。以后可用 `vps config set net.v4_forward true` 恢复 IPv4 入站转发。 + ### IPv6 IPv6 直通默认关闭。交互式安装会询问是否启用,并根据网络条件提供以下模式: diff --git a/configs/config.yaml.example b/configs/config.yaml.example index 823d5b0..655774f 100644 --- a/configs/config.yaml.example +++ b/configs/config.yaml.example @@ -12,7 +12,7 @@ panel: url_path: AUTO # 10-char random [a-zA-Z0-9_-] secret prefix, generated once at install admin_url_path: AUTO # 10-char random secret prefix for the ADMIN panel; can be # changed later or set to empty to disable the admin panel - admin_pass_hash: AUTO # bcrypt hash of the admin panel password; generated at install, + admin_pass_hash: AUTO # bcrypt hash of the admin panel password; generated at install, # reset via `vps admin-passwd`. No admin username — password only. net: @@ -28,14 +28,22 @@ net: # SSH/port-block DNAT and traefik/domains disabled # (NAT4 outbound kept). Toggle at runtime: vps config set net.v4_forward true|false ext_if: AUTO # detected from default route + ipv6_mode: none # fixed at install: none, prefix, or pool ipv6_subnet: "" # optional: global prefix for IPv6 pass-through, e.g. "2602:fada:6::/64". - # /64 or shorter works (e.g. /56); a provider /80 slice like + # /64 or shorter uses the first /64; a provider /80 slice like # "2406:da14:1dd2:a807:753a::/80" is also supported. # empty = IPv6 disabled (default). Containers get global # addresses via SLAAC; no NAT; set at install time. + ipv6_pool: [] # optional (pool mode): bare global IPv6 addresses or /128; + # addresses are assigned to containers until they are deleted. incus: image: "vpsmgr/debian-sshd" image_fallback: "images:debian/13" pool: vpsmgr bridge: incusbr0 + socket: "/var/lib/incus/unix.socket" + swap_ratio: 0.5 # 0 = no container swap; 0.5 = memory allowance / 2 + +snapshots: + limit: 1 # 0 disables new snapshots diff --git a/docs/configuration.md b/docs/configuration.md index 1223d7b..2df7b90 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -5,6 +5,13 @@ root-only read/write). The `VPSMGR_CONFIG` env var points the `vps` binary at another path; the shell install/uninstall scripts always use `/etc/vpsmgr/config.yaml`. +The installer is intended for a fresh, dedicated host unless existing services, +ports, bridges, UFW, and firewall rules have been checked. For a host that must +keep other public services and only needs IPv6 inbound access, install with +`./install.sh --disable-v4forward`; this requires an explicit confirmation, +skips vpsmgr's reserved-port check, writes `net.v4_forward=false`, and leaves +Traefik installed but stopped. + **Editing config.yaml by hand is discouraged.** The sanctioned interface is `vps config list` / `vps config set` / `vps config help`, which validate every change and refuse immutable fields. A raw YAML edit still works but is not @@ -21,7 +28,7 @@ same table; `vps config list` shows the live values with this annotation. | `panel.listen` | operator | `systemctl restart vps` | a FRESH install picks a random free port in 2000-9999 | | `panel.cert` | operator | restart panel | TLS certificate path | | `panel.key` | operator | restart panel | TLS private key path | -| `panel.db` | operator | restart panel | SQLite database path | +| `panel.db` | operator | re-run `vps install` | SQLite database path | | `panel.public_ip` | operator | re-run `vps install` | NIC IPv4 used by firewall/routing; cert is regenerated | | `panel.display_ip` | operator | restart panel | address shown to users (panel URL / SSH hints); any string without spaces (IP or domain), or empty = fall back to `public_ip` | | `panel.session_days` | operator | restart panel | login session lifetime (days) | @@ -34,19 +41,19 @@ same table; `vps config list` shows the live values with this annotation. | `net.ext_if` | operator | re-run `vps install` | external NIC (auto-detected from default route) | | `net.ipv6_subnet` | operator | re-run `vps install` | global IPv6 prefix for pass-through, e.g. `2602:fada:6::/64`; empty = disabled (does not remove IPv6 state already applied, see note below) | | `net.ipv6_mode` | **fixed at install** | — | IPv6 allocation mode: `none` / `prefix` (/112 blocks) / `pool` (per-container address) | -| `net.ipv6_pool` | operator | applied immediately | pool-mode address list (bare global addresses or `/128`); editable via the admin panel's IPv6 Pool page | +| `net.ipv6_pool` | operator | `vps config set` needs `--apply`; admin-panel changes apply immediately | pool-mode address list (bare global addresses or `/128`); editable via the admin panel's IPv6 Pool page | | `incus.image` | operator | next `vps add` / reinstall | container image alias | | `incus.image_fallback` | operator | next `vps add` / reinstall | fallback remote image | | `incus.pool` | **fixed at install** | — | storage pool | | `incus.bridge` | **fixed at install** | — | managed bridge | | `incus.socket` | operator | restart panel | Incus daemon Unix socket | | `incus.swap_ratio` | operator | **applied immediately** | swap granted to each container as a multiple of its memory limit (`limits.memory.swap = limits.memory × ratio`); `0` disables container swap. Setting it re-applies the allowance to **all existing containers** (no restart) | -| `snapshots.limit` | operator | restart panel | max snapshots a user may keep per container (`0` = default `1`) | +| `snapshots.limit` | operator | restart panel | max snapshots a user may keep per container (`0` = disable new snapshots) | ### How "fixed at install" is enforced Fields marked **fixed at install** (`net.subnet`, `net.gateway`, `incus.pool`, -`incus.bridge`, `panel.url_path`) are snapshotted into the DB settings table on +`incus.bridge`, `panel.url_path`, `net.ipv6_mode`) are snapshotted into the DB settings table on the first `vps install`. Every later `vps install` and `vps serve` compares the live config against that snapshot and **refuses to run** if any of them drifted — `vps config set` also refuses them up front. The user panel path @@ -91,7 +98,7 @@ net: ext_if: AUTO # external NIC, auto-detected from the default route ipv6_mode: "" # IPv6 allocation mode: none / prefix / pool (fixed at install) ipv6_subnet: "" # optional: global prefix for IPv6 pass-through, e.g. "2602:fada:6::/64" - # (/64 or shorter, incl. provider /80 slices like + # (/64 or shorter uses the first /64; provider /80 slices like # "2406:da14:1dd2:a807:753a::/80"); empty = disabled (default), # but does not remove IPv6 state already applied ipv6_pool: [] # optional (pool mode): the /128 addresses containers are @@ -108,6 +115,9 @@ incus: # memory limit (0 = no swap; 0.5 = a 1 GiB # container may use 512 MiB host swap); # applied to all containers immediately on set + +snapshots: + limit: 1 # 0 disables new snapshots ``` ## Port scheme (fixed) @@ -159,7 +169,8 @@ goes away when the panel is uninstalled. change them after first install. - `net.ipv6_subnet` must be a **global** (non-ULA) IPv6 CIDR with an explicit prefix length — a bare address is rejected, never silently assumed `/64`. - Valid range is `/48`..`/80` (see [ipv6.md](ipv6.md)). + The validator accepts a global prefix of `/80` or shorter; `/48`..`/80` are + the documented operational range (see [ipv6.md](ipv6.md)). - `net.ipv6_mode` is fixed at install and immutable (like `net.subnet`): `none` (pure IPv4), `prefix` (classic /112 blocks), `pool` (per-container address from `net.ipv6_pool`). Switching modes would renumber containers. diff --git a/install.sh b/install.sh index a6d6a69..665d985 100755 --- a/install.sh +++ b/install.sh @@ -4,19 +4,29 @@ # ./install.sh # default: download latest prebuilt release binary (fallback: local build) # ./install.sh --local-build # force local Go compilation of the panel binary # ./install.sh --update # force re-download of the prebuilt release binary over an existing one +# ./install.sh --disable-v4forward # install IPv6-only inbound policy; skip reserved-port checks set -euo pipefail cd "$(dirname "$0")" ROOT="$PWD" BUILD_MODE=release +DISABLE_V4FORWARD=0 for arg in "$@"; do case "$arg" in --local-build) BUILD_MODE=local ;; --update) BUILD_MODE=update ;; + --disable-v4forward) DISABLE_V4FORWARD=1 ;; esac done export VPSMGR_BUILD_MODE="$BUILD_MODE" +if [[ "$DISABLE_V4FORWARD" == "1" ]]; then + # This explicit installer choice overrides an adopted config and any + # VPSMGR_V4_FORWARD value inherited from the caller. 00-check.sh uses the + # separate marker to skip checks for ports that vpsmgr will not expose. + export VPSMGR_V4_FORWARD=0 + export VPSMGR_DISABLE_V4FORWARD=1 +fi # Storage backend: zfs (default) or dir. dir has no quotas/snapshots/clones — # only meant for throwaway test boxes. Never fall back automatically. @@ -31,6 +41,24 @@ if [[ $EUID -ne 0 ]]; then exit 1 fi +if [[ "$DISABLE_V4FORWARD" == "1" ]]; then + echo + echo "!! --disable-v4forward: install with IPv4 inbound forwarding disabled !!" + echo " Containers will have no IPv4 SSH/port DNAT; Traefik will be installed but stopped." + echo " Reserved vpsmgr port checks will be skipped. You can re-enable later with:" + echo " vps config set net.v4_forward true" + if [[ ! -t 0 ]]; then + echo "error: --disable-v4forward requires an interactive confirmation" >&2 + exit 1 + fi + read -r -p "Continue with IPv4 inbound disabled? [Y/n] " V4_CONFIRM + case "$V4_CONFIRM" in + ''|y|Y|yes|YES) ;; + n|N|no|NO) echo "[install] aborted by user"; exit 1 ;; + *) echo "error: please answer Y or n" >&2; exit 1 ;; + esac +fi + # Local build: make it obvious WHICH branch will be compiled, and give the user # a chance to abort — some people want a dev build but end up building stable. if [[ "$BUILD_MODE" == "local" ]]; then diff --git a/oneclick.sh b/oneclick.sh index 856d3a3..3427cf8 100644 --- a/oneclick.sh +++ b/oneclick.sh @@ -10,6 +10,7 @@ # Supported args (passed straight through to install.sh): # --update re-download the latest prebuilt release binary over an existing one # --local-build force local Go compilation of the panel binary +# --disable-v4forward install with IPv4 inbound forwarding disabled # Env: # VPSMGR_STORAGE=zfs|dir storage backend (default zfs) # VPSMGR_BRANCH= branch/tag to fetch (default main) @@ -32,7 +33,7 @@ fi ARGS=() for a in "$@"; do case "$a" in - --update|--local-build) ARGS+=("$a") ;; + --update|--local-build|--disable-v4forward) ARGS+=("$a") ;; *) echo "oneclick.sh: ignoring unknown arg '$a'" >&2 ;; esac done diff --git a/scripts/00-check.sh b/scripts/00-check.sh index b909078..4f5a81d 100755 --- a/scripts/00-check.sh +++ b/scripts/00-check.sh @@ -197,6 +197,9 @@ fi # panel and traefik are already running and owned by vpsmgr — those listeners # are excluded by process name. Checks TCP and UDP (the user port block is # DNAT-ed for both). +if [[ "${VPSMGR_DISABLE_V4FORWARD:-0}" == "1" ]]; then + log "v4 forwarding disabled by installer — skipping reserved port checks" +else port_reserved(){ local p="$1" [[ "$p" == "80" || "$p" == "443" ]] && return 0 @@ -226,6 +229,7 @@ $CONFLICTS Free these ports (or remove the programs above) and re-run install." fi log "reserved ports are free" +fi # --- detect public ip / ext iface --- # ext iface: prefer the IPv4 default route, then the IPv6 default route (covers