Browse Source

fix: replace SNICallback with setSecureContext for IP cert compatibility

pull/2552/head
Platon47 4 months ago
committed by GitHub
parent
commit
04dcb2fc1b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 129
      scripts/entrypoint.sh

129
scripts/entrypoint.sh

@ -2,16 +2,16 @@
#=== #===
# wg-easy-ip-tls entrypoint # wg-easy-ip-tls entrypoint
# Architecture: # Architecture:
# - dumb-init is PID 1 and spawns this script for proper # - dumb-init is PID 1 and spawns this script for proper
# signal forwarding and zombie reaping # signal forwarding and zombie reaping
# - Nitro (wg-easy) runs on HTTP internally on NITRO_PORT # - Nitro (wg-easy) runs on HTTP internally on NITRO_PORT
# - If LEGO_ENABLED=true and INSECURE!=true: a Node.js TLS # - If LEGO_ENABLED=true and INSECURE!=true: a Node.js TLS
# reverse proxy wraps Nitro on PORT (HTTPS termination) # reverse proxy wraps Nitro on PORT (HTTPS termination)
# Certs are re-read from disk on every TLS handshake so # Certs are loaded at startup; renewed certs are applied
# renewed certs take effect without restart # via server.setSecureContext() without restart
# - If INSECURE=true: Nitro listens directly on PORT (HTTP) # - If INSECURE=true: Nitro listens directly on PORT (HTTP)
# - A background renewal loop re-runs lego-renew.sh every # - A background renewal loop re-runs lego-renew.sh every
# LEGO_RENEW_INTERVAL seconds (default: 5 days) # LEGO_RENEW_INTERVAL seconds (default: 5 days)
#=== #===
set -eu set -eu
@ -48,7 +48,7 @@ cleanup() {
trap cleanup TERM INT trap cleanup TERM INT
if [ "$LEGO_ENABLED" = "true" ] && [ "$INSECURE" != "true" ]; then if [ "$LEGO_ENABLED" = "true" ] && [ "$INSECURE" != "true" ]; then
# ── TLS mode ─── # -- TLS mode ---
/usr/local/bin/lego-renew.sh /usr/local/bin/lego-renew.sh
# Start background cert renewal loop # Start background cert renewal loop
@ -79,67 +79,72 @@ if [ "$LEGO_ENABLED" = "true" ] && [ "$INSECURE" != "true" ]; then
done done
echo "[entrypoint] Starting TLS proxy on port $PORT..." echo "[entrypoint] Starting TLS proxy on port $PORT..."
# Certs are read from disk on every handshake so renewed certs take effect immediately # Use setSecureContext for cert hot-reload (works with IP certs - no SNI needed)
node -e " node -e "
const https = require('https'); const https = require('https');
const http = require('http'); const http = require('http');
const net = require('net'); const net = require('net');
const fs = require('fs'); const fs = require('fs');
const CERT_FILE = '$CERT_FILE'; const CERT_FILE = '$CERT_FILE';
const KEY_FILE = '$KEY_FILE'; const KEY_FILE = '$KEY_FILE';
const NITRO_PORT = $NITRO_PORT; const NITRO_PORT = $NITRO_PORT;
const server = https.createServer({ const loadCreds = () => ({
SNICallback: (servername, cb) => { cert: fs.readFileSync(CERT_FILE),
try { key: fs.readFileSync(KEY_FILE),
cb(null, require('tls').createSecureContext({ });
cert: fs.readFileSync(CERT_FILE), const server = https.createServer(loadCreds(), (req, res) => {
key: fs.readFileSync(KEY_FILE), const proxy = http.request({
})); hostname: '127.0.0.1',
} catch (e) { port: NITRO_PORT,
cb(e); path: req.url,
} method: req.method,
} headers: req.headers,
}, (req, res) => { }, (proxyRes) => {
const proxy = http.request({ res.writeHead(proxyRes.statusCode, proxyRes.headers);
hostname: '127.0.0.1', proxyRes.pipe(res);
port: NITRO_PORT, });
path: req.url, proxy.on('error', (e) => {
method: req.method, console.error('[tls-proxy] error:', e.message);
headers: req.headers, if (!res.headersSent) { res.writeHead(502); }
}, (proxyRes) => { res.end('Bad Gateway');
res.writeHead(proxyRes.statusCode, proxyRes.headers); });
proxyRes.pipe(res); req.pipe(proxy);
}); });
proxy.on('error', (e) => { server.on('upgrade', (req, socket, head) => {
console.error('[tls-proxy] error:', e.message); const conn = net.connect(NITRO_PORT, '127.0.0.1', () => {
if (!res.headersSent) { res.writeHead(502); } conn.write('GET ' + req.url + ' HTTP/1.1\\r\\n' +
res.end('Bad Gateway'); Object.entries(req.headers).map(([k,v]) => k + ': ' + v).join('\\r\\n') +
'\\r\\n\\r\\n');
if (head && head.length) conn.write(head);
socket.pipe(conn);
conn.pipe(socket);
});
conn.on('error', (e) => {
console.error('[tls-proxy] ws error:', e.message);
socket.destroy();
});
}); });
req.pipe(proxy); // Hot-reload certs when lego-renew.sh updates them
}); fs.watchFile(CERT_FILE, { interval: 60000, persistent: true }, (curr, prev) => {
server.on('upgrade', (req, socket, head) => { if (curr.mtime !== prev.mtime) {
const conn = net.connect(NITRO_PORT, '127.0.0.1', () => { try {
conn.write('GET ' + req.url + ' HTTP/1.1\\r\\n' + server.setSecureContext(loadCreds());
Object.entries(req.headers).map(([k,v]) => k + ': ' + v).join('\\r\\n') + console.log('[tls-proxy] Certificate reloaded at ' + curr.mtime.toISOString());
'\\r\\n\\r\\n'); } catch (e) {
if (head && head.length) conn.write(head); console.error('[tls-proxy] Failed to reload cert:', e.message);
socket.pipe(conn); }
conn.pipe(socket); }
}); });
conn.on('error', (e) => { server.listen($PORT, '0.0.0.0', () => {
console.error('[tls-proxy] ws error:', e.message); console.log('[tls-proxy] HTTPS listening on 0.0.0.0:$PORT -> http://127.0.0.1:$NITRO_PORT');
socket.destroy();
}); });
});
server.listen($PORT, '0.0.0.0', () => {
console.log('[tls-proxy] HTTPS listening on 0.0.0.0:$PORT -> http://127.0.0.1:$NITRO_PORT');
});
" & " &
echo $! > "$PROXY_PID_FILE" echo $! > "$PROXY_PID_FILE"
else else
# ── HTTP mode (INSECURE=true or LEGO_ENABLED=false) ─── # -- HTTP mode (INSECURE=true or LEGO_ENABLED=false) ---
echo "[entrypoint] Starting wg-easy in HTTP mode on port $PORT..." echo "[entrypoint] Starting wg-easy in HTTP mode on port $PORT..."
PORT="$PORT" HOST="0.0.0.0" node /app/server/index.mjs & PORT="$PORT" HOST="0.0.0.0" node /app/server/index.mjs &
echo $! > "$SERVER_PID_FILE" echo $! > "$SERVER_PID_FILE"
fi fi
wait wait

Loading…
Cancel
Save