fix: systemd tangle-deploy missing ob-shell, add OIDC proxy, chmod fix

- Replaced stale /usr/local/bin/tangle-deploy (no (require 'ob-shell))
  with correct repo version — was writing crowdsecLapiKey: nil every 5min
- Added chmod +x to tangle-deploy.sh so git pull doesn't strip exec bit
- Added oidc-rewrite-proxy.py and oidc-proxy.service as tangle targets
- Documented Gitea OIDC discovery rewrite fix
- Added systemd unit detection to tangle-deploy restart logic
- Updated changelog
This commit is contained in:
Hermes
2026-06-06 19:15:36 +00:00
parent 5fff6d9cfa
commit e62bd88527

View File

@@ -70,6 +70,7 @@ if [ ! -f "$ORG_FILE" ]; then
echo "ERROR: $ORG_FILE not found in $REPO_DIR"
exit 1
fi
chmod +x "$0"
echo "=== Tangling $ORG_FILE ==="
emacs --batch -Q --load /usr/share/emacs/28.2/lisp/org/org-loaddefs.el \
--eval "(require 'org)" \
@@ -84,6 +85,10 @@ if [ -f /docker/appdata/traefik/traefik.yaml ] || \
echo 'Traefik config changed -- restarting...'
docker compose up -d traefik
fi
if [ -f /etc/systemd/system/oidc-proxy.service ]; then
echo 'Systemd unit changed -- reloading...'
systemctl daemon-reload
fi
if [ -f /docker/compose/docker-compose.yaml ]; then
echo 'Docker compose changed -- restarting all services'
docker compose up -d 2>&1 | tail -5
@@ -1238,6 +1243,101 @@ services:
- traefik.http.services.gitea.loadbalancer.server.port=3000
#+END_SRC
*** Gitea OIDC — Discovery Rewrite Proxy
Gitea's OIDC provider uses Authentik's auto-discovery URL to fetch
endpoint metadata. The discovery document returned by Authentik contains
internal Docker hostnames (like =http://authentik:9000/=) which the
browser cannot resolve. Gitea's =openidConnect= provider in v1.25.5 does
not support =CustomURLMapping= (confirmed from source
=providers_openid.go==CreateGothProvider= ignores the field), so the
redirect URLs must be rewritten externally.
The fix is a small HTTP proxy at =172.28.10.1:9122= (the Docker bridge
gateway) that intercepts the discovery request, fetches the real document
from Authentik at =172.28.10.33:9000=, and rewrites all internal URLs to
=https://auth.gharbeia.net=.
The proxy runs as a systemd service on production-1:
#+BEGIN_SRC ini :tangle /etc/systemd/system/oidc-proxy.service
[Unit]
Description=OIDC discovery rewrite proxy for Gitea
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /docker/compose/oidc-rewrite-proxy.py
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
#+END_SRC
The proxy lives at =/docker/compose/oidc-rewrite-proxy.py= on production-1:
#+BEGIN_SRC python :tangle /docker/compose/oidc-rewrite-proxy.py
#!/usr/bin/env python3
\"\"\"Minimal OIDC discovery rewrite proxy for Gitea's openidConnect provider.
Listens on 0.0.0.0:9122. Rewrites internal Authentik URLs to the public
HTTPS URL so Gitea redirects browsers to auth.gharbeia.net.
\"\"\"
import json
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.request import urlopen, Request
UPSTREAM = "http://172.28.10.33:9000"
PUBLIC = "https://auth.gharbeia.net"
DISCOVERY_PATH = "/application/o/gitea-oidc/.well-known/openid-configuration"
class RewriteHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path != DISCOVERY_PATH:
self.send_response(404)
self.end_headers()
self.wfile.write(b"Not found")
return
try:
upstream_url = f"{UPSTREAM}{DISCOVERY_PATH}"
req = Request(upstream_url, headers={"Accept": "application/json"})
with urlopen(req, timeout=5) as resp:
body = resp.read().decode()
body = body.replace(UPSTREAM, PUBLIC)
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(body.encode())
except Exception as e:
self.send_response(502)
self.end_headers()
self.wfile.write(f"Proxy error: {e}".encode())
def log_message(self, format, *args):
pass
if __name__ == "__main__":
server = HTTPServer(("0.0.0.0", 9122), RewriteHandler)
print("OIDC rewrite proxy listening on :9122", flush=True)
server.serve_forever()
#+END_SRC
The systemd service is tangled from the block above. After deploying, enable
with =systemctl enable --now oidc-proxy=.
Gitea's =OpenIDConnectAutoDiscoveryURL= in the database was updated to point
at the proxy:
: http://172.28.10.1:9122/application/o/gitea-oidc/.well-known/openid-configuration
** Infrastructure Services
Core data and networking services that everything depends on.
@@ -1632,6 +1732,23 @@ wp-config: =/docker/appdata/khaledfahmy-site/html/wp-config.php=
- Created infrastructure.org as source of truth
- Added Forward Auth to internal LAN routers
** [2026-06-06 Sat] Systemd tangle-deploy fixed — ob-shell, chmod, OIDC proxy
- Replaced stale /usr/local/bin/tangle-deploy (missing (require 'ob-shell))
with the correct repo version. Every 5-minute systemd timer cycle was
writing crowdsecLapiKey: nil because it couldn't evaluate the sh code block.
- Added chmod +x "$0" to tangle-deploy.sh so git pull doesn't strip the
executable bit, keeping cron + systemd reliable.
- Created and deployed oidc-rewrite-proxy.py: a discovery rewrite proxy that
intercepts Gitea's OIDC metadata request and rewrites internal
http://authentik:9000 URLs to https://auth.gharbeia.net.
- Registered oidc-proxy as a systemd service on production-1 (port 9122).
- Updated Gitea's OpenIDConnectAutoDiscoveryURL in the database to point
at the proxy (http://172.28.10.1:9122/...).
- Reverted Gitea's CustomURLMapping to {} (confirmed unused by source code).
- Fixed qBittorrent v5.2.1 persistent password — old PBKDF2 hash was not
recognized by the v5 upgrade. Set new password hash in config, updated
Sonarr and Radarr download client credentials via API.
** [2026-06-02 Tue] Gluetun port cleanup — only downloaders behind VPN
- Removed 20+ stale port mappings from gluetun (services migrated off VPN)
- Updated all internal router URLs: standalone services now referenced by