From ed3df0728f7fe44983ff93e2858492321775bcf8 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 8 Apr 2026 23:29:50 +0200 Subject: [PATCH] fix: container stack installers, DNS resolution, uninstall cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace aardvark-dns container names with host.containers.internal for all cross-app connections (LND→Bitcoin, ElectrumX→Bitcoin, Mempool→ElectrumX, Fedimint→Bitcoin, NBXplorer→Bitcoin P2P+RPC) - Add BTCPay multi-container stack installer (postgres + nbxplorer + btcpay-server) with proper secrets, data dir ownership, NOAUTH - Add Mempool multi-container stack installer (mariadb + mempool-api + mempool-frontend) with host.containers.internal for RPC - Immediately remove apps from state on uninstall (no 3-min ghost delay) - Include archy-bitcoin-ui in bitcoin uninstall container list - Fix LND UI port 8081 (was 8080, conflicting with LND gRPC) - Fix ElectrumX UI: proxy /electrs-status to backend, cache-busting headers, graceful fallback when backend returns HTML - Add Tor hidden services for ElectrumX and LND in torrc template - Remove unused detect_bitcoin_container_name() (replaced by host.containers.internal) Co-Authored-By: Claude Opus 4.6 --- .../archipelago/src/api/rpc/package/config.rs | 55 ++- .../src/api/rpc/package/install.rs | 8 +- .../src/api/rpc/package/runtime.rs | 19 ++ .../archipelago/src/api/rpc/package/stacks.rs | 318 +++++++++++++++++- docker/electrs-ui/index.html | 8 +- docker/electrs-ui/nginx.conf | 12 +- docker/lnd-ui/nginx.conf | 2 +- scripts/tor/torrc.template | 12 +- 8 files changed, 397 insertions(+), 37 deletions(-) diff --git a/core/archipelago/src/api/rpc/package/config.rs b/core/archipelago/src/api/rpc/package/config.rs index b8525ae9..8cc5c0f8 100644 --- a/core/archipelago/src/api/rpc/package/config.rs +++ b/core/archipelago/src/api/rpc/package/config.rs @@ -6,25 +6,6 @@ use anyhow::{Context, Result}; #[allow(dead_code)] pub(super) const TRUSTED_REGISTRIES: &[&str] = &["docker.io/", "ghcr.io/", "localhost/", "80.71.235.15:3000/"]; -/// Detect which Bitcoin container is running on archy-net for DNS resolution. -/// Returns the container name to use as the RPC host (e.g., "bitcoin-knots"). -pub(super) fn detect_bitcoin_container_name() -> String { - // Synchronous check — called from get_app_config which is sync - let output = std::process::Command::new("podman") - .args(["ps", "--format", "{{.Names}}"]) - .output(); - if let Ok(out) = output { - let names = String::from_utf8_lossy(&out.stdout); - for candidate in &["bitcoin-knots", "bitcoin-core", "bitcoin"] { - if names.lines().any(|l| l.trim() == *candidate) { - return candidate.to_string(); - } - } - } - // Default to bitcoin-knots (most common) - "bitcoin-knots".to_string() -} - /// Validate Docker image against trusted registry allowlist. pub(super) fn is_valid_docker_image(image: &str) -> bool { if image.is_empty() || image.len() > 256 { @@ -318,7 +299,7 @@ pub(super) fn all_container_names(package_id: &str) -> Vec { "bitcoin" | "bitcoin-core" | "bitcoin-knots" => vec![ "bitcoin-knots".into(), "bitcoin".into(), "bitcoin-core".into(), "archy-bitcoin-knots".into(), "archy-bitcoin".into(), - "bitcoin-ui".into(), + "bitcoin-ui".into(), "archy-bitcoin-ui".into(), ], // LND + UI "lnd" => vec!["lnd".into(), "archy-lnd".into(), "archy-lnd-ui".into()], @@ -426,6 +407,24 @@ fn read_secret(name: &str, default: &str) -> String { .unwrap_or_else(|_| default.to_string()) } +/// Read a secret or generate and persist a random one if it doesn't exist. +pub(super) async fn read_or_generate_secret(name: &str) -> String { + let path = format!("/var/lib/archipelago/secrets/{}", name); + if let Ok(val) = tokio::fs::read_to_string(&path).await { + let trimmed = val.trim().to_string(); + if !trimmed.is_empty() { + return trimmed; + } + } + // Generate a 24-byte random password (hex-encoded = 48 chars) + let mut buf = [0u8; 24]; + rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut buf); + let secret = hex::encode(buf); + let _ = tokio::fs::create_dir_all("/var/lib/archipelago/secrets").await; + let _ = tokio::fs::write(&path, &secret).await; + secret +} + /// Read the node-level Nostr secret key (hex) for identity-aware apps. /// Returns empty string if not yet generated. fn read_nostr_secret_hex() -> String { @@ -491,9 +490,9 @@ pub(super) async fn get_app_config( "--bitcoin.node=bitcoind".to_string(), format!("--bitcoind.rpcuser={}", rpc_user), format!("--bitcoind.rpcpass={}", rpc_pass), - "--bitcoind.rpchost=bitcoin-knots:8332".to_string(), - "--bitcoind.zmqpubrawblock=tcp://bitcoin-knots:28332".to_string(), - "--bitcoind.zmqpubrawtx=tcp://bitcoin-knots:28333".to_string(), + "--bitcoind.rpchost=host.containers.internal:8332".to_string(), + "--bitcoind.zmqpubrawblock=tcp://host.containers.internal:28332".to_string(), + "--bitcoind.zmqpubrawtx=tcp://host.containers.internal:28333".to_string(), "--rpclisten=0.0.0.0:10009".to_string(), "--restlisten=0.0.0.0:8080".to_string(), "--listen=0.0.0.0:9735".to_string(), @@ -528,7 +527,7 @@ pub(super) async fn get_app_config( vec!["/var/lib/archipelago/mempool:/data".to_string()], vec![ "MEMPOOL_BACKEND=electrum".to_string(), - "ELECTRUM_HOST=electrumx".to_string(), + "ELECTRUM_HOST=host.containers.internal".to_string(), "ELECTRUM_PORT=50001".to_string(), "ELECTRUM_TLS_ENABLED=false".to_string(), format!("CORE_RPC_HOST={}", host_ip), @@ -545,15 +544,13 @@ pub(super) async fn get_app_config( None, ), "electrumx" | "mempool-electrs" | "electrs" => { - // Detect which bitcoin container is running for archy-net DNS resolution - let bitcoin_host = detect_bitcoin_container_name(); ( vec!["50001:50001".to_string()], vec!["/var/lib/archipelago/electrumx:/data".to_string()], vec![ format!( - "DAEMON_URL=http://{}:{}@{}:8332/", - rpc_user, rpc_pass, bitcoin_host + "DAEMON_URL=http://{}:{}@host.containers.internal:8332/", + rpc_user, rpc_pass ), "COIN=Bitcoin".to_string(), "DB_DIRECTORY=/data".to_string(), @@ -757,7 +754,7 @@ pub(super) async fn get_app_config( Some(vec![ "--data-dir".to_string(), "/data".to_string(), - format!("--bitcoind-url=http://{}:{}@bitcoin-knots:8332", rpc_user, rpc_pass), + format!("--bitcoind-url=http://{}:{}@host.containers.internal:8332", rpc_user, rpc_pass), ]), ), "fedimint-gateway" => ( diff --git a/core/archipelago/src/api/rpc/package/install.rs b/core/archipelago/src/api/rpc/package/install.rs index 575d4dfa..9a437bd1 100644 --- a/core/archipelago/src/api/rpc/package/install.rs +++ b/core/archipelago/src/api/rpc/package/install.rs @@ -68,6 +68,12 @@ impl RpcHandler { if package_id == "penpot" || package_id == "penpot-frontend" { return self.install_penpot_stack().await; } + if matches!(package_id, "btcpay-server" | "btcpayserver" | "btcpay") { + return self.install_btcpay_stack().await; + } + if matches!(package_id, "mempool" | "mempool-web") { + return self.install_mempool_stack().await; + } // Dependency checks let deps = detect_running_deps().await?; @@ -692,7 +698,7 @@ bitcoin.mainnet=true\n\ bitcoin.node=bitcoind\n\ \n\ [Bitcoind]\n\ -bitcoind.rpchost=bitcoin-knots:8332\n\ +bitcoind.rpchost=host.containers.internal:8332\n\ bitcoind.rpcuser={user}\n\ bitcoind.rpcpass={pass}\n\ bitcoind.rpcpolling=true\n\ diff --git a/core/archipelago/src/api/rpc/package/runtime.rs b/core/archipelago/src/api/rpc/package/runtime.rs index 438d0143..c37f93da 100644 --- a/core/archipelago/src/api/rpc/package/runtime.rs +++ b/core/archipelago/src/api/rpc/package/runtime.rs @@ -374,6 +374,25 @@ impl RpcHandler { removed ); + // Immediately remove from in-memory state so the UI updates without + // waiting for the scanner's absence threshold (3 scans × 60s each). + { + let (mut data, _rev) = self.state_manager.get_snapshot().await; + let before = data.package_data.len(); + data.package_data.remove(package_id); + // Also remove any alias keys (e.g. "bitcoin-knots" vs "bitcoin") + let aliases: Vec = data.package_data.keys() + .filter(|k| super::config::all_container_names(package_id) + .iter().any(|c| c.strip_prefix("archy-").unwrap_or(c) == k.as_str())) + .cloned().collect(); + for alias in &aliases { + data.package_data.remove(alias); + } + if data.package_data.len() < before { + self.state_manager.update_data(data).await; + } + } + Ok(serde_json::json!({ "status": "uninstalled", "stopped": stopped, diff --git a/core/archipelago/src/api/rpc/package/stacks.rs b/core/archipelago/src/api/rpc/package/stacks.rs index 03250c1e..e27a0c1c 100644 --- a/core/archipelago/src/api/rpc/package/stacks.rs +++ b/core/archipelago/src/api/rpc/package/stacks.rs @@ -1,4 +1,4 @@ -//! Multi-container app stack installers (Immich, Penpot). +//! Multi-container app stack installers (Immich, Penpot, BTCPay, Mempool). //! //! Each stack pulls multiple images, creates a private network, and starts //! containers in dependency order. @@ -7,6 +7,8 @@ use crate::api::rpc::RpcHandler; use anyhow::{Context, Result}; use tracing::info; +const REGISTRY: &str = "80.71.235.15:3000/archipelago"; + /// Pull an image with retry and exponential backoff (3 attempts). async fn pull_image_with_retry(image: &str) -> Result<()> { const MAX_ATTEMPTS: u32 = 3; @@ -361,4 +363,318 @@ impl RpcHandler { "message": "Penpot stack installed and started" })) } + + /// Install BTCPay stack (postgres + nbxplorer + btcpay-server). + pub(super) async fn install_btcpay_stack(&self) -> Result { + use super::install::install_log; + + let check = tokio::process::Command::new("podman") + .args(["ps", "-a", "--format", "{{.Names}}"]) + .output() + .await + .context("Failed to list containers")?; + let stdout = String::from_utf8_lossy(&check.stdout); + if stdout.lines().any(|l| l.trim() == "btcpay-server") { + return Err(anyhow::anyhow!( + "BTCPay already installed. Stop and remove it first." + )); + } + + // Dependency check: Bitcoin must be running + let deps = super::dependencies::detect_running_deps().await?; + super::dependencies::check_install_deps("btcpay-server", &deps)?; + + install_log("INSTALL START: btcpay-server (stack: postgres + nbxplorer + btcpay)").await; + + let (rpc_user, rpc_pass) = crate::bitcoin_rpc::bitcoin_rpc_credentials().await; + let host_ip = &self.config.host_ip; + + // Read or generate btcpay DB password + let db_pass = super::config::read_or_generate_secret("btcpay-db-password").await; + + let images = [ + &format!("{}/postgres:15.17", REGISTRY), + &format!("{}/nbxplorer:2.6.0", REGISTRY), + &format!("{}/btcpayserver:1.13.7", REGISTRY), + ]; + for img in &images { + pull_image_with_retry(img).await?; + } + + // Create data dirs (chown to current user so rootless podman can write) + let _ = tokio::process::Command::new("sudo") + .args([ + "mkdir", "-p", + "/var/lib/archipelago/postgres-btcpay", + "/var/lib/archipelago/btcpay/Main", + "/var/lib/archipelago/nbxplorer/Main", + ]) + .output() + .await; + let user = std::env::var("USER").unwrap_or_else(|_| "archipelago".to_string()); + for dir in &[ + "/var/lib/archipelago/postgres-btcpay", + "/var/lib/archipelago/btcpay", + "/var/lib/archipelago/nbxplorer", + ] { + let _ = tokio::process::Command::new("sudo") + .args(["chown", "-R", &format!("{}:{}", user, user), dir]) + .output() + .await; + } + + // Ensure archy-net exists + let _ = tokio::process::Command::new("podman") + .args(["network", "create", "archy-net"]) + .output() + .await; + + // 1. PostgreSQL + let _ = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "archy-btcpay-db", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "archy-btcpay-db", + "--memory=512m", + "-v", "/var/lib/archipelago/postgres-btcpay:/var/lib/postgresql/data", + "-e", "POSTGRES_DB=btcpay", + "-e", "POSTGRES_USER=btcpay", + "-e", &format!("POSTGRES_PASSWORD={}", db_pass), + &format!("{}/postgres:15.17", REGISTRY), + ]) + .output() + .await; + tokio::time::sleep(std::time::Duration::from_secs(8)).await; + + // Create nbxplorer database (superuser is "btcpay", not "postgres") + let _ = tokio::process::Command::new("podman") + .args([ + "exec", "archy-btcpay-db", + "psql", "-U", "btcpay", "-c", "CREATE DATABASE nbxplorer;", + ]) + .output() + .await; + + // 2. NBXplorer + let _ = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "archy-nbxplorer", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "archy-nbxplorer", + "--memory=512m", + "-p", "32838:32838", + "-v", "/var/lib/archipelago/nbxplorer:/data", + "-e", "NBXPLORER_DATADIR=/data", + "-e", "NBXPLORER_NETWORK=mainnet", + "-e", "NBXPLORER_CHAINS=btc", + "-e", "NBXPLORER_BIND=0.0.0.0:32838", + "-e", "NBXPLORER_BTCRPCURL=http://host.containers.internal:8332", + "-e", &format!("NBXPLORER_BTCRPCUSER={}", rpc_user), + "-e", &format!("NBXPLORER_BTCRPCPASSWORD={}", rpc_pass), + "-e", "NBXPLORER_BTCNODEENDPOINT=host.containers.internal:8333", + "-e", "NBXPLORER_NOAUTH=1", + "-e", &format!( + "NBXPLORER_POSTGRES=User ID=btcpay;Password={};Host=archy-btcpay-db;Port=5432;Database=nbxplorer;Include Error Detail=true", + db_pass + ), + &format!("{}/nbxplorer:2.6.0", REGISTRY), + ]) + .output() + .await; + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + // 3. BTCPay Server + let run = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "btcpay-server", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "btcpay-server", + "--memory=1g", + "-p", "23000:49392", + "-v", "/var/lib/archipelago/btcpay:/datadir", + "-e", "ASPNETCORE_URLS=http://0.0.0.0:49392", + "-e", "BTCPAY_PROTOCOL=http", + "-e", &format!("BTCPAY_HOST={}:23000", host_ip), + "-e", "BTCPAY_CHAINS=btc", + "-e", "BTCPAY_BTCEXPLORERURL=http://archy-nbxplorer:32838", + "-e", &format!("BTCPAY_BTCRPCURL=http://host.containers.internal:8332"), + "-e", &format!("BTCPAY_BTCRPCUSER={}", rpc_user), + "-e", &format!("BTCPAY_BTCRPCPASSWORD={}", rpc_pass), + "-e", &format!( + "BTCPAY_POSTGRES=User ID=btcpay;Password={};Host=archy-btcpay-db;Port=5432;Database=btcpay;Include Error Detail=true", + db_pass + ), + &format!("{}/btcpayserver:1.13.7", REGISTRY), + ]) + .output() + .await + .context("Failed to start btcpay-server")?; + + if !run.status.success() { + let stderr = String::from_utf8_lossy(&run.stderr); + install_log(&format!("INSTALL FAIL: btcpay-server — {}", stderr)).await; + return Err(anyhow::anyhow!("Failed to start BTCPay Server: {}", stderr)); + } + + install_log("INSTALL OK: btcpay-server stack").await; + info!("BTCPay stack installed and started"); + Ok(serde_json::json!({ + "success": true, + "package_id": "btcpay-server", + "message": "BTCPay stack installed and started", + "container_id": String::from_utf8_lossy(&run.stdout).trim().to_string(), + })) + } + + /// Install Mempool stack (mariadb + mempool-api + mempool-web). + pub(super) async fn install_mempool_stack(&self) -> Result { + use super::install::install_log; + + let check = tokio::process::Command::new("podman") + .args(["ps", "-a", "--format", "{{.Names}}"]) + .output() + .await + .context("Failed to list containers")?; + let stdout = String::from_utf8_lossy(&check.stdout); + if stdout.lines().any(|l| l.trim() == "mempool" || l.trim() == "archy-mempool-web") { + return Err(anyhow::anyhow!( + "Mempool already installed. Stop and remove it first." + )); + } + + // Dependency check: Bitcoin + ElectrumX must be running + let deps = super::dependencies::detect_running_deps().await?; + super::dependencies::check_install_deps("mempool", &deps)?; + + install_log("INSTALL START: mempool (stack: mariadb + mempool-api + mempool-web)").await; + + let (rpc_user, rpc_pass) = crate::bitcoin_rpc::bitcoin_rpc_credentials().await; + + let db_pass = super::config::read_or_generate_secret("mempool-db-password").await; + let root_pass = super::config::read_or_generate_secret("mempool-db-root-password").await; + + let images = [ + &format!("{}/mariadb:11.4.10", REGISTRY), + &format!("{}/mempool-backend:v3.0.0", REGISTRY), + &format!("{}/mempool-frontend:v3.0.0", REGISTRY), + ]; + for img in &images { + pull_image_with_retry(img).await?; + } + + // Create data dirs (chown to current user so rootless podman can write) + let _ = tokio::process::Command::new("sudo") + .args([ + "mkdir", "-p", + "/var/lib/archipelago/mysql-mempool", + "/var/lib/archipelago/mempool", + ]) + .output() + .await; + let user = std::env::var("USER").unwrap_or_else(|_| "archipelago".to_string()); + for dir in &[ + "/var/lib/archipelago/mysql-mempool", + "/var/lib/archipelago/mempool", + ] { + let _ = tokio::process::Command::new("sudo") + .args(["chown", "-R", &format!("{}:{}", user, user), dir]) + .output() + .await; + } + + // Ensure archy-net exists + let _ = tokio::process::Command::new("podman") + .args(["network", "create", "archy-net"]) + .output() + .await; + + // 1. MariaDB + let _ = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "archy-mempool-db", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "archy-mempool-db", + "--memory=512m", + "-v", "/var/lib/archipelago/mysql-mempool:/var/lib/mysql", + "-e", "MYSQL_DATABASE=mempool", + "-e", "MYSQL_USER=mempool", + "-e", &format!("MYSQL_PASSWORD={}", db_pass), + "-e", &format!("MYSQL_ROOT_PASSWORD={}", root_pass), + &format!("{}/mariadb:11.4.10", REGISTRY), + ]) + .output() + .await; + tokio::time::sleep(std::time::Duration::from_secs(10)).await; + + // 2. Mempool API backend + let _ = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "mempool-api", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "mempool-api", + "--memory=512m", + "-p", "8999:8999", + "-v", "/var/lib/archipelago/mempool:/data", + "-e", "MEMPOOL_BACKEND=electrum", + "-e", "ELECTRUM_HOST=host.containers.internal", + "-e", "ELECTRUM_PORT=50001", + "-e", "ELECTRUM_TLS_ENABLED=false", + "-e", "CORE_RPC_HOST=host.containers.internal", + "-e", "CORE_RPC_PORT=8332", + "-e", &format!("CORE_RPC_USERNAME={}", rpc_user), + "-e", &format!("CORE_RPC_PASSWORD={}", rpc_pass), + "-e", "DATABASE_ENABLED=true", + "-e", "DATABASE_HOST=archy-mempool-db", + "-e", "DATABASE_DATABASE=mempool", + "-e", "DATABASE_USERNAME=mempool", + "-e", &format!("DATABASE_PASSWORD={}", db_pass), + &format!("{}/mempool-backend:v3.0.0", REGISTRY), + ]) + .output() + .await; + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + + // 3. Mempool frontend + let run = tokio::process::Command::new("podman") + .args([ + "run", "-d", + "--name", "mempool", + "--restart", "unless-stopped", + "--network", "archy-net", + "--network-alias", "mempool", + "--memory=256m", + "-p", "4080:8080", + "-e", "FRONTEND_HTTP_PORT=8080", + "-e", "BACKEND_MAINNET_HTTP_HOST=mempool-api", + &format!("{}/mempool-frontend:v3.0.0", REGISTRY), + ]) + .output() + .await + .context("Failed to start mempool frontend")?; + + if !run.status.success() { + let stderr = String::from_utf8_lossy(&run.stderr); + install_log(&format!("INSTALL FAIL: mempool — {}", stderr)).await; + return Err(anyhow::anyhow!("Failed to start Mempool: {}", stderr)); + } + + install_log("INSTALL OK: mempool stack").await; + info!("Mempool stack installed and started"); + Ok(serde_json::json!({ + "success": true, + "package_id": "mempool", + "message": "Mempool stack installed and started", + "container_id": String::from_utf8_lossy(&run.stdout).trim().to_string(), + })) + } } diff --git a/docker/electrs-ui/index.html b/docker/electrs-ui/index.html index 1d4f23d3..58d38ab0 100644 --- a/docker/electrs-ui/index.html +++ b/docker/electrs-ui/index.html @@ -355,11 +355,15 @@ async function updateStatus() { try { - var resp = await fetch('/electrs-status'); + var resp = await fetch('/electrs-status', { cache: 'no-store' }); if (!resp.ok) { throw new Error('Backend unavailable (HTTP ' + resp.status + ')'); } - var data = await resp.json(); + var text = await resp.text(); + if (text.trim().charAt(0) !== '{') { + throw new Error('Waiting for Archipelago backend...'); + } + var data = JSON.parse(text); // Extract Tor onion from status response if (data.tor_onion && !torOnion) { diff --git a/docker/electrs-ui/nginx.conf b/docker/electrs-ui/nginx.conf index d9224af6..9f927d8f 100644 --- a/docker/electrs-ui/nginx.conf +++ b/docker/electrs-ui/nginx.conf @@ -5,9 +5,17 @@ server { root /usr/share/nginx/html; index index.html; - # electrs-status is fetched via absolute /electrs-status path, - # handled by the host nginx → backend at :5678 directly + location /electrs-status { + proxy_pass http://127.0.0.1:5678/electrs-status; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_connect_timeout 10s; + proxy_read_timeout 10s; + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + location / { + add_header Cache-Control "no-cache"; try_files $uri $uri/ /index.html; } } diff --git a/docker/lnd-ui/nginx.conf b/docker/lnd-ui/nginx.conf index affa3170..5d6f0c17 100644 --- a/docker/lnd-ui/nginx.conf +++ b/docker/lnd-ui/nginx.conf @@ -1,5 +1,5 @@ server { - listen 8080; + listen 8081; server_name _; root /usr/share/nginx/html; diff --git a/scripts/tor/torrc.template b/scripts/tor/torrc.template index 07b560e9..f6119555 100644 --- a/scripts/tor/torrc.template +++ b/scripts/tor/torrc.template @@ -12,9 +12,19 @@ DataDirectory /var/lib/archipelago/tor HiddenServiceDir /var/lib/archipelago/tor/hidden_service_archipelago/ HiddenServicePort 80 127.0.0.1:80 -# LND UI +# Bitcoin P2P (protocol service) +HiddenServiceDir /var/lib/archipelago/tor/hidden_service_bitcoin/ +HiddenServicePort 8333 127.0.0.1:8333 + +# ElectrumX (protocol service — wallet connections) +HiddenServiceDir /var/lib/archipelago/tor/hidden_service_electrumx/ +HiddenServicePort 50001 127.0.0.1:50001 + +# LND (protocol service — Lightning Network) HiddenServiceDir /var/lib/archipelago/tor/hidden_service_lnd/ HiddenServicePort 80 127.0.0.1:8081 +HiddenServicePort 9735 127.0.0.1:9735 +HiddenServicePort 10009 127.0.0.1:10009 # BTCPay Server HiddenServiceDir /var/lib/archipelago/tor/hidden_service_btcpay/