fix: Tor management system, bug fixes, federation name sync
Major changes: - Full Tor hidden service management via systemd path unit pattern (tor-helper.sh + archipelago-tor-helper.path/service) — respects NoNewPrivileges=yes, no sudo needed from backend - Container doctor: prefer system Tor over container, remove archy-tor - Deploy script: fix torrc generation (read correct services.json path), web apps map port 80→local port, enable both tor and tor@default - Federation: server rename pushes name to peers via background sync - Server name: fix root-owned file, optimistic store update - Mesh: local echo for sent messages, sendingArch loading state - Web5: Message button → Mesh redirect, node name lookup in messages - PeerFiles: show DID not onion in header - Connected Nodes: flex-1 instead of fixed max-h - Toast notifications route to Mesh - Deploy script: fix single-quote syntax in SSH block Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -685,8 +685,9 @@ PYEOF
|
||||
# Fix secrets directory ownership (must be readable by archipelago user, not root)
|
||||
sudo chown -R archipelago:archipelago /var/lib/archipelago/secrets 2>/dev/null || true
|
||||
sudo chmod 700 /var/lib/archipelago/secrets 2>/dev/null || true
|
||||
# Fix any root-owned config files in data dir (dead man's switch, sessions, etc.)
|
||||
sudo find /var/lib/archipelago -maxdepth 1 -name '*.json' -user root -exec chown archipelago:archipelago {} \; 2>/dev/null || true
|
||||
# Fix any root-owned files in data dir - dead mans switch, sessions, server-name
|
||||
sudo find /var/lib/archipelago -maxdepth 1 -name "*.json" -user root -exec chown archipelago:archipelago {} \; 2>/dev/null || true
|
||||
sudo chown archipelago:archipelago /var/lib/archipelago/server-name 2>/dev/null || true
|
||||
echo " Data directories OK"
|
||||
|
||||
# Rootless podman UID mapping: fix data dir ownership so container processes
|
||||
@@ -716,6 +717,26 @@ PYEOF
|
||||
scp $SSH_OPTS "$PROJECT_DIR/neode-ui/public/nostr-provider.js" "$TARGET_HOST:/tmp/nostr-provider.js" 2>/dev/null && \
|
||||
ssh $SSH_OPTS "$TARGET_HOST" 'sudo cp /tmp/nostr-provider.js /opt/archipelago/web-ui/nostr-provider.js && echo " nostr-provider.js deployed"' 2>/dev/null || echo " (nostr-provider.js not found, skipping)"
|
||||
|
||||
# Deploy tor-helper: script + systemd path unit for privileged Tor management
|
||||
progress "Deploying tor-helper"
|
||||
scp $SSH_OPTS \
|
||||
"$PROJECT_DIR/scripts/tor-helper.sh" \
|
||||
"$PROJECT_DIR/image-recipe/configs/archipelago-tor-helper.path" \
|
||||
"$PROJECT_DIR/image-recipe/configs/archipelago-tor-helper.service" \
|
||||
"$TARGET_HOST:/tmp/" 2>/dev/null && \
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
sudo mkdir -p /opt/archipelago/scripts
|
||||
sudo cp /tmp/tor-helper.sh /opt/archipelago/scripts/tor-helper.sh
|
||||
sudo chmod 755 /opt/archipelago/scripts/tor-helper.sh
|
||||
sudo chown root:root /opt/archipelago/scripts/tor-helper.sh
|
||||
sudo cp /tmp/archipelago-tor-helper.path /etc/systemd/system/
|
||||
sudo cp /tmp/archipelago-tor-helper.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable archipelago-tor-helper.path
|
||||
sudo systemctl start archipelago-tor-helper.path
|
||||
echo " tor-helper deployed with systemd path unit"
|
||||
' 2>/dev/null || echo " (tor-helper deploy skipped)"
|
||||
|
||||
# Sync nginx config (second pass — includes HTTPS snippets)
|
||||
scp $SSH_OPTS "$PROJECT_DIR/image-recipe/configs/nginx-archipelago.conf" "$TARGET_HOST:/tmp/nginx-archipelago.conf" 2>/dev/null && \
|
||||
ssh $SSH_OPTS "$TARGET_HOST" '
|
||||
@@ -1201,32 +1222,54 @@ print("services.json created")
|
||||
'
|
||||
fi
|
||||
|
||||
# Generate torrc — use /var/lib/tor/ for hidden services (AppArmor-safe)
|
||||
# Generate torrc from services.json — use /var/lib/tor/ for hidden services
|
||||
sudo python3 -c '
|
||||
import json
|
||||
lines = ["SocksPort 9050", "ControlPort 0", ""]
|
||||
try:
|
||||
with open("/var/lib/archipelago/tor/services.json") as f:
|
||||
cfg = json.load(f)
|
||||
extra_ports = {"lnd": [8080]} # LND REST API over Tor
|
||||
import json, os
|
||||
|
||||
# Protocol services get direct port mapping; web apps map port 80 to their local port
|
||||
PROTOCOL_SERVICES = {"bitcoin", "bitcoin-knots", "electrs", "electrumx", "lnd"}
|
||||
|
||||
lines = ["# Auto-generated by Archipelago deploy", "SocksPort 9050", "# ControlPort disabled", ""]
|
||||
|
||||
# Try reading services config (check both paths for compatibility)
|
||||
cfg = None
|
||||
for path in ["/var/lib/archipelago/tor-config/services.json", "/var/lib/archipelago/tor/services.json"]:
|
||||
try:
|
||||
with open(path) as f:
|
||||
cfg = json.load(f)
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if cfg:
|
||||
for svc in cfg.get("services", []):
|
||||
if svc.get("enabled", True):
|
||||
n = svc["name"]
|
||||
p = svc["local_port"]
|
||||
lines.append("HiddenServiceDir /var/lib/tor/hidden_service_%s" % n)
|
||||
lines.append("HiddenServicePort %d 127.0.0.1:%d" % (p, p))
|
||||
for ep in extra_ports.get(n, []):
|
||||
lines.append("HiddenServicePort %d 127.0.0.1:%d" % (ep, ep))
|
||||
lines.append("")
|
||||
except Exception:
|
||||
for n, ports in [("archipelago",[80]),("bitcoin",[8333]),("electrumx",[50001]),("lnd",[9735,8080]),("btcpay",[23000]),("mempool",[4080]),("fedimint",[8175])]:
|
||||
if not svc.get("enabled", True):
|
||||
continue
|
||||
n = svc["name"]
|
||||
p = svc["local_port"]
|
||||
lines.append("HiddenServiceDir /var/lib/tor/hidden_service_%s" % n)
|
||||
for p in ports:
|
||||
if n in PROTOCOL_SERVICES:
|
||||
# Protocol: direct port mapping
|
||||
lines.append("HiddenServicePort %d 127.0.0.1:%d" % (p, p))
|
||||
if n == "lnd":
|
||||
lines.append("HiddenServicePort 9735 127.0.0.1:9735")
|
||||
lines.append("HiddenServicePort 10009 127.0.0.1:10009")
|
||||
else:
|
||||
# Web app: map port 80 on .onion to local app port (access via app.onion without port)
|
||||
lines.append("HiddenServicePort 80 127.0.0.1:%d" % p)
|
||||
lines.append("")
|
||||
else:
|
||||
# Fallback: default services
|
||||
for n, mappings in [("archipelago",[(80,80)]),("bitcoin",[(8333,8333)]),("electrs",[(50001,50001)]),("lnd",[(8080,8080),(9735,9735),(10009,10009)]),("btcpay",[(80,23000)]),("mempool",[(80,4080)]),("fedimint",[(80,8175)])]:
|
||||
lines.append("HiddenServiceDir /var/lib/tor/hidden_service_%s" % n)
|
||||
for remote_p, local_p in mappings:
|
||||
lines.append("HiddenServicePort %d 127.0.0.1:%d" % (remote_p, local_p))
|
||||
lines.append("")
|
||||
|
||||
with open("/etc/tor/torrc", "w") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
print("torrc generated with %d services" % (len(lines) // 3))
|
||||
enabled = sum(1 for s in (cfg or {}).get("services", []) if s.get("enabled", True))
|
||||
print("torrc generated with %d services" % (enabled or 7))
|
||||
'
|
||||
|
||||
# Remove any old Tor container (system Tor is preferred)
|
||||
@@ -1238,6 +1281,8 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
# Use system Tor (preferred — no AppArmor issues with default paths)
|
||||
if command -v tor >/dev/null 2>&1; then
|
||||
sudo systemctl enable tor 2>/dev/null
|
||||
sudo systemctl enable tor@default 2>/dev/null
|
||||
sudo systemctl restart tor 2>/dev/null
|
||||
sudo systemctl restart tor@default 2>/dev/null
|
||||
echo ' Using system Tor daemon'
|
||||
else
|
||||
@@ -1245,6 +1290,8 @@ print("torrc generated with %d services" % (len(lines) // 3))
|
||||
sudo apt-get update -qq && sudo apt-get install -y -qq tor 2>/dev/null || true
|
||||
if command -v tor >/dev/null 2>&1; then
|
||||
sudo systemctl enable tor 2>/dev/null
|
||||
sudo systemctl enable tor@default 2>/dev/null
|
||||
sudo systemctl restart tor 2>/dev/null
|
||||
sudo systemctl restart tor@default 2>/dev/null
|
||||
echo ' System Tor installed and started'
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user