fix: harden node upgrades and prepare 1.9.0-alpha

This commit is contained in:
archipelago
2026-10-05 12:43:49 -04:00
parent 138a541d01
commit daac47cac4
129 changed files with 9910 additions and 794 deletions
+55 -54
View File
@@ -48,6 +48,13 @@ SCRIPT_DIR_FBC="$(cd "$(dirname "$0")" && pwd)"
# as root (rootful podman), the backend can't see them at all.
DOCKER="runuser -u archipelago -- env XDG_RUNTIME_DIR=/run/user/$(id -u archipelago) podman"
prepare_filebrowser_credentials() {
install -d -o archipelago -g archipelago -m 700 /var/lib/archipelago/secrets/filebrowser
chown 100000:100000 /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-data
runuser -u archipelago -- env XDG_RUNTIME_DIR="/run/user/$(id -u archipelago)" \
python3 "$SCRIPT_DIR_FBC/filebrowser-credentials.py" --image "$FILEBROWSER_IMAGE"
}
PORT_ALLOC_FILE="/var/lib/archipelago/port-allocations.env"
mkdir -p /var/lib/archipelago 2>/dev/null || true
[ -f "$PORT_ALLOC_FILE" ] && . "$PORT_ALLOC_FILE"
@@ -142,19 +149,14 @@ if [ -f "$UNBUNDLED_MARKER" ]; then
return 1
}
# Create FileBrowser (noauth — behind Archipelago login)
if ! $DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q filebrowser; then
log "Creating FileBrowser (noauth)..."
# Create FileBrowser (unique private Cloud credentials)
if ! $DOCKER container exists filebrowser; then
log "Creating FileBrowser (secure Cloud login)..."
mkdir -p /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-data
mkdir -p /var/lib/archipelago/filebrowser/{Documents,Photos,Music,Videos,Downloads}
chown -R 100000:100000 /var/lib/archipelago/filebrowser
chown -R 100000:100000 /var/lib/archipelago/filebrowser-data
# Write config with database on persistent volume
cat > /var/lib/archipelago/filebrowser-data/.filebrowser.json <<'FBEOF'
{"port":80,"baseURL":"","address":"0.0.0.0","database":"/data/filebrowser.db","root":"/srv","log":"stdout"}
FBEOF
chown 100000:100000 /var/lib/archipelago/filebrowser-data/.filebrowser.json
pull_with_fallback "${FILEBROWSER_IMAGE}"
chown 100000:100000 /var/lib/archipelago/filebrowser
chown 100000:100000 /var/lib/archipelago/filebrowser-data
pull_with_fallback "${FILEBROWSER_IMAGE}" || exit 1
prepare_filebrowser_credentials || { log "ERROR: secure File Browser setup failed"; exit 1; }
$DOCKER run -d --name filebrowser --restart unless-stopped \
--network archy-net \
--cap-drop=ALL --cap-add=DAC_OVERRIDE --cap-add=NET_BIND_SERVICE \
@@ -162,21 +164,13 @@ FBEOF
--health-cmd='wget -q --spider http://localhost:80/health || exit 1' \
--health-interval=30s --health-timeout=5s --health-retries=3 \
--memory=256m \
-p 8083:80 \
-p 127.0.0.1:8083:80 \
-v /var/lib/archipelago/filebrowser:/srv \
-v /var/lib/archipelago/filebrowser-data:/data \
${FILEBROWSER_IMAGE} \
--config /data/.filebrowser.json 2>>"$LOG" && \
log " FileBrowser created" || log " WARNING: FileBrowser creation failed"
# Set noauth after first start
sleep 3
$DOCKER exec filebrowser /filebrowser config set --auth.method=noauth --database /data/filebrowser.db 2>>"$LOG" || true
$DOCKER exec filebrowser /filebrowser users add admin admin --perm.admin --database /data/filebrowser.db 2>>"$LOG" || true
$DOCKER restart filebrowser 2>>"$LOG" || true
# Create filebrowser password for backend token flow
mkdir -p /var/lib/archipelago/secrets/filebrowser
echo -n "admin" > /var/lib/archipelago/secrets/filebrowser/password
chown -R 1000:1000 /var/lib/archipelago/secrets
fi
# Create Fedimint Client (fmcd) alongside FileBrowser so ecash / networking
@@ -537,7 +531,7 @@ for dir in lnd electrumx btcpay nbxplorer jellyfin vaultwarden \
done
# Nginx Proxy Manager runs as root in the rootless user namespace, which maps to
# the archipelago user on host bind mounts. Keep certbot's webroot writable.
[ -d /var/lib/archipelago/nginx-proxy-manager ] && chown -R 1000:1000 /var/lib/archipelago/nginx-proxy-manager 2>/dev/null
# Existing NPM ownership is preserved; new storage is initialized below.
# Bitcoin Knots: container UID 101 → host UID 100101
[ -d /var/lib/archipelago/bitcoin ] && chown -R 100101:100101 /var/lib/archipelago/bitcoin 2>/dev/null
# Postgres: container UID 70 → host UID 100070
@@ -1249,48 +1243,55 @@ fi
track_container "searxng"
# OnlyOffice removed — incompatible with rootless Podman (internal postgres/rabbitmq)
# CryptPad is the replacement (single Node.js process, e2e encrypted)
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q filebrowser; then
log "Creating File Browser (noauth — behind Archipelago login)..."
if ! $DOCKER container exists filebrowser; then
log "Creating File Browser (secure Cloud login)..."
mkdir -p /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-data
mkdir -p /var/lib/archipelago/filebrowser/{Documents,Photos,Music,Downloads,Builds}
# Config with noauth + database on persistent volume (survives container recreation)
cat > /var/lib/archipelago/filebrowser-data/.filebrowser.json << 'FBEOF'
{"port":80,"baseURL":"","address":"0.0.0.0","database":"/data/filebrowser.db","root":"/srv","log":"stdout"}
FBEOF
$DOCKER image exists "$FILEBROWSER_IMAGE" || $DOCKER pull "$FILEBROWSER_IMAGE" || exit 1
prepare_filebrowser_credentials || { log "ERROR: secure File Browser setup failed"; exit 1; }
$DOCKER run -d --name filebrowser --restart unless-stopped \
--health-cmd="wget -q --spider http://localhost:80/health || exit 1" --health-interval=120s --health-timeout=5s --health-retries=3 \
--memory=$(mem_limit filebrowser) \
--cap-drop ALL --security-opt no-new-privileges:true \
--cap-drop ALL --cap-add=DAC_OVERRIDE --cap-add=NET_BIND_SERVICE --security-opt no-new-privileges:true \
--tmpfs=/tmp:rw,noexec,nosuid,size=256m --tmpfs=/run:rw,noexec,nosuid,size=64m \
-p 8083:80 \
-p 127.0.0.1:8083:80 \
-v /var/lib/archipelago/filebrowser:/srv \
-v /var/lib/archipelago/filebrowser-data:/data \
"$FILEBROWSER_IMAGE" \
--config /data/.filebrowser.json 2>>"$LOG" || true
# Set noauth after first start (initializes database on volume)
sleep 3
$DOCKER exec filebrowser /filebrowser config set --auth.method=noauth --database /data/filebrowser.db 2>>"$LOG" || true
$DOCKER exec filebrowser /filebrowser users add admin admin --perm.admin --database /data/filebrowser.db 2>>"$LOG" || true
$DOCKER restart filebrowser 2>>"$LOG" || true
fi
track_container "filebrowser"
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q nginx-proxy-manager; then
log "Creating Nginx Proxy Manager..."
mkdir -p /var/lib/archipelago/nginx-proxy-manager/data /var/lib/archipelago/nginx-proxy-manager/letsencrypt
mkdir -p /var/lib/archipelago/nginx-proxy-manager/data/letsencrypt-acme-challenge/.well-known/acme-challenge
chown -R 1000:1000 /var/lib/archipelago/nginx-proxy-manager 2>/dev/null || true
NPM_ADMIN_PORT=$(alloc_port nginx-proxy-manager 8081)
NPM_HTTP_PORT=$(alloc_port nginx-proxy-manager-http 8084)
NPM_HTTPS_PORT=$(alloc_port nginx-proxy-manager-https 8444)
$DOCKER run -d --name nginx-proxy-manager --restart unless-stopped \
--health-cmd="curl -sf http://localhost:81/ || exit 1" --health-interval=120s --health-timeout=5s --health-retries=3 \
--memory=$(mem_limit nginx-proxy-manager) \
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE --cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges:true \
-p ${NPM_ADMIN_PORT}:81 -p ${NPM_HTTP_PORT}:80 -p ${NPM_HTTPS_PORT}:443 \
-v /var/lib/archipelago/nginx-proxy-manager/data:/data \
-v /var/lib/archipelago/nginx-proxy-manager/letsencrypt:/etc/letsencrypt \
"${NPM_IMAGE}" 2>>"$LOG" || true
# Resolve existing storage before creating anything; never revive a stopped
# container through a duplicate run or recursively rewrite its ownership.
if ! $DOCKER container exists nginx-proxy-manager; then
if NPM_LAYOUT=$(python3 "$SCRIPT_DIR_FBC/npm-public-bridge.py" --resolve); then
NPM_DATA_DIR=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["data"])' <<<"$NPM_LAYOUT")
NPM_CERT_DIR=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["certificates"])' <<<"$NPM_LAYOUT")
if [ -n "$NPM_DATA_DIR" ] && [ -n "$NPM_CERT_DIR" ]; then
for npm_dir in "$NPM_DATA_DIR" "$NPM_CERT_DIR" "$NPM_DATA_DIR/letsencrypt-acme-challenge/.well-known/acme-challenge"; do
if [ ! -d "$npm_dir" ]; then
install -d -o archipelago -g archipelago "$npm_dir" || exit 1
fi
done
NPM_ADMIN_PORT=$(alloc_port nginx-proxy-manager 8081)
python3 "$SCRIPT_DIR_FBC/npm-public-bridge.py" --resolve --prepare-realip >/dev/null || exit 1
NPM_HTTP_PORT=$(alloc_port nginx-proxy-manager-http 8088)
NPM_HTTPS_PORT=$(alloc_port nginx-proxy-manager-https 8444)
if ! $DOCKER run -d --name nginx-proxy-manager --restart unless-stopped \
--network slirp4netns:allow_host_loopback=true,cidr=169.254.1.0/24 \
--health-cmd="curl -sf http://127.0.0.1:81/api/ || exit 1" --health-interval=120s --health-timeout=5s --health-retries=3 \
--memory=$(mem_limit nginx-proxy-manager) \
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE --cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges:true \
-p "127.0.0.1:${NPM_ADMIN_PORT}:81" -p "127.0.0.1:${NPM_HTTP_PORT}:80" -p "127.0.0.1:${NPM_HTTPS_PORT}:443" \
-v "$NPM_DATA_DIR:/data" -v "$NPM_CERT_DIR:/etc/letsencrypt" \
"${NPM_IMAGE}" 2>>"$LOG"; then
log "ERROR: NPM creation failed; existing persistent state preserved"
fi
fi
else
log "ERROR: NPM storage resolution failed; no directories or containers changed"
fi
fi
track_container "nginx-proxy-manager"
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q portainer; then