#!/usr/bin/env bash # Runs on a Proxmox VE host. Creates a privileged LXC container prepared for # WireGuard (kernel module + /dev/net/tun + CAP_NET_ADMIN + nftables), copies # this repo into it, and runs scripts/install.sh inside the container. # # Privileged container is required: WireGuard needs CAP_NET_ADMIN and access # to /dev/net/tun, which unprivileged LXC containers cannot reliably get. set -euo pipefail usage() { cat >&2 < --hostname [options] Required: --vmid numeric LXC container ID (e.g. 200) --hostname container hostname (e.g. wireguard-ui-multi) Options: --storage Proxmox storage for rootfs (default: local-lvm) --template LXC template volid (default: auto-detect + download newest debian-* template) --bridge network bridge (default: vmbr0) --ip static CIDR (e.g. 10.0.0.50/24) or "dhcp" (default: dhcp) --gw gateway IP, required if --ip is a static CIDR --disk rootfs size in GB (default: 4) --memory RAM in MB (default: 512) --cores CPU cores (default: 1) --repo-src path to this repo on the Proxmox host (default: script's own repo root) --start start the container after creation (default: created but stopped, then started to run the installer, left running) EOF exit 1 } VMID="" HOSTNAME="" STORAGE="local-lvm" TEMPLATE="" BRIDGE="vmbr0" IP="dhcp" GW="" DISK="4" MEMORY="512" CORES="1" REPO_SRC="" while [[ $# -gt 0 ]]; do case "$1" in --vmid) VMID="$2"; shift 2 ;; --hostname) HOSTNAME="$2"; shift 2 ;; --storage) STORAGE="$2"; shift 2 ;; --template) TEMPLATE="$2"; shift 2 ;; --bridge) BRIDGE="$2"; shift 2 ;; --ip) IP="$2"; shift 2 ;; --gw) GW="$2"; shift 2 ;; --disk) DISK="$2"; shift 2 ;; --memory) MEMORY="$2"; shift 2 ;; --cores) CORES="$2"; shift 2 ;; --repo-src) REPO_SRC="$2"; shift 2 ;; -h|--help) usage ;; *) echo "Unknown option: $1" >&2; usage ;; esac done [[ -z "$VMID" || -z "$HOSTNAME" ]] && usage if [[ "$(id -u)" -ne 0 ]]; then echo "Must run as root on the Proxmox host." >&2 exit 1 fi if ! command -v pct >/dev/null 2>&1; then echo "pct not found - this script must run on a Proxmox VE host." >&2 exit 1 fi if [[ -z "$REPO_SRC" ]]; then REPO_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" fi if [[ -z "$TEMPLATE" ]]; then echo "No --template given, looking up newest debian-* template..." pveam update >/dev/null TEMPLATE_FILE="$(pveam available --section system \ | awk '{print $2}' \ | grep -E '^debian-[0-9]+-standard_' \ | sort -V \ | tail -n1)" if [[ -z "$TEMPLATE_FILE" ]]; then echo "Could not find any debian-* template via 'pveam available'." >&2 exit 1 fi if ! pveam list "$STORAGE" | grep -q "$TEMPLATE_FILE"; then echo "Downloading $TEMPLATE_FILE to storage $STORAGE..." pveam download "$STORAGE" "$TEMPLATE_FILE" fi TEMPLATE="${STORAGE}:vztmpl/${TEMPLATE_FILE}" echo "Using template: $TEMPLATE" fi NET_CONFIG="name=eth0,bridge=${BRIDGE},firewall=1" if [[ "$IP" == "dhcp" ]]; then NET_CONFIG="${NET_CONFIG},ip=dhcp" else if [[ -z "$GW" ]]; then echo "--gw is required when --ip is a static CIDR." >&2 exit 1 fi NET_CONFIG="${NET_CONFIG},ip=${IP},gw=${GW}" fi echo "Creating privileged LXC $VMID ($HOSTNAME)..." pct create "$VMID" "$TEMPLATE" \ --hostname "$HOSTNAME" \ --storage "$STORAGE" \ --rootfs "${STORAGE}:${DISK}" \ --memory "$MEMORY" \ --cores "$CORES" \ --net0 "$NET_CONFIG" \ --unprivileged 0 \ --features "nesting=1,keyctl=1" \ --onboot 1 echo "Enabling /dev/net/tun and WireGuard kernel module passthrough..." CONF="/etc/pve/lxc/${VMID}.conf" { echo "lxc.cgroup2.devices.allow: c 10:200 rwm" echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file" } >> "$CONF" echo "Starting container..." pct start "$VMID" sleep 5 echo "Installing base dependencies inside container (Go, git, wireguard-tools, nftables)..." pct exec "$VMID" -- bash -c " set -e apt-get update apt-get install -y wireguard-tools nftables curl ca-certificates git if ! command -v go >/dev/null 2>&1; then ARCH=\$(dpkg --print-architecture) curl -fsSL https://go.dev/dl/go1.22.5.linux-\${ARCH}.tar.gz -o /tmp/go.tar.gz tar -C /usr/local -xzf /tmp/go.tar.gz ln -sf /usr/local/go/bin/go /usr/local/bin/go rm -f /tmp/go.tar.gz fi " echo "Copying repo into container..." TMP_TAR="$(mktemp)" tar -C "$REPO_SRC" -czf "$TMP_TAR" --exclude=.git . pct push "$VMID" "$TMP_TAR" /tmp/wireguard-ui-multi.tar.gz rm -f "$TMP_TAR" pct exec "$VMID" -- bash -c " set -e mkdir -p /opt/wireguard-ui-multi-src tar -C /opt/wireguard-ui-multi-src -xzf /tmp/wireguard-ui-multi.tar.gz rm -f /tmp/wireguard-ui-multi.tar.gz " echo "Running native installer inside container..." pct exec "$VMID" -- bash -c " set -e cd /opt/wireguard-ui-multi-src go build -o wireguard-ui-multi ./cmd/wireguard-ui-multi bash scripts/install.sh " echo echo "Container $VMID ($HOSTNAME) is set up. wireguard-ui-multi is installed but not started." echo "To enable and start it inside the container, run:" echo echo " pct exec $VMID -- systemctl enable --now wireguard-ui-multi.service" echo echo "Then check status with:" echo echo " pct exec $VMID -- systemctl status wireguard-ui-multi.service" echo " pct exec $VMID -- journalctl -u wireguard-ui-multi.service -f"