From b91512e97fbfa5a819fe3013258c6effa5569d05 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Fri, 6 Mar 2026 01:26:12 +0800 Subject: [PATCH] feat: add missing service deploy scripts (sing-box, tnt, minio, galene) Infrastructure audit revealed services running in production with no corresponding deploy scripts. Closes #11. - sing-box: server + client deploy scripts. Config generated by sing-box-yg (https://github.com/yonggekkk/sing-box-yg), stored in infra for recovery. - tnt: terminal chat server via official install.sh; proper systemd unit with unprivileged user and security hardening. - minio: single-binary install from dl.min.io; minio-user, /etc/default/minio. - galene: binary install from GitHub releases; configurable UDP range for WebRTC. - frp/server: add FRP_WEB_USER to .env.example and frps.toml.example; fix hardcoded "root" username in web dashboard config. --- README.md | 47 +++++++++++++-- services/frp/server/.env.example | 1 + services/frp/server/deploy.sh | 2 +- services/frp/server/frps.toml.example | 2 +- services/galene/.env.example | 6 ++ services/galene/deploy.sh | 81 ++++++++++++++++++++++++++ services/minio/.env.example | 8 +++ services/minio/deploy.sh | 83 +++++++++++++++++++++++++++ services/sing-box/client/.env.example | 3 + services/sing-box/client/deploy.sh | 66 +++++++++++++++++++++ services/sing-box/server/.env.example | 3 + services/sing-box/server/deploy.sh | 77 +++++++++++++++++++++++++ services/tnt/.env.example | 7 +++ services/tnt/deploy.sh | 70 ++++++++++++++++++++++ 14 files changed, 450 insertions(+), 6 deletions(-) create mode 100644 services/galene/.env.example create mode 100755 services/galene/deploy.sh create mode 100644 services/minio/.env.example create mode 100755 services/minio/deploy.sh create mode 100644 services/sing-box/client/.env.example create mode 100755 services/sing-box/client/deploy.sh create mode 100644 services/sing-box/server/.env.example create mode 100755 services/sing-box/server/deploy.sh create mode 100644 services/tnt/.env.example create mode 100755 services/tnt/deploy.sh diff --git a/README.md b/README.md index 827b8d9..0d28435 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ INFRA_DIR=/path/to/infra/services/nginx ./services/nginx/deploy.sh ``` ### Shadowsocks -GFW-resistant proxy. +GFW-resistant proxy (legacy; new deployments should use sing-box). ```bash # Server (VPS) @@ -60,6 +60,18 @@ INFRA_DIR=/path/to/infra/services/shadowsocks/server ./services/shadowsocks/serv INFRA_DIR=/path/to/infra/services/shadowsocks/client ./services/shadowsocks/client/deploy.sh ``` +### Sing-box +Multi-protocol proxy (VLESS/Reality, VMess/WS, Hysteria2). Config generated once +by [sing-box-yg](https://github.com/yonggekkk/sing-box-yg), then stored in infra. + +```bash +# Server (VPS) +INFRA_DIR=/path/to/infra/services/sing-box/server ./services/sing-box/server/deploy.sh + +# Client (home machine) +INFRA_DIR=/path/to/infra/services/sing-box/client ./services/sing-box/client/deploy.sh +``` + ### FRP Reverse tunnel — expose home services through VPS. @@ -71,6 +83,27 @@ INFRA_DIR=/path/to/infra/services/frp/server ./services/frp/server/deploy.sh INFRA_DIR=/path/to/infra/services/frp/client ./services/frp/client/deploy.sh ``` +### TNT +SSH-based terminal chat server. + +```bash +INFRA_DIR=/path/to/infra/services/tnt ./services/tnt/deploy.sh +``` + +### MinIO +S3-compatible object storage. + +```bash +INFRA_DIR=/path/to/infra/services/minio ./services/minio/deploy.sh +``` + +### Galene +WebRTC video conferencing server. + +```bash +INFRA_DIR=/path/to/infra/services/galene ./services/galene/deploy.sh +``` + ## Home Services Docker-based services with their own config. @@ -143,9 +176,15 @@ automa/ │ ├── shadowsocks/ │ │ ├── server/deploy.sh │ │ └── client/deploy.sh -│ └── frp/ -│ ├── server/deploy.sh -│ └── client/deploy.sh +│ ├── sing-box/ +│ │ ├── server/deploy.sh +│ │ └── client/deploy.sh +│ ├── frp/ +│ │ ├── server/deploy.sh +│ │ └── client/deploy.sh +│ ├── tnt/deploy.sh +│ ├── minio/deploy.sh +│ └── galene/deploy.sh ├── minecraft/ # Minecraft server (Docker) ├── teamspeak/ # TeamSpeak server (Docker) ├── nextcloud/ # Nextcloud (Docker) diff --git a/services/frp/server/.env.example b/services/frp/server/.env.example index 87a31cc..78e495d 100644 --- a/services/frp/server/.env.example +++ b/services/frp/server/.env.example @@ -2,5 +2,6 @@ # description: FRP server (frps) — public entry point for reverse tunnels FRP_TOKEN= +FRP_WEB_USER=admin FRP_WEB_PASSWORD= FRP_BIND_PORT=7000 diff --git a/services/frp/server/deploy.sh b/services/frp/server/deploy.sh index dbe27b7..40bcee5 100755 --- a/services/frp/server/deploy.sh +++ b/services/frp/server/deploy.sh @@ -10,7 +10,7 @@ ENV_FILE="${INFRA_DIR:-.}/.env" [ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; } set -a; source "$ENV_FILE"; set +a -require_env FRP_TOKEN FRP_WEB_PASSWORD FRP_BIND_PORT +require_env FRP_TOKEN FRP_WEB_USER FRP_WEB_PASSWORD FRP_BIND_PORT find_template() { local f="$1" diff --git a/services/frp/server/frps.toml.example b/services/frp/server/frps.toml.example index c9e9834..720a6d5 100644 --- a/services/frp/server/frps.toml.example +++ b/services/frp/server/frps.toml.example @@ -6,7 +6,7 @@ vhostHTTPSPort = 8443 webServer.addr = "127.0.0.1" webServer.port = 7500 -webServer.user = "root" +webServer.user = "${FRP_WEB_USER}" webServer.password = "${FRP_WEB_PASSWORD}" log.to = "./frps.log" diff --git a/services/galene/.env.example b/services/galene/.env.example new file mode 100644 index 0000000..a94ce22 --- /dev/null +++ b/services/galene/.env.example @@ -0,0 +1,6 @@ +# role: vps +# description: Galene video conferencing server +GALENE_VERSION=0.9.2 +GALENE_HTTP_ADDR=127.0.0.1:8443 +GALENE_TURN_ADDR=x.x.x.x:1194 +GALENE_UDP_RANGE=10000-10100 diff --git a/services/galene/deploy.sh b/services/galene/deploy.sh new file mode 100755 index 0000000..692c19c --- /dev/null +++ b/services/galene/deploy.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Deploys Galene video conferencing server. +# https://github.com/jech/galene +# +# Usage: INFRA_DIR=/path/to/infra/services/galene ./deploy.sh + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../../bin/lib/common.sh" + +ENV_FILE="${INFRA_DIR:-.}/.env" +[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; } +set -a; source "$ENV_FILE"; set +a + +require_env GALENE_VERSION GALENE_HTTP_ADDR GALENE_TURN_ADDR + +INSTALL_DIR="/opt/galene" +BIN="$INSTALL_DIR/galene" + +if [[ -x "$BIN" ]]; then + log_info "galene already at $BIN, skipping download" +else + log_info "Downloading Galene ${GALENE_VERSION}..." + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) log_error "Unsupported arch: $ARCH"; exit 1 ;; + esac + URL="https://github.com/jech/galene/releases/download/galene-${GALENE_VERSION}/galene-${GALENE_VERSION}-linux-${ARCH}.tar.gz" + TMP="$(mktemp -d)" + wget -qO "$TMP/galene.tar.gz" "$URL" + mkdir -p "$INSTALL_DIR" + tar -xf "$TMP/galene.tar.gz" -C "$INSTALL_DIR" --strip-components=1 + chmod +x "$BIN" + rm -rf "$TMP" +fi + +log_info "Creating directories..." +mkdir -p "$INSTALL_DIR"/{data,groups,static} + +log_info "Deploying groups config from INFRA_DIR..." +if [[ -d "${INFRA_DIR}/groups" ]]; then + cp -r "${INFRA_DIR}/groups/." "$INSTALL_DIR/groups/" +fi + +log_info "Installing systemd service..." +cat > /etc/systemd/system/galene.service </dev/null; then + useradd --system --no-create-home --shell /usr/sbin/nologin minio-user +fi + +log_info "Creating data directory: ${MINIO_VOLUMES}..." +mkdir -p "${MINIO_VOLUMES}" +chown minio-user:minio-user "${MINIO_VOLUMES}" + +log_info "Writing /etc/default/minio..." +cat > /etc/default/minio < /etc/systemd/system/minio.service <<'EOF' +[Unit] +Description=MinIO +Documentation=https://min.io/docs/minio/linux/index.html +Wants=network-online.target +After=network-online.target +AssertFileIsExecutable=/usr/local/bin/minio + +[Service] +WorkingDirectory=/usr/local +User=minio-user +Group=minio-user +EnvironmentFile=/etc/default/minio +ExecStartPre=/bin/bash -c 'if [ -z "${MINIO_VOLUMES}" ]; then echo "MINIO_VOLUMES not set"; exit 1; fi' +ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES +Restart=always +LimitNOFILE=65536 +TasksMax=infinity +TimeoutStopSec=infinity +SendSIGKILL=no + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reload +systemctl enable --now minio + +log_info "MinIO deployed" +echo " API: http://localhost:9000" +echo " Console: http://localhost:9001" +echo "" +echo "Remaining manual steps:" +echo " 1. Configure nginx reverse proxy (see infra/services/nginx/sites/)" +echo " 2. Get TLS cert: certbot --nginx -d ${MINIO_SERVER_URL#https://}" diff --git a/services/sing-box/client/.env.example b/services/sing-box/client/.env.example new file mode 100644 index 0000000..a73dab5 --- /dev/null +++ b/services/sing-box/client/.env.example @@ -0,0 +1,3 @@ +# role: homeserver +# description: sing-box transparent proxy client connecting to sing-box server +SING_BOX_VERSION=1.11.0 diff --git a/services/sing-box/client/deploy.sh b/services/sing-box/client/deploy.sh new file mode 100755 index 0000000..1bcf53f --- /dev/null +++ b/services/sing-box/client/deploy.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# Deploys sing-box as a transparent proxy client (home machine / LAN gateway). +# +# Usage: INFRA_DIR=/path/to/infra/services/sing-box/client ./deploy.sh + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../../../bin/lib/common.sh" + +ENV_FILE="${INFRA_DIR:-.}/.env" +[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; } +set -a; source "$ENV_FILE"; set +a + +require_env SING_BOX_VERSION + +INSTALL_DIR="/etc/sing-box" +BIN="$INSTALL_DIR/sing-box" + +if [[ -x "$BIN" ]]; then + log_info "sing-box already at $BIN, skipping download" +else + log_info "Downloading sing-box ${SING_BOX_VERSION}..." + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) log_error "Unsupported arch: $ARCH"; exit 1 ;; + esac + URL="https://github.com/SagerNet/sing-box/releases/download/v${SING_BOX_VERSION}/sing-box-${SING_BOX_VERSION}-linux-${ARCH}.tar.gz" + TMP="$(mktemp -d)" + wget -qO "$TMP/sing-box.tar.gz" "$URL" + tar -xf "$TMP/sing-box.tar.gz" -C "$TMP" + mkdir -p "$INSTALL_DIR" + install -m 755 "$TMP/sing-box-${SING_BOX_VERSION}-linux-${ARCH}/sing-box" "$BIN" + rm -rf "$TMP" +fi + +log_info "Deploying client config..." +CONFIG_SRC="${INFRA_DIR}/sing_box_client.json" +[ -f "$CONFIG_SRC" ] || { log_error "sing_box_client.json not found in INFRA_DIR"; exit 1; } +cp "$CONFIG_SRC" "$INSTALL_DIR/config.json" + +log_info "Installing systemd service..." +cat > /etc/systemd/system/sing-box-client.service <<'EOF' +[Unit] +Description=sing-box Client +After=network.target nss-lookup.target + +[Service] +User=root +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +ExecStart=/etc/sing-box/sing-box run -c /etc/sing-box/config.json +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reload +systemctl enable --now sing-box-client + +log_info "sing-box client deployed" diff --git a/services/sing-box/server/.env.example b/services/sing-box/server/.env.example new file mode 100644 index 0000000..7b5229d --- /dev/null +++ b/services/sing-box/server/.env.example @@ -0,0 +1,3 @@ +# role: vps +# description: sing-box proxy server (VLESS/Reality, VMess/WS, Hysteria2 via sing-box-yg) +SING_BOX_VERSION=1.11.0 diff --git a/services/sing-box/server/deploy.sh b/services/sing-box/server/deploy.sh new file mode 100755 index 0000000..61b85b0 --- /dev/null +++ b/services/sing-box/server/deploy.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Deploys sing-box proxy server on VPS. +# +# Config generated by https://github.com/yonggekkk/sing-box-yg — run that +# script once interactively to create /etc/s-box/sb.json, certs, and keys. +# Then commit the generated files into infra for future re-deployment. +# +# Usage: INFRA_DIR=/path/to/infra/services/sing-box/server ./deploy.sh + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../../../bin/lib/common.sh" + +ENV_FILE="${INFRA_DIR:-.}/.env" +[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; } +set -a; source "$ENV_FILE"; set +a + +require_env SING_BOX_VERSION + +INSTALL_DIR="/etc/s-box" +BIN="$INSTALL_DIR/sing-box" + +if [[ -x "$BIN" ]]; then + log_info "sing-box already at $BIN, skipping download" +else + log_info "Downloading sing-box ${SING_BOX_VERSION}..." + ARCH="$(uname -m)" + case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) log_error "Unsupported arch: $ARCH"; exit 1 ;; + esac + URL="https://github.com/SagerNet/sing-box/releases/download/v${SING_BOX_VERSION}/sing-box-${SING_BOX_VERSION}-linux-${ARCH}.tar.gz" + TMP="$(mktemp -d)" + wget -qO "$TMP/sing-box.tar.gz" "$URL" + tar -xf "$TMP/sing-box.tar.gz" -C "$TMP" + mkdir -p "$INSTALL_DIR" + install -m 755 "$TMP/sing-box-${SING_BOX_VERSION}-linux-${ARCH}/sing-box" "$BIN" + rm -rf "$TMP" +fi + +log_info "Deploying config from INFRA_DIR..." +for f in sb.json cert.pem private.key public.key; do + src="${INFRA_DIR}/$f" + if [[ -f "$src" ]]; then + cp "$src" "$INSTALL_DIR/$f" + log_info " copied $f" + fi +done + +log_info "Installing systemd service..." +cat > /etc/systemd/system/sing-box.service <<'EOF' +[Unit] +After=network.target nss-lookup.target + +[Service] +User=root +WorkingDirectory=/root +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +ExecStart=/etc/s-box/sing-box run -c /etc/s-box/sb.json +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=10 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target +EOF + +systemctl daemon-reload +systemctl enable --now sing-box + +log_info "sing-box server deployed" +echo "" +echo "Note: initial config must be generated via sing-box-yg:" +echo " bash <(curl -Ls https://raw.githubusercontent.com/yonggekkk/sing-box-yg/main/sb.sh)" diff --git a/services/tnt/.env.example b/services/tnt/.env.example new file mode 100644 index 0000000..f1f972c --- /dev/null +++ b/services/tnt/.env.example @@ -0,0 +1,7 @@ +# role: any +# description: TNT terminal chat server (SSH-based, github.com/m1ngsama/TNT) +TNT_PORT=2222 +TNT_ACCESS_TOKEN= +TNT_BIND_ADDR=0.0.0.0 +TNT_MAX_CONNECTIONS=50 +TNT_MAX_CONN_PER_IP=3 diff --git a/services/tnt/deploy.sh b/services/tnt/deploy.sh new file mode 100755 index 0000000..a30be0f --- /dev/null +++ b/services/tnt/deploy.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# Deploys TNT terminal chat server. +# https://github.com/m1ngsama/TNT +# +# Usage: INFRA_DIR=/path/to/infra/services/tnt ./deploy.sh + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../../bin/lib/common.sh" + +ENV_FILE="${INFRA_DIR:-.}/.env" +[ -f "$ENV_FILE" ] || { log_error "No .env found at $ENV_FILE"; exit 1; } +set -a; source "$ENV_FILE"; set +a + +require_env TNT_PORT TNT_ACCESS_TOKEN + +BIN="/usr/local/bin/tnt" +DATA_DIR="/var/lib/tnt" + +if [[ -x "$BIN" ]]; then + log_info "tnt already at $BIN, skipping download" +else + log_info "Installing tnt via official installer..." + curl -sSL https://raw.githubusercontent.com/m1ngsama/TNT/main/install.sh | sh +fi + +log_info "Setting up data directory..." +mkdir -p "$DATA_DIR" + +# Create unprivileged user if not exists +if ! id tnt &>/dev/null; then + useradd --system --no-create-home --shell /usr/sbin/nologin tnt +fi +chown tnt:tnt "$DATA_DIR" + +log_info "Installing systemd service..." +cat > /etc/systemd/system/tnt.service <"