feat: rootless podman, session hardening, boot stability, sidebar fix
Rootless podman migration (TASK-11): - Remove sudo from all podman calls in PodmanClient + 8 backend files - Remove sudo from all podman/docker calls in deploy script - Restore full systemd security hardening: NoNewPrivileges, RestrictAddressFamilies, MemoryDenyWriteExecute, RestrictRealtime, RestrictNamespaces, RestrictSUIDSGID, SystemCallFilter, ProtectSystem=strict - Enable loginctl linger for rootless container persistence - Remove Ollama from auto-deploy (marketplace-only) Session & auth hardening: - Increase MAX_CONCURRENT_SESSIONS 20→50 (prevents eviction storms) - Debounced 401 redirect in rpc-client.ts (prevents redirect storms) Boot stability: - optimize-debian.sh: adds chrony, swap, removes policy-rc.d - deploy script: pre-restart chrony + swap setup - ISO build: chrony package, swap file creation - BootScreen: no longer clears localStorage (prevents splash replay) - RootRedirect: sole owner of localStorage clearing on server ready UI fixes: - Sidebar opacity default changed from 0→visible (fixes missing sidebar after page-persistence login without entrance animation) - Console.log/error wrapped in import.meta.env.DEV guards - Remove unused route import from RootRedirect Beta tracking: - CLAUDE.md: beta freeze protocol added - MASTER_PLAN.md: TASK-11, TASK-17, phase structure - BETA-PROGRESS.md: initial tracking doc - Tagged v1.2.0-alpha.1 as pre-rootless baseline Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -340,13 +340,13 @@ if [ "$BOTH" = true ]; then
|
||||
fi
|
||||
# FileBrowser fix
|
||||
DOCKER=podman; command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
FB=$(sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -x filebrowser || true)
|
||||
FB=$($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -x filebrowser || true)
|
||||
if [ -n "$FB" ]; then
|
||||
RO=$(sudo $DOCKER inspect filebrowser 2>/dev/null | grep -oP "\"ReadonlyRootfs\":\s*\K\w+" || echo "false")
|
||||
RO=$($DOCKER inspect filebrowser 2>/dev/null | grep -oP "\"ReadonlyRootfs\":\s*\K\w+" || echo "false")
|
||||
if [ "$RO" = "true" ]; then
|
||||
sudo $DOCKER stop filebrowser 2>/dev/null; sudo $DOCKER rm filebrowser 2>/dev/null
|
||||
$DOCKER stop filebrowser 2>/dev/null; $DOCKER rm filebrowser 2>/dev/null
|
||||
sudo mkdir -p /var/lib/archipelago/filebrowser
|
||||
sudo $DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>/dev/null
|
||||
$DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
' 2>/dev/null || true
|
||||
@@ -677,15 +677,15 @@ PYEOF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
FB_EXISTS=$(sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -x filebrowser || true)
|
||||
FB_EXISTS=$($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -x filebrowser || true)
|
||||
if [ -n "$FB_EXISTS" ]; then
|
||||
RO=$(sudo $DOCKER inspect filebrowser 2>/dev/null | grep -oP "\"ReadonlyRootfs\":\s*\K\w+" || echo "false")
|
||||
RO=$($DOCKER inspect filebrowser 2>/dev/null | grep -oP "\"ReadonlyRootfs\":\s*\K\w+" || echo "false")
|
||||
if [ "$RO" = "true" ]; then
|
||||
echo " FileBrowser has read-only root — recreating..."
|
||||
sudo $DOCKER stop filebrowser 2>/dev/null
|
||||
sudo $DOCKER rm filebrowser 2>/dev/null
|
||||
$DOCKER stop filebrowser 2>/dev/null
|
||||
$DOCKER rm filebrowser 2>/dev/null
|
||||
sudo mkdir -p /var/lib/archipelago/filebrowser
|
||||
sudo $DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>&1 | tail -1
|
||||
$DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>&1 | tail -1
|
||||
echo " FileBrowser recreated"
|
||||
else
|
||||
echo " FileBrowser OK"
|
||||
@@ -693,7 +693,7 @@ PYEOF
|
||||
else
|
||||
echo " Creating FileBrowser..."
|
||||
sudo mkdir -p /var/lib/archipelago/filebrowser
|
||||
sudo $DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>&1 | tail -1
|
||||
$DOCKER run -d --name filebrowser --restart=always -p 8083:80 -v /var/lib/archipelago/filebrowser:/srv docker.io/filebrowser/filebrowser:v2.27.0 2>&1 | tail -1
|
||||
echo " FileBrowser created"
|
||||
fi
|
||||
' 2>/dev/null || true
|
||||
@@ -713,6 +713,30 @@ PYEOF
|
||||
}
|
||||
MANIFEST_EOF
|
||||
|
||||
# Ensure NTP and swap are configured (prevents OOM kills and clock drift)
|
||||
progress "Ensuring NTP + swap"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
# NTP via chrony
|
||||
if ! dpkg -l chrony >/dev/null 2>&1; then
|
||||
sudo rm -f /usr/sbin/policy-rc.d
|
||||
sudo apt-get update -qq && sudo apt-get install -y chrony 2>/dev/null
|
||||
fi
|
||||
sudo systemctl enable chrony 2>/dev/null
|
||||
sudo systemctl start chrony 2>/dev/null
|
||||
sudo timedatectl set-ntp true 2>/dev/null
|
||||
# Swap
|
||||
if [ ! -f /swapfile ]; then
|
||||
TOTAL_KB=$(grep MemTotal /proc/meminfo | awk "{print \$2}")
|
||||
SZ=$((TOTAL_KB / 1024 / 1024))
|
||||
[ "$SZ" -gt 8 ] && SZ=8
|
||||
[ "$SZ" -lt 2 ] && SZ=2
|
||||
sudo fallocate -l ${SZ}G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
|
||||
grep -q "/swapfile" /etc/fstab || echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab
|
||||
echo " Created ${SZ}G swap"
|
||||
fi
|
||||
sudo swapon /swapfile 2>/dev/null || true
|
||||
' 2>&1 | tail -5 | sed 's/^/ /' || true
|
||||
|
||||
# Restart services
|
||||
progress "Restarting services"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo systemctl start archipelago && sudo systemctl restart nginx"
|
||||
@@ -726,44 +750,44 @@ MANIFEST_EOF
|
||||
else
|
||||
# Rebuild and recreate LND UI container (port 8081 so Launch from UI and http://host:8081 both work)
|
||||
progress "Rebuilding LND UI"
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/lnd-ui && (command -v podman >/dev/null 2>&1 && sudo podman build --no-cache -t lnd-ui:latest . || sudo docker build --no-cache -t lnd-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/lnd-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t lnd-ui:latest . || docker build --no-cache -t lnd-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
echo " Recreating LND UI container (port 8081)..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
for c in $(sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i lnd-ui); do
|
||||
[ -n "$c" ] && sudo $DOCKER stop "$c" 2>/dev/null; sudo $DOCKER rm -f "$c" 2>/dev/null
|
||||
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i lnd-ui); do
|
||||
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
|
||||
done
|
||||
sudo $DOCKER run -d --name archy-lnd-ui -p 8081:80 --restart unless-stopped lnd-ui:latest
|
||||
$DOCKER run -d --name archy-lnd-ui -p 8081:80 --restart unless-stopped lnd-ui:latest
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
fi
|
||||
|
||||
# Rebuild and recreate ElectrumX UI container (port 50002)
|
||||
progress "Rebuilding ElectrumX UI"
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/electrs-ui && (command -v podman >/dev/null 2>&1 && sudo podman build --no-cache -t electrs-ui:latest . || sudo docker build --no-cache -t electrs-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/electrs-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t electrs-ui:latest . || docker build --no-cache -t electrs-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
echo " Recreating ElectrumX UI container (port 50002, host network)..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
for c in $(sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i electrs-ui); do
|
||||
[ -n "$c" ] && sudo $DOCKER stop "$c" 2>/dev/null; sudo $DOCKER rm -f "$c" 2>/dev/null
|
||||
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i electrs-ui); do
|
||||
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
|
||||
done
|
||||
sudo $DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped electrs-ui:latest
|
||||
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped electrs-ui:latest
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
fi
|
||||
|
||||
# Rebuild and recreate Bitcoin UI container (host network, port 8334 in nginx.conf)
|
||||
# Host network required: bitcoin-ui proxies Bitcoin RPC at 127.0.0.1:8332
|
||||
progress "Rebuilding Bitcoin UI"
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/bitcoin-ui && (command -v podman >/dev/null 2>&1 && sudo podman build --no-cache -t bitcoin-ui:latest . || sudo docker build --no-cache -t bitcoin-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/bitcoin-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t bitcoin-ui:latest . || docker build --no-cache -t bitcoin-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
|
||||
echo " Recreating Bitcoin UI container (port 8334, host network)..."
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
for c in $(sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i bitcoin-ui); do
|
||||
[ -n "$c" ] && sudo $DOCKER stop "$c" 2>/dev/null; sudo $DOCKER rm -f "$c" 2>/dev/null
|
||||
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i bitcoin-ui); do
|
||||
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
|
||||
done
|
||||
sudo $DOCKER run -d --name archy-bitcoin-ui --network host --restart unless-stopped bitcoin-ui:latest
|
||||
$DOCKER run -d --name archy-bitcoin-ui --network host --restart unless-stopped bitcoin-ui:latest
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
fi
|
||||
|
||||
@@ -825,9 +849,9 @@ MANIFEST_EOF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
sudo \$DOCKER network create archy-net 2>/dev/null || true
|
||||
\$DOCKER network create archy-net 2>/dev/null || true
|
||||
NET_OPT='--network archy-net'
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qE 'bitcoin-knots|archy-bitcoin-knots'; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qE 'bitcoin-knots|archy-bitcoin-knots'; then
|
||||
echo ' Creating Bitcoin Knots (mainnet, archipelago RPC)...'
|
||||
sudo mkdir -p /var/lib/archipelago/bitcoin
|
||||
# Demo mode: prune=550 saves ~194GB disk, but disables txindex (incompatible with electrumx)
|
||||
@@ -838,7 +862,7 @@ MANIFEST_EOF
|
||||
BTC_EXTRA_ARGS="-txindex=1"
|
||||
BTC_DBCACHE=4096
|
||||
fi
|
||||
sudo \$DOCKER run -d --name bitcoin-knots --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name bitcoin-knots --restart unless-stopped \$NET_OPT \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8332:8332 -p 8333:8333 \
|
||||
@@ -850,7 +874,7 @@ MANIFEST_EOF
|
||||
-dbcache=\$BTC_DBCACHE
|
||||
echo ' Bitcoin Knots started (sync may take hours)'
|
||||
else
|
||||
sudo \$DOCKER network connect archy-net bitcoin-knots 2>/dev/null || true
|
||||
\$DOCKER network connect archy-net bitcoin-knots 2>/dev/null || true
|
||||
fi
|
||||
" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
@@ -864,14 +888,14 @@ MANIFEST_EOF
|
||||
# Clean any duplicate/old mempool containers (user may have two versions)
|
||||
# EXCLUDE electrumx/mempool-electrs - indexing takes days, do not recreate on every deploy
|
||||
for c in mempool mempool-api mempool-web archy-mempool-api archy-mempool-web; do
|
||||
sudo \$DOCKER stop \$c 2>/dev/null
|
||||
sudo \$DOCKER rm -f \$c 2>/dev/null
|
||||
\$DOCKER stop \$c 2>/dev/null
|
||||
\$DOCKER rm -f \$c 2>/dev/null
|
||||
done
|
||||
# Create mysql-mempool if missing
|
||||
if ! sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qE 'mysql-mempool|archy-mempool-db'; then
|
||||
if ! \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qE 'mysql-mempool|archy-mempool-db'; then
|
||||
echo ' Creating mysql-mempool...'
|
||||
sudo mkdir -p /var/lib/archipelago/mysql-mempool
|
||||
sudo \$DOCKER run -d --name archy-mempool-db --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name archy-mempool-db --restart unless-stopped \$NET_OPT \
|
||||
-v /var/lib/archipelago/mysql-mempool:/var/lib/mysql \
|
||||
-e MYSQL_DATABASE=mempool \
|
||||
-e MYSQL_USER=mempool \
|
||||
@@ -880,25 +904,25 @@ MANIFEST_EOF
|
||||
docker.io/mariadb:10.11
|
||||
sleep 3
|
||||
fi
|
||||
MYSQL_CNT=\$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'mysql-mempool|archy-mempool-db' | head -1)
|
||||
MYSQL_CNT=\$(\$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'mysql-mempool|archy-mempool-db' | head -1)
|
||||
MYSQL_CNT=\${MYSQL_CNT:-archy-mempool-db}
|
||||
# Ensure DB is on archy-net so mempool-api can resolve it
|
||||
sudo \$DOCKER network connect archy-net \$MYSQL_CNT 2>/dev/null || true
|
||||
\$DOCKER network connect archy-net \$MYSQL_CNT 2>/dev/null || true
|
||||
# Stop and remove old mempool-electrs if present (replaced by electrumx)
|
||||
if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q mempool-electrs; then
|
||||
if \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q mempool-electrs; then
|
||||
echo ' Removing old mempool-electrs (replaced by ElectrumX)...'
|
||||
sudo \$DOCKER stop mempool-electrs 2>/dev/null
|
||||
sudo \$DOCKER rm -f mempool-electrs 2>/dev/null
|
||||
\$DOCKER stop mempool-electrs 2>/dev/null
|
||||
\$DOCKER rm -f mempool-electrs 2>/dev/null
|
||||
fi
|
||||
# Create electrumx ONLY if missing - do NOT recreate (indexing takes days)
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q electrumx; then
|
||||
if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q electrumx; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q electrumx; then
|
||||
if \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q electrumx; then
|
||||
echo ' Starting existing electrumx (preserving index)...'
|
||||
sudo \$DOCKER start electrumx 2>/dev/null || true
|
||||
\$DOCKER start electrumx 2>/dev/null || true
|
||||
else
|
||||
echo ' Creating electrumx (indexer - may take days to sync, do not recreate)...'
|
||||
sudo mkdir -p /var/lib/archipelago/electrumx
|
||||
sudo \$DOCKER run -d --name electrumx --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name electrumx --restart unless-stopped \$NET_OPT \
|
||||
-p 50001:50001 \
|
||||
-v /var/lib/archipelago/electrumx:/data \
|
||||
-e DAEMON_URL=http://$BITCOIN_RPC_USER:$BITCOIN_RPC_PASS@bitcoin-knots:8332/ \
|
||||
@@ -909,15 +933,15 @@ MANIFEST_EOF
|
||||
fi
|
||||
fi
|
||||
# Create/recreate mempool-api (backend on 8999) - required for mempool to work
|
||||
for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'mempool-api|archy-mempool-api'); do
|
||||
for c in \$(\$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'mempool-api|archy-mempool-api'); do
|
||||
echo ' Recreating mempool-api (backend)...'
|
||||
sudo \$DOCKER stop \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
\$DOCKER stop \"\$c\" 2>/dev/null
|
||||
\$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
done
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q mempool-api; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q mempool-api; then
|
||||
echo ' Creating mempool-api (backend)...'
|
||||
sudo mkdir -p /var/lib/archipelago/mempool
|
||||
sudo \$DOCKER run -d --name mempool-api --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name mempool-api --restart unless-stopped \$NET_OPT \
|
||||
-p 8999:8999 \
|
||||
-v /var/lib/archipelago/mempool:/data \
|
||||
-e MEMPOOL_BACKEND=electrum \
|
||||
@@ -936,15 +960,15 @@ MANIFEST_EOF
|
||||
docker.io/mempool/backend:v2.5.0
|
||||
fi
|
||||
# Recreate mempool frontend - handle both 'mempool' and 'mempool-web' (frontend was on wrong port 8999)
|
||||
for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E '^mempool\$|mempool-web|archy-mempool-web'); do
|
||||
for c in \$(\$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E '^mempool\$|mempool-web|archy-mempool-web'); do
|
||||
echo ' Recreating mempool frontend on 4080...'
|
||||
sudo \$DOCKER stop \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
\$DOCKER stop \"\$c\" 2>/dev/null
|
||||
\$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
break
|
||||
done
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q archy-mempool-web; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q archy-mempool-web; then
|
||||
echo ' Creating mempool frontend on 4080...'
|
||||
sudo \$DOCKER run -d --name archy-mempool-web --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name archy-mempool-web --restart unless-stopped \$NET_OPT \
|
||||
-p 4080:8080 \
|
||||
-e FRONTEND_HTTP_PORT=8080 \
|
||||
-e BACKEND_MAINNET_HTTP_HOST=mempool-api \
|
||||
@@ -959,15 +983,15 @@ MANIFEST_EOF
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
TARGET_IP='$TARGET_IP'
|
||||
sudo \$DOCKER network create archy-net 2>/dev/null || true
|
||||
\$DOCKER network create archy-net 2>/dev/null || true
|
||||
NET_OPT='--network archy-net'
|
||||
# Ensure bitcoin-knots is on archy-net for NBXplorer/BTCPay to reach it
|
||||
sudo \$DOCKER network connect archy-net bitcoin-knots 2>/dev/null || true
|
||||
\$DOCKER network connect archy-net bitcoin-knots 2>/dev/null || true
|
||||
# Create PostgreSQL for BTCPay if missing
|
||||
if ! sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qE 'archy-btcpay-db|postgres-btcpay'; then
|
||||
if ! \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qE 'archy-btcpay-db|postgres-btcpay'; then
|
||||
echo ' Creating archy-btcpay-db (PostgreSQL)...'
|
||||
sudo mkdir -p /var/lib/archipelago/postgres-btcpay
|
||||
sudo \$DOCKER run -d --name archy-btcpay-db --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name archy-btcpay-db --restart unless-stopped \$NET_OPT \
|
||||
-v /var/lib/archipelago/postgres-btcpay:/var/lib/postgresql/data \
|
||||
-e POSTGRES_DB=btcpay \
|
||||
-e POSTGRES_USER=btcpay \
|
||||
@@ -976,16 +1000,16 @@ MANIFEST_EOF
|
||||
sleep 3
|
||||
fi
|
||||
# Create NBXplorer database in PostgreSQL (NBXplorer needs its own DB)
|
||||
sudo \$DOCKER exec archy-btcpay-db psql -U postgres -tc \"SELECT 1 FROM pg_database WHERE datname='nbxplorer'\" 2>/dev/null | grep -q 1 || \
|
||||
sudo \$DOCKER exec -e PGPASSWORD=$BTCPAY_DB_PASS archy-btcpay-db psql -U postgres -c \"CREATE DATABASE nbxplorer;\" 2>/dev/null || true
|
||||
\$DOCKER exec archy-btcpay-db psql -U postgres -tc \"SELECT 1 FROM pg_database WHERE datname='nbxplorer'\" 2>/dev/null | grep -q 1 || \
|
||||
\$DOCKER exec -e PGPASSWORD=$BTCPAY_DB_PASS archy-btcpay-db psql -U postgres -c \"CREATE DATABASE nbxplorer;\" 2>/dev/null || true
|
||||
# Create NBXplorer (required by BTCPay - indexes blocks for payment tracking)
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then
|
||||
if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then
|
||||
sudo \$DOCKER start archy-nbxplorer 2>/dev/null || true
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then
|
||||
if \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then
|
||||
\$DOCKER start archy-nbxplorer 2>/dev/null || true
|
||||
else
|
||||
echo ' Creating archy-nbxplorer...'
|
||||
sudo mkdir -p /var/lib/archipelago/nbxplorer
|
||||
sudo \$DOCKER run -d --name archy-nbxplorer --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name archy-nbxplorer --restart unless-stopped \$NET_OPT \
|
||||
-p 32838:32838 \
|
||||
-v /var/lib/archipelago/nbxplorer:/data \
|
||||
-e NBXPLORER_DATADIR=/data \
|
||||
@@ -1002,16 +1026,16 @@ MANIFEST_EOF
|
||||
fi
|
||||
# Recreate btcpay-server with PostgreSQL, NBXplorer URL, and Bitcoin RPC
|
||||
for c in btcpay-server archy-btcpay; do
|
||||
if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx \"\$c\"; then
|
||||
if \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx \"\$c\"; then
|
||||
echo ' Recreating btcpay-server with NBXplorer...'
|
||||
sudo \$DOCKER stop \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
\$DOCKER stop \"\$c\" 2>/dev/null
|
||||
\$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
fi
|
||||
done
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q btcpay-server; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q btcpay-server; then
|
||||
echo ' Creating btcpay-server on 23000...'
|
||||
sudo mkdir -p /var/lib/archipelago/btcpay
|
||||
sudo \$DOCKER run -d --name btcpay-server --restart unless-stopped \$NET_OPT \
|
||||
\$DOCKER run -d --name btcpay-server --restart unless-stopped \$NET_OPT \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 23000:49392 \
|
||||
@@ -1035,30 +1059,30 @@ MANIFEST_EOF
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
# Remove old single-container 'immich' if present (wrong port mapping, conflicts with immich_server)
|
||||
if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx immich; then
|
||||
if \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx immich; then
|
||||
echo ' Removing old immich container (use immich_server)...'
|
||||
sudo \$DOCKER stop immich 2>/dev/null
|
||||
sudo \$DOCKER rm -f immich 2>/dev/null
|
||||
sudo \$DOCKER start immich_server 2>/dev/null || true
|
||||
\$DOCKER stop immich 2>/dev/null
|
||||
\$DOCKER rm -f immich 2>/dev/null
|
||||
\$DOCKER start immich_server 2>/dev/null || true
|
||||
fi
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_server; then
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_server; then
|
||||
echo ' Creating Immich stack...'
|
||||
sudo mkdir -p /var/lib/archipelago/immich /var/lib/archipelago/immich-db
|
||||
sudo \$DOCKER network create immich-net 2>/dev/null || true
|
||||
if ! sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q immich_postgres; then
|
||||
sudo \$DOCKER run -d --name immich_postgres --restart unless-stopped --network immich-net \
|
||||
\$DOCKER network create immich-net 2>/dev/null || true
|
||||
if ! \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q immich_postgres; then
|
||||
\$DOCKER run -d --name immich_postgres --restart unless-stopped --network immich-net \
|
||||
-v /var/lib/archipelago/immich-db:/var/lib/postgresql/data \
|
||||
-e POSTGRES_PASSWORD=$IMMICH_DB_PASS -e POSTGRES_USER=postgres -e POSTGRES_DB=immich \
|
||||
ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 2>/dev/null || true
|
||||
sleep 5
|
||||
fi
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_redis; then
|
||||
sudo \$DOCKER run -d --name immich_redis --restart unless-stopped --network immich-net \
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_redis; then
|
||||
\$DOCKER run -d --name immich_redis --restart unless-stopped --network immich-net \
|
||||
docker.io/valkey/valkey:7-alpine 2>/dev/null || true
|
||||
sleep 2
|
||||
fi
|
||||
if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_server; then
|
||||
sudo \$DOCKER run -d --name immich_server --restart unless-stopped --network immich-net \
|
||||
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q immich_server; then
|
||||
\$DOCKER run -d --name immich_server --restart unless-stopped --network immich-net \
|
||||
-p 2283:2283 -v /var/lib/archipelago/immich:/usr/src/app/upload \
|
||||
-e DB_HOSTNAME=immich_postgres -e DB_USERNAME=postgres -e DB_PASSWORD=$IMMICH_DB_PASS \
|
||||
-e DB_DATABASE_NAME=immich -e REDIS_HOSTNAME=immich_redis \
|
||||
@@ -1125,9 +1149,9 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
'
|
||||
|
||||
# Remove any old Tor container (system Tor is preferred)
|
||||
for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'archy-tor|^tor\$'); do
|
||||
sudo \$DOCKER stop \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
for c in \$(\$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'archy-tor|^tor\$'); do
|
||||
\$DOCKER stop \"\$c\" 2>/dev/null
|
||||
\$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
done
|
||||
|
||||
# Use system Tor (preferred — no AppArmor issues with default paths)
|
||||
@@ -1174,11 +1198,11 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
($TIMEOUT_CMD ssh $SSH_OPTS "$TARGET_HOST" "
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E '^fedimint\$'); do
|
||||
for c in \$(\$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E '^fedimint\$'); do
|
||||
echo ' Recreating fedimint with FM_API_URL...'
|
||||
sudo \$DOCKER stop \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
sudo \$DOCKER run -d --name fedimint --restart unless-stopped \
|
||||
\$DOCKER stop \"\$c\" 2>/dev/null
|
||||
\$DOCKER rm -f \"\$c\" 2>/dev/null
|
||||
\$DOCKER run -d --name fedimint --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8173:8173 -p 8174:8174 -p 8175:8175 \
|
||||
@@ -1199,15 +1223,15 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
|
||||
# Ensure Fedimint Gateway companion container
|
||||
# Auto-detect LND: if running with credentials, use lnd mode; otherwise use ldk (built-in)
|
||||
sudo \$DOCKER rm -f fedimint-gateway 2>/dev/null || true
|
||||
\$DOCKER rm -f fedimint-gateway 2>/dev/null || true
|
||||
echo ' Creating fedimint-gateway...'
|
||||
sudo mkdir -p /var/lib/archipelago/fedimint-gateway
|
||||
LND_CERT=/var/lib/archipelago/lnd/tls.cert
|
||||
LND_MACAROON=/var/lib/archipelago/lnd/data/chain/bitcoin/mainnet/admin.macaroon
|
||||
GW_COMMON=\"-p 8176:8176 -v /var/lib/archipelago/fedimint-gateway:/data docker.io/fedimint/gatewayd:v0.10.0 gatewayd --data-dir /data --listen 0.0.0.0:8176 --bcrypt-password-hash '$FEDI_HASH' --network bitcoin --bitcoind-url http://$TARGET_IP:8332 --bitcoind-username $BITCOIN_RPC_USER --bitcoind-password $BITCOIN_RPC_PASS\"
|
||||
if sudo \$DOCKER ps --format '{{.Names}}' | grep -q '^lnd\$' && sudo test -f \$LND_CERT && sudo test -f \$LND_MACAROON; then
|
||||
if \$DOCKER ps --format '{{.Names}}' | grep -q '^lnd\$' && sudo test -f \$LND_CERT && sudo test -f \$LND_MACAROON; then
|
||||
echo ' LND detected — using lnd mode'
|
||||
sudo \$DOCKER run -d --name fedimint-gateway --restart unless-stopped \
|
||||
\$DOCKER run -d --name fedimint-gateway --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8176:8176 \
|
||||
@@ -1222,7 +1246,7 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
lnd --lnd-rpc-host $TARGET_IP:10009 --lnd-tls-cert /lnd/tls.cert --lnd-macaroon /lnd/admin.macaroon
|
||||
else
|
||||
echo ' No LND found — using ldk (built-in Lightning)'
|
||||
sudo \$DOCKER run -d --name fedimint-gateway --restart unless-stopped \
|
||||
\$DOCKER run -d --name fedimint-gateway --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8176:8176 -p 9737:9737 \
|
||||
@@ -1242,9 +1266,9 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx lnd; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx lnd; then
|
||||
sudo $DOCKER start lnd 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx lnd; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx lnd; then
|
||||
$DOCKER start lnd 2>/dev/null || true
|
||||
echo " LND started (existing)"
|
||||
else
|
||||
echo " Creating LND..."
|
||||
@@ -1275,7 +1299,7 @@ autopilot.active=false
|
||||
LNDCONF
|
||||
sudo cp /tmp/lnd.conf /var/lib/archipelago/lnd/lnd.conf
|
||||
fi
|
||||
sudo $DOCKER run -d --name lnd --restart unless-stopped --network archy-net \
|
||||
$DOCKER run -d --name lnd --restart unless-stopped --network archy-net \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add FOWNER --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 9735:9735 -p 10009:10009 -p 8080:8080 \
|
||||
@@ -1293,13 +1317,13 @@ LNDCONF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx homeassistant; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx homeassistant; then
|
||||
sudo $DOCKER start homeassistant 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx homeassistant; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx homeassistant; then
|
||||
$DOCKER start homeassistant 2>/dev/null || true
|
||||
else
|
||||
echo " Creating Home Assistant..."
|
||||
sudo mkdir -p /var/lib/archipelago/home-assistant
|
||||
sudo $DOCKER run -d --name homeassistant --restart unless-stopped \
|
||||
$DOCKER run -d --name homeassistant --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add DAC_OVERRIDE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8123:8123 -v /var/lib/archipelago/home-assistant:/config \
|
||||
@@ -1316,14 +1340,14 @@ LNDCONF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx grafana; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx grafana; then
|
||||
sudo $DOCKER start grafana 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx grafana; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx grafana; then
|
||||
$DOCKER start grafana 2>/dev/null || true
|
||||
else
|
||||
echo " Creating Grafana..."
|
||||
sudo mkdir -p /var/lib/archipelago/grafana
|
||||
sudo chown 472:472 /var/lib/archipelago/grafana 2>/dev/null || true
|
||||
sudo $DOCKER run -d --name grafana --restart unless-stopped \
|
||||
$DOCKER run -d --name grafana --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 3000:3000 -v /var/lib/archipelago/grafana:/var/lib/grafana \
|
||||
@@ -1340,13 +1364,13 @@ LNDCONF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx jellyfin; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx jellyfin; then
|
||||
sudo $DOCKER start jellyfin 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx jellyfin; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx jellyfin; then
|
||||
$DOCKER start jellyfin 2>/dev/null || true
|
||||
else
|
||||
echo " Creating Jellyfin..."
|
||||
sudo mkdir -p /var/lib/archipelago/jellyfin/config /var/lib/archipelago/jellyfin/cache
|
||||
sudo $DOCKER run -d --name jellyfin --restart unless-stopped \
|
||||
$DOCKER run -d --name jellyfin --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
-p 8096:8096 \
|
||||
-v /var/lib/archipelago/jellyfin/config:/config \
|
||||
@@ -1363,13 +1387,13 @@ LNDCONF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx vaultwarden; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx vaultwarden; then
|
||||
sudo $DOCKER start vaultwarden 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx vaultwarden; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx vaultwarden; then
|
||||
$DOCKER start vaultwarden 2>/dev/null || true
|
||||
else
|
||||
echo " Creating Vaultwarden..."
|
||||
sudo mkdir -p /var/lib/archipelago/vaultwarden
|
||||
sudo $DOCKER run -d --name vaultwarden --restart unless-stopped \
|
||||
$DOCKER run -d --name vaultwarden --restart unless-stopped \
|
||||
--cap-drop ALL --cap-add CHOWN --cap-add SETUID --cap-add SETGID --cap-add NET_BIND_SERVICE \
|
||||
--security-opt no-new-privileges:true \
|
||||
-p 8082:80 -v /var/lib/archipelago/vaultwarden:/data \
|
||||
@@ -1385,12 +1409,12 @@ LNDCONF
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx searxng; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx searxng; then
|
||||
sudo $DOCKER start searxng 2>/dev/null || true
|
||||
if ! $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx searxng; then
|
||||
if $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx searxng; then
|
||||
$DOCKER start searxng 2>/dev/null || true
|
||||
else
|
||||
echo " Creating SearXNG..."
|
||||
sudo $DOCKER run -d --name searxng --restart unless-stopped \
|
||||
$DOCKER run -d --name searxng --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
-p 8888:8080 \
|
||||
docker.io/searxng/searxng:latest
|
||||
@@ -1400,26 +1424,8 @@ LNDCONF
|
||||
fi
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Ollama (local LLM inference — used by AIUI)
|
||||
progress "Ensuring Ollama"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
DOCKER=podman
|
||||
command -v podman >/dev/null 2>&1 || DOCKER=docker
|
||||
if ! sudo $DOCKER ps --format "{{.Names}}" 2>/dev/null | grep -qx ollama; then
|
||||
if sudo $DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -qx ollama; then
|
||||
sudo $DOCKER start ollama 2>/dev/null || true
|
||||
else
|
||||
echo " Creating Ollama..."
|
||||
sudo mkdir -p /var/lib/archipelago/ollama
|
||||
sudo $DOCKER run -d --name ollama --restart unless-stopped \
|
||||
--cap-drop ALL --security-opt no-new-privileges:true \
|
||||
-p 11434:11434 -v /var/lib/archipelago/ollama:/root/.ollama \
|
||||
docker.io/ollama/ollama:latest
|
||||
fi
|
||||
else
|
||||
echo " Ollama already running"
|
||||
fi
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
# Ollama — optional, install from marketplace if needed
|
||||
# (removed from auto-deploy: large image, not needed for core functionality)
|
||||
|
||||
fi # end FRONTEND_ONLY guard
|
||||
|
||||
@@ -1437,31 +1443,31 @@ LNDCONF
|
||||
# resolve container IPs for nginx proxy (DNS resolver 127.0.0.11 is unreliable in podman)
|
||||
progress "Fixing IndeedHub for NIP-07"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
if sudo podman ps --format "{{.Names}}" 2>/dev/null | grep -q "^indeedhub$"; then
|
||||
if podman ps --format "{{.Names}}" 2>/dev/null | grep -q "^indeedhub$"; then
|
||||
CHANGED=false
|
||||
NETWORK=$(sudo podman inspect indeedhub --format "{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}}{{end}}" 2>/dev/null)
|
||||
NETWORK=$(podman inspect indeedhub --format "{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}}{{end}}" 2>/dev/null)
|
||||
|
||||
# Remove X-Frame-Options so iframe works
|
||||
if sudo podman exec indeedhub grep -q "X-Frame-Options" /etc/nginx/conf.d/default.conf 2>/dev/null; then
|
||||
sudo podman exec indeedhub sed -i "/X-Frame-Options/d" /etc/nginx/conf.d/default.conf
|
||||
if podman exec indeedhub grep -q "X-Frame-Options" /etc/nginx/conf.d/default.conf 2>/dev/null; then
|
||||
podman exec indeedhub sed -i "/X-Frame-Options/d" /etc/nginx/conf.d/default.conf
|
||||
CHANGED=true
|
||||
echo " Removed X-Frame-Options from IndeedHub"
|
||||
fi
|
||||
|
||||
# Inject nostr-provider.js for NIP-07 signing
|
||||
if ! sudo podman exec indeedhub test -f /usr/share/nginx/html/nostr-provider.js 2>/dev/null; then
|
||||
sudo podman cp /opt/archipelago/web-ui/nostr-provider.js indeedhub:/usr/share/nginx/html/nostr-provider.js 2>/dev/null
|
||||
if ! podman exec indeedhub test -f /usr/share/nginx/html/nostr-provider.js 2>/dev/null; then
|
||||
podman cp /opt/archipelago/web-ui/nostr-provider.js indeedhub:/usr/share/nginx/html/nostr-provider.js 2>/dev/null
|
||||
echo " Copied nostr-provider.js into IndeedHub"
|
||||
fi
|
||||
|
||||
# Add nostr-provider.js + sub_filter to nginx config
|
||||
if ! sudo podman exec indeedhub grep -q "nostr-provider" /etc/nginx/conf.d/default.conf 2>/dev/null; then
|
||||
sudo podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null
|
||||
if ! podman exec indeedhub grep -q "nostr-provider" /etc/nginx/conf.d/default.conf 2>/dev/null; then
|
||||
podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null
|
||||
# Add nostr-provider location block before sw.js block
|
||||
sed -i "/location = \/sw.js {/i\\ location = /nostr-provider.js {\n add_header Cache-Control \"no-cache, no-store, must-revalidate\";\n expires off;\n }\n" /tmp/ih-nginx.conf
|
||||
# Add sub_filter for nostr-provider injection
|
||||
sed -i "/try_files.*index.html/a\\ sub_filter_once on;\n sub_filter '"'"'</head>'"'"' '"'"'<script src=\"/nostr-provider.js\"></script></head>'"'"';" /tmp/ih-nginx.conf
|
||||
sudo podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null
|
||||
podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null
|
||||
rm -f /tmp/ih-nginx.conf
|
||||
CHANGED=true
|
||||
echo " Injected nostr-provider.js into IndeedHub nginx"
|
||||
@@ -1469,26 +1475,26 @@ LNDCONF
|
||||
|
||||
# Replace DNS-based upstream resolution with hardcoded container IPs
|
||||
# (podman DNS resolver 127.0.0.11 is unreliable, causing 502 errors)
|
||||
API_IP=$(sudo podman inspect indeedhub-build_api_1 --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
MINIO_IP=$(sudo podman inspect indeedhub-minio --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
RELAY_IP=$(sudo podman inspect indeedhub-relay --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
API_IP=$(podman inspect indeedhub-build_api_1 --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
MINIO_IP=$(podman inspect indeedhub-minio --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
RELAY_IP=$(podman inspect indeedhub-relay --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null)
|
||||
|
||||
if [ -n "$API_IP" ] && [ -n "$MINIO_IP" ] && [ -n "$RELAY_IP" ]; then
|
||||
sudo podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null
|
||||
podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null
|
||||
# Remove DNS resolver lines and replace upstream variables with hardcoded IPs
|
||||
sed -i "s|resolver 127.0.0.11 valid=30s ipv6=off;||g" /tmp/ih-nginx.conf
|
||||
sed -i "s|set \$api_upstream http://api:4000;|set \$api_upstream http://$API_IP:4000;|g" /tmp/ih-nginx.conf
|
||||
sed -i "s|set \$minio_upstream http://minio:9000;|set \$minio_upstream http://$MINIO_IP:9000;|g" /tmp/ih-nginx.conf
|
||||
sed -i "s|set \$relay_upstream http://relay:8080;|set \$relay_upstream http://$RELAY_IP:8080;|g" /tmp/ih-nginx.conf
|
||||
sed -i "s|proxy_set_header Host \$host;|proxy_set_header Host \$http_host;|g" /tmp/ih-nginx.conf
|
||||
sudo podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null
|
||||
podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null
|
||||
rm -f /tmp/ih-nginx.conf
|
||||
CHANGED=true
|
||||
echo " Patched IndeedHub nginx with container IPs (API=$API_IP MINIO=$MINIO_IP RELAY=$RELAY_IP)"
|
||||
fi
|
||||
|
||||
if [ "$CHANGED" = true ]; then
|
||||
sudo podman exec indeedhub nginx -s reload 2>/dev/null
|
||||
podman exec indeedhub nginx -s reload 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
' 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
@@ -53,4 +53,35 @@ EOF
|
||||
# Apply sysctl settings
|
||||
sysctl --system >/dev/null 2>&1 || true
|
||||
|
||||
# Remove policy-rc.d if present — leftover from chroot build, blocks service starts
|
||||
rm -f /usr/sbin/policy-rc.d 2>/dev/null || true
|
||||
|
||||
# Ensure NTP time sync via chrony (more reliable than systemd-timesyncd)
|
||||
if ! dpkg -l chrony >/dev/null 2>&1; then
|
||||
echo "🕐 Installing chrony for NTP time sync..."
|
||||
apt-get update -qq && apt-get install -y chrony 2>/dev/null || true
|
||||
fi
|
||||
systemctl enable chrony 2>/dev/null || true
|
||||
systemctl start chrony 2>/dev/null || true
|
||||
timedatectl set-ntp true 2>/dev/null || true
|
||||
|
||||
# Ensure swap exists — prevents OOM kills on memory-constrained nodes
|
||||
TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
TOTAL_MEM_GB=$((TOTAL_MEM_KB / 1024 / 1024))
|
||||
SWAP_SIZE_GB=$((TOTAL_MEM_GB > 8 ? 8 : TOTAL_MEM_GB))
|
||||
if [ ! -f /swapfile ]; then
|
||||
echo "💾 Creating ${SWAP_SIZE_GB}G swap file..."
|
||||
fallocate -l ${SWAP_SIZE_GB}G /swapfile
|
||||
chmod 600 /swapfile
|
||||
mkswap /swapfile
|
||||
swapon /swapfile
|
||||
if ! grep -q '/swapfile' /etc/fstab; then
|
||||
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||
fi
|
||||
echo "✅ Swap created: ${SWAP_SIZE_GB}G"
|
||||
else
|
||||
echo "✅ Swap file already exists"
|
||||
swapon /swapfile 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "✅ Debian optimization complete!"
|
||||
|
||||
Reference in New Issue
Block a user