feat(ssl): move certificate generation to runtime with persistent volume

Self-signed SSL certificates are now generated at first startup instead
of being baked into the Docker image. Certificates persist in ./certs/
and are reused on subsequent runs. Users can provide their own certs
This commit is contained in:
2026-02-17 08:58:44 +01:00
parent 742b0662a7
commit 6c75fe55d0
5 changed files with 68 additions and 35 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# SSL certificates (auto-generated or user-provided)
/certs/
# ElectrumX server data
/electrumx-data/

View File

@@ -1,7 +1,7 @@
FROM lukechilds/electrumx
# Install curl (needed by entrypoint for RPC calls and IP detection)
RUN apk add --no-cache curl || apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
RUN apk add --no-cache curl openssl || apt-get update && apt-get install -y --no-install-recommends curl openssl && rm -rf /var/lib/apt/lists/*
# Copy Palladium coin definition and patch ElectrumX
COPY electrumx-patch/coins_plm.py /tmp/coins_plm.py
@@ -28,34 +28,6 @@ for target in [
print('>> Patched ElectrumX with Palladium coin classes')
PATCH
RUN mkdir -p /certs && \
cat >/certs/openssl.cnf <<'EOF' && \
openssl req -x509 -nodes -newkey rsa:4096 -days 3650 \
-keyout /certs/server.key -out /certs/server.crt \
-config /certs/openssl.cnf && \
chmod 600 /certs/server.key && chmod 644 /certs/server.crt
[req]
distinguished_name = dn
x509_extensions = v3_req
prompt = no
[dn]
C = IT
ST = -
L = -
O = ElectrumX
CN = plm.local
[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = plm.local
IP.1 = 127.0.0.1
EOF
ENV SSL_CERTFILE=/certs/server.crt
ENV SSL_KEYFILE=/certs/server.key

View File

@@ -46,6 +46,9 @@ palladium-stack/
│ ├── blocks/ # Blockchain blocks (auto-generated)
│ ├── chainstate/ # Blockchain state (auto-generated)
│ └── ... # Other runtime data (auto-generated)
├── certs/ # SSL certificates (auto-generated on first run)
│ ├── server.crt # Self-signed certificate
│ └── server.key # Private key
├── electrumx-data/ # ElectrumX database (auto-generated)
├── web-dashboard/ # Web monitoring dashboard
│ ├── app.py # Flask backend API
@@ -271,7 +274,7 @@ docker compose up -d
**What happens:**
1. Builds three Docker images: `palladium-node`, `electrumx-server`, and `palladium-dashboard`
2. Starts Palladium node first
3. Starts ElectrumX (waits for node to be ready)
3. Starts ElectrumX (waits for node to be ready, auto-generates SSL certificates in `./certs/` if not present)
4. Starts Web Dashboard (connects to both services)
**First build takes 5-10 minutes.**
@@ -455,8 +458,6 @@ Key settings in `.palladium/palladium.conf`:
| `port=2333` | Default | P2P network port (mainnet) |
| `rpcport=2332` | Default | RPC port (mainnet) |
**Important:** current `docker-compose.yml` starts `palladiumd` with command-line `-rpcallowip=0.0.0.0/0`, which overrides `rpcallowip` values in `palladium.conf`. Keep this in mind for security hardening.
**ZeroMQ Ports (optional):**
- `28332` - Block hash notifications
- `28333` - Transaction hash notifications
@@ -680,8 +681,9 @@ docker compose build --no-cache
```
3. **SSL Certificates:**
- Default uses self-signed certificates
- For production, use valid SSL certificates (Let's Encrypt)
- Self-signed certificates are auto-generated on first startup in `./certs/`
- The certificate includes localhost and the auto-detected public IP in its SAN
- To use your own certificates (e.g. Let's Encrypt), place `server.crt` and `server.key` in `./certs/` before starting
4. **Dashboard Access:**
- Consider adding authentication
@@ -744,7 +746,7 @@ environment:
## Notes
* **Data Persistence:** All data stored in `./.palladium/` and `./electrumx-data/`
* **Data Persistence:** All data stored in `./.palladium/`, `./electrumx-data/`, and `./certs/`
* **Backup:** Regularly backup `.palladium/wallet.dat` if you store funds
* **Network Switch:** Always clear ElectrumX database when switching networks
* **Updates:** Check for Palladium Core updates regularly

View File

@@ -72,6 +72,7 @@ services:
volumes:
- ./electrumx-data:/data
- ./.palladium/palladium.conf:/palladium-config/palladium.conf:ro
- ./certs:/certs
dashboard:
build:

View File

@@ -70,6 +70,61 @@ echo "DAEMON_URL: http://${RPC_USER}:***@palladiumd:${RPC_PORT}/"
echo "REPORT_SERVICES: ${REPORT_SERVICES:-not set}"
echo "=========================================="
# ── SSL certificate generation (skip if certs already exist) ──
if [ ! -f /certs/server.crt ] || [ ! -f /certs/server.key ]; then
echo "SSL certificates not found, generating self-signed certificate..."
# Collect SAN entries
SAN="DNS.1 = localhost"
SAN_IDX=1
IP_IDX=1
SAN="${SAN}\nIP.${IP_IDX} = 127.0.0.1"
# Try to detect public IP for SAN
for url in https://icanhazip.com https://ifconfig.me https://api.ipify.org; do
DETECTED_IP=$(curl -sf --max-time 5 "$url" 2>/dev/null | tr -d '[:space:]')
if [ -n "$DETECTED_IP" ]; then
IP_IDX=$((IP_IDX + 1))
SAN="${SAN}\nIP.${IP_IDX} = ${DETECTED_IP}"
echo ">> Including public IP in certificate SAN: ${DETECTED_IP}"
break
fi
done
cat >/tmp/openssl.cnf <<SSLEOF
[req]
distinguished_name = dn
x509_extensions = v3_req
prompt = no
[dn]
C = IT
ST = -
L = -
O = PalladiumStack
CN = localhost
[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
$(echo -e "$SAN")
SSLEOF
openssl req -x509 -nodes -newkey rsa:4096 -days 3650 \
-keyout /certs/server.key -out /certs/server.crt \
-config /tmp/openssl.cnf 2>/dev/null
chmod 600 /certs/server.key
chmod 644 /certs/server.crt
rm -f /tmp/openssl.cnf
echo ">> SSL certificate generated successfully"
else
echo ">> Using existing SSL certificates from /certs/"
fi
# Update TX_COUNT / TX_COUNT_HEIGHT in coins.py from the live node
echo "Fetching chain tx stats from palladiumd..."
TX_STATS=$(curl -sf --user "${RPC_USER}:${RPC_PASSWORD}" \