Credentials were hardcoded as bcrypt hashes directly in middlewares.yml and Caddyfile. Auth now loads from environment variables or an external secrets manager, with no secrets in any committed file.
Auth changes
Traefik — switched from inline users: to usersFile::
# dynamic/middlewares.ymlbasic-auth:basicAuth:usersFile:/etc/traefik/secrets/users # generated by `make gen-users-file`removeHeader:true
secrets/users is generated at deploy time from .env via grep/cut (not shell sourcing — bcrypt $ signs survive intact). secrets/ is git-ignored and container-mounted read-only.
Caddy — native env-var substitution in Caddyfile:
{$PROXY_DOMAIN:mac.local} {
handle_path /n8n/* {
basicauth * {
{$PROXY_AUTH_USER:admin} {$PROXY_AUTH_HASH}
}
...
}
}
env_file: .env in docker-compose.yml passes variables to the container. Domain is also env-driven.
Both stacks support loading from a secrets vault before invoking make:
export PROXY_AUTH_HASH="$(vault kv get -field=hash secret/proxy-auth)"
make gen-users-file && make up # Traefik
make up # Caddy reads directly from env
Makefiles
reverse-proxy/Makefile — top-level delegator (make traefik-up, make caddy-reload, etc.)
traefik/Makefile — setup, gen-certs, gen-hash, gen-users-file, trust-ca, up/down/restart/logs/health/clean
caddy/Makefile — same, plus reload; no gen-users-file needed
New docs
docs/quickstart-ubuntu.md — end-to-end guide for Ubuntu 24.04: Docker install, Avahi mDNS, host.docker.internal, firewall, and troubleshooting
docs/caddy-vs-traefik.md — feature comparison table with a per-use-case recommendation matrix
.env.example added to both stacks as the canonical credential template
Original prompt
Create a pull request in repository peterwwillis/ai-agent-coding targeting base branch main that adds a complete local reverse-proxy setup for both Traefik and Caddy, suitable for Linux and macOS, with offline operation and local TLS.
Goal
Provide ready-to-use configurations so the user can access local AI services by hostname + path prefix instead of remembering ports, e.g.:
https://<hostname>/ollama/
https://<hostname>/openwebui/
https://<hostname>/n8n/
Required file structure
Add files under:
reverse-proxy/traefik/
reverse-proxy/caddy/
reverse-proxy/scripts/
reverse-proxy/docs/
You may include additional supporting files if helpful.
Traefik deliverables
-
reverse-proxy/traefik/docker-compose.yml
- Run Traefik container.
- Expose TLS entrypoint on 443.
- Enable file provider for dynamic config.
- Mount
dynamic/ and certs/ directories.
-
reverse-proxy/traefik/dynamic/tls.yml
- Configure static TLS certificate/key file loading from mounted cert paths.
-
reverse-proxy/traefik/dynamic/middlewares.yml
- Include:
- Basic auth middleware (with clearly marked placeholder hash and instructions).
- Strip-prefix middlewares for each route.
- A protected chain middleware suitable for sensitive routes.
-
reverse-proxy/traefik/dynamic/routes.yml
- Route path prefixes to local services:
/ollama -> local Ollama
/llama-swap -> local llama-swap
/openwebui -> local Open WebUI
/n8n -> local n8n
/terminal -> local web terminal
/code -> local web vscode/code-server
/searxng -> local SearXNG
/llamacpp-rpc -> local llama.cpp RPC frontend/aggregator
/vnc -> local web VNC client
- Add sensible defaults and comments for macOS/Linux host reachability (
host.docker.internal, Linux alternatives).
- Ensure websocket-friendly proxy behavior.
Caddy deliverables
-
reverse-proxy/caddy/docker-compose.yml
- Run Caddy with mounted Caddyfile and certs.
- Expose 443.
-
reverse-proxy/caddy/Caddyfile
- Configure one example site block for
https://mac.local (document how to adapt hostname).
- Path-prefix reverse_proxy handlers for same services as above.
- Strip path prefixes before upstream where appropriate.
- Apply Basic Auth to sensitive routes (n8n, terminal, code, vnc) with placeholder hash.
- Keep config compatible with local/offline TLS via cert/key files.
Authentication/authorization
- Provide practical guidance and examples for:
- Basic auth (username/password)
- API token/header-based auth for selected prefixes
- If Traefik/Caddy native config is insufficient for strict header-value enforcement, include an optional local forward-auth pattern in docs with clear explanation.
TLS and offline requirements
- Must work without internet calls.
- Include docs for two local TLS approaches:
- Self-signed cert
- Local CA-signed cert (recommended) with trust-store instructions.
Scripts
Add helpful scripts in reverse-proxy/scripts/ (shell scripts) for:
- Generating local certs (self-signed and/or local CA flow).
- Generating bcrypt hashes for basic auth placeholders.
- Optional basic health-check script to validate mapped routes.
Scripts should be executable-friendly and documented.
Documentation
Add a comprehensive markdown guide at:
reverse-proxy/docs/README.md
README must include:
- Architecture overview and URL scheme.
- Service port assumptions and how to customize.
- Per-machine setup for macOS and Linux.
- How to run Traefik stack.
- How to run Caddy stack.
- Route table for all requested services.
- Auth setup (basic auth and token-forward-auth option).
- TLS setup and trust instructions.
- Troubleshooting section for common path-prefix and websocket issues.
- Security notes (especially for n8n/code-server/vnc exposure).
Quality bar
- Keep configs clean, commented, and production-minded for local LAN use.
- Ensure paths and file references are internally consistent.
- Prefer practical defaults; use placeholders where secrets are needed.
- Do not remove or alter unrelated existing repo content.
PR details
Use a concise descriptive PR title, e.g.:
"Add local reverse-proxy stacks (Traefik + Caddy) with TLS/auth for AI services"
This pull request was created from Copilot chat.
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.
Credentials were hardcoded as bcrypt hashes directly in `middlewares.yml` and `Caddyfile`. Auth now loads from environment variables or an external secrets manager, with no secrets in any committed file.
## Auth changes
**Traefik** — switched from inline `users:` to `usersFile:`:
```yaml
# dynamic/middlewares.yml
basic-auth:
basicAuth:
usersFile: /etc/traefik/secrets/users # generated by `make gen-users-file`
removeHeader: true
```
`secrets/users` is generated at deploy time from `.env` via `grep/cut` (not shell sourcing — bcrypt `$` signs survive intact). `secrets/` is git-ignored and container-mounted read-only.
**Caddy** — native env-var substitution in Caddyfile:
```
{$PROXY_DOMAIN:mac.local} {
handle_path /n8n/* {
basicauth * {
{$PROXY_AUTH_USER:admin} {$PROXY_AUTH_HASH}
}
...
}
}
```
`env_file: .env` in `docker-compose.yml` passes variables to the container. Domain is also env-driven.
Both stacks support loading from a secrets vault before invoking make:
```bash
export PROXY_AUTH_HASH="$(vault kv get -field=hash secret/proxy-auth)"
make gen-users-file && make up # Traefik
make up # Caddy reads directly from env
```
## Makefiles
- `reverse-proxy/Makefile` — top-level delegator (`make traefik-up`, `make caddy-reload`, etc.)
- `traefik/Makefile` — `setup`, `gen-certs`, `gen-hash`, `gen-users-file`, `trust-ca`, `up/down/restart/logs/health/clean`
- `caddy/Makefile` — same, plus `reload`; no `gen-users-file` needed
## New docs
- `docs/quickstart-ubuntu.md` — end-to-end guide for Ubuntu 24.04: Docker install, Avahi mDNS, `host.docker.internal`, firewall, and troubleshooting
- `docs/caddy-vs-traefik.md` — feature comparison table with a per-use-case recommendation matrix
- `.env.example` added to both stacks as the canonical credential template
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
> Create a pull request in repository `peterwwillis/ai-agent-coding` targeting base branch `main` that adds a complete local reverse-proxy setup for both Traefik and Caddy, suitable for Linux and macOS, with offline operation and local TLS.
>
> ## Goal
> Provide ready-to-use configurations so the user can access local AI services by hostname + path prefix instead of remembering ports, e.g.:
> - `https://<hostname>/ollama/`
> - `https://<hostname>/openwebui/`
> - `https://<hostname>/n8n/`
>
> ## Required file structure
> Add files under:
> - `reverse-proxy/traefik/`
> - `reverse-proxy/caddy/`
> - `reverse-proxy/scripts/`
> - `reverse-proxy/docs/`
>
> You may include additional supporting files if helpful.
>
> ## Traefik deliverables
> 1. `reverse-proxy/traefik/docker-compose.yml`
> - Run Traefik container.
> - Expose TLS entrypoint on 443.
> - Enable file provider for dynamic config.
> - Mount `dynamic/` and `certs/` directories.
>
> 2. `reverse-proxy/traefik/dynamic/tls.yml`
> - Configure static TLS certificate/key file loading from mounted cert paths.
>
> 3. `reverse-proxy/traefik/dynamic/middlewares.yml`
> - Include:
> - Basic auth middleware (with clearly marked placeholder hash and instructions).
> - Strip-prefix middlewares for each route.
> - A protected chain middleware suitable for sensitive routes.
>
> 4. `reverse-proxy/traefik/dynamic/routes.yml`
> - Route path prefixes to local services:
> - `/ollama` -> local Ollama
> - `/llama-swap` -> local llama-swap
> - `/openwebui` -> local Open WebUI
> - `/n8n` -> local n8n
> - `/terminal` -> local web terminal
> - `/code` -> local web vscode/code-server
> - `/searxng` -> local SearXNG
> - `/llamacpp-rpc` -> local llama.cpp RPC frontend/aggregator
> - `/vnc` -> local web VNC client
> - Add sensible defaults and comments for macOS/Linux host reachability (`host.docker.internal`, Linux alternatives).
> - Ensure websocket-friendly proxy behavior.
>
> ## Caddy deliverables
> 1. `reverse-proxy/caddy/docker-compose.yml`
> - Run Caddy with mounted Caddyfile and certs.
> - Expose 443.
>
> 2. `reverse-proxy/caddy/Caddyfile`
> - Configure one example site block for `https://mac.local` (document how to adapt hostname).
> - Path-prefix reverse_proxy handlers for same services as above.
> - Strip path prefixes before upstream where appropriate.
> - Apply Basic Auth to sensitive routes (n8n, terminal, code, vnc) with placeholder hash.
> - Keep config compatible with local/offline TLS via cert/key files.
>
> ## Authentication/authorization
> - Provide practical guidance and examples for:
> - Basic auth (username/password)
> - API token/header-based auth for selected prefixes
> - If Traefik/Caddy native config is insufficient for strict header-value enforcement, include an optional local forward-auth pattern in docs with clear explanation.
>
> ## TLS and offline requirements
> - Must work without internet calls.
> - Include docs for two local TLS approaches:
> - Self-signed cert
> - Local CA-signed cert (recommended) with trust-store instructions.
>
> ## Scripts
> Add helpful scripts in `reverse-proxy/scripts/` (shell scripts) for:
> - Generating local certs (self-signed and/or local CA flow).
> - Generating bcrypt hashes for basic auth placeholders.
> - Optional basic health-check script to validate mapped routes.
>
> Scripts should be executable-friendly and documented.
>
> ## Documentation
> Add a comprehensive markdown guide at:
> - `reverse-proxy/docs/README.md`
>
> README must include:
> - Architecture overview and URL scheme.
> - Service port assumptions and how to customize.
> - Per-machine setup for macOS and Linux.
> - How to run Traefik stack.
> - How to run Caddy stack.
> - Route table for all requested services.
> - Auth setup (basic auth and token-forward-auth option).
> - TLS setup and trust instructions.
> - Troubleshooting section for common path-prefix and websocket issues.
> - Security notes (especially for n8n/code-server/vnc exposure).
>
> ## Quality bar
> - Keep configs clean, commented, and production-minded for local LAN use.
> - Ensure paths and file references are internally consistent.
> - Prefer practical defaults; use placeholders where secrets are needed.
> - Do not remove or alter unrelated existing repo content.
>
> ## PR details
> Use a concise descriptive PR title, e.g.:
> "Add local reverse-proxy stacks (Traefik + Caddy) with TLS/auth for AI services"
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
*This pull request was created from Copilot chat.*
>
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).