feat(proxy): add share_gate for Discord-group external access
Deploy Caddyfile to valhalla / deploy (push) Failing after 4s

Capability-URL snippet: external users visit ?k=SHARE_KEY once, Caddy
sets a 30-day HttpOnly cookie and redirects to the clean path. Subsequent
visits check the cookie only. Internal IPs and tailnet pass through
unconditionally. Applied to roms.ginnoir.com and romhacks.ginnoir.com.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ginnoir
2026-06-24 01:02:06 -05:00
co-authored by Claude Sonnet 4.6
parent 8510b1403e
commit f477465a1d
2 changed files with 25 additions and 2 deletions
+21 -2
View File
@@ -36,6 +36,25 @@
remote_ip 192.168.1.0/24 172.16.0.0/12 100.64.0.0/10 127.0.0.1
}
# Shared-link gate — external users visit ?k={$SHARE_KEY} once to get a 30-day cookie.
# Internal IPs and tailnet clients pass through unconditionally.
# Usage: import share_gate (replaces import internal_only on shared services)
(share_gate) {
route {
@has_key query k={$SHARE_KEY}
handle @has_key {
header Set-Cookie "share_access={$SHARE_KEY}; Path=/; Max-Age=2592000; HttpOnly; Secure; SameSite=Strict"
redir {http.request.uri.path} 302
}
@deny_external {
not remote_ip 192.168.1.0/24 172.16.0.0/12 100.64.0.0/10 127.0.0.1
not expression `{http.request.cookie.share_access} == "{$SHARE_KEY}"`
}
respond @deny_external "Access denied" 403
}
}
# =============================================================
# FOUNDRY VTT — public
# =============================================================
@@ -219,12 +238,12 @@ stash.ginnoir.com {
# serve node (roms-share.<tailnet>.ts.net), NOT public exposure here.
# =============================================================
roms.ginnoir.com {
import internal_only
import share_gate
reverse_proxy romm:8080
}
romhacks.ginnoir.com {
import internal_only
import share_gate
root * /srv/romhacks-wiki
file_server
}
+4
View File
@@ -2,3 +2,7 @@
# Cloudflare API token for Caddy's DNS-01 TLS challenge.
# Scoped token: Zone > DNS > Edit on the ginnoir.com zone only.
CF_API_TOKEN=cfut_ijIT9HDjXWKgd0dtnyLqxv8L3deB7hSDivSqquwp905a6c51
# Shared-link gate key — external users visit ?k=<value> once to get a 30-day cookie.
# Rotate: change value here, push, Portainer redeploys proxy stack, post new URL in Discord.
SHARE_KEY=8e5d9f1ca20a448b66ed171aea97d172