diff --git a/app.py b/app.py
index 2a6e7e0..e15cfbf 100644
--- a/app.py
+++ b/app.py
@@ -38,6 +38,10 @@ BTCPAY_URL = os.environ.get("BTCPAY_URL", "https://10.30.20.140")
BTCPAY_STORE = os.environ.get("BTCPAY_STORE_ID", "")
BTCPAY_TOKEN = os.environ.get("BTCPAY_API_KEY", "")
+# Public SOCKS5 endpoint customers connect to (authenticated frontend on CT158)
+PROXY_HOST = os.environ.get("PROXY_PUBLIC_HOST", "10.30.20.116")
+PROXY_PORT = os.environ.get("PROXY_PUBLIC_PORT", "1081")
+
def db():
con = getattr(g, "_db", None)
if con is None:
@@ -108,7 +112,8 @@ def index():
user = current_user()
if not user:
return render_template_string(AUTH_HTML, mode="login", error="")
- return render_template_string(DASH_HTML, user=user, locations=LOCATIONS, plans=PLANS)
+ return render_template_string(DASH_HTML, user=user, locations=LOCATIONS, plans=PLANS,
+ proxy_host=PROXY_HOST, proxy_port=PROXY_PORT)
@app.route("/health")
def health():
@@ -255,12 +260,12 @@ def btcpay_webhook():
return jsonify({"ok": True})
def provision_proxy(location, user, pw):
- """Best-effort: add user auth to the gost frontend for this location.
- The gost SOCKS5 frontends need per-user auth; for now we record the creds
- and the actual gost auth layer is wired per-location (see rigel-proxy setup)."""
- # Placeholder — the real gost auth is applied via the proxy gateway config.
- # Creds are persisted on the subscription row so the customer sees them.
- app.logger.info(f"provision proxy {location} for {user}")
+ """No per-node writes needed: the authenticated SOCKS5 frontend
+ (rigel-proxy.service on CT158) validates every connection live against the
+ subscriptions table, so persisting the row IS the provisioning step.
+ The upstream exits are dumb unauthenticated relays on the LAN."""
+ up = LOCATIONS.get(location, {}).get("upstream", "?")
+ app.logger.info(f"provisioned {location} (upstream {up}) for {user}")
# ── templates ───────────────────────────────────────────────────────────
AUTH_HTML = r"""
@@ -332,6 +337,10 @@ main{padding:28px;max-width:900px;margin:0 auto}
.subs{margin-top:32px}.subs h2{font-size:17px}.subs table{width:100%;border-collapse:collapse;font-size:13px}
.subs th,.subs td{padding:10px;text-align:left;border-bottom:1px solid #1e2742}.subs th{color:var(--muted);font-weight:500}
.badge{padding:3px 8px;border-radius:10px;font-size:11px}.active{background:#14321f;color:#2ecc71}.pending{background:#332a14;color:#f1c40f}.expired{background:#33171a;color:#e74c3c}
+.subcard{background:var(--card);border:1px solid #1e2742;border-radius:12px;padding:18px;margin-top:14px}
+.srow{font-size:15px;margin-bottom:6px}
+.lbl{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:10px}
+code{display:block;background:#0d1325;border:1px solid #26304f;border-radius:6px;padding:8px 10px;font-size:12px;color:#9fd0ff;word-break:break-all;margin-top:3px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
✦ Rigel — {{user["username"]}}
@@ -359,9 +368,21 @@ async function logout(){await fetch('/api/logout',{method:'POST'});location.relo
async function loadSubs(){
let r=await fetch('/api/subscriptions').then(x=>x.json());
if(!r.length){document.getElementById('subs').innerHTML='
No subscriptions yet.
';return;}
- let html='
Location
Plan
Status
Expires
Proxy creds
';
- for(const s of r){html+=`
${s.location}
${s.plan}
${s.status}
${s.expires_at||'—'}
${s.proxy_user||'—'}
`;}
- html+='
';document.getElementById('subs').innerHTML=html;
+ let h='';
+ for(const s of r){
+ h+=`