Skip to content

Deploy self hosting with docker compose behind nginx: TLS, per-client auth, and OAuth for Claude connectors - #36

Open
laazik wants to merge 10 commits into
silly-geese:masterfrom
laazik:nginx-front
Open

Deploy self hosting with docker compose behind nginx: TLS, per-client auth, and OAuth for Claude connectors#36
laazik wants to merge 10 commits into
silly-geese:masterfrom
laazik:nginx-front

Conversation

@laazik

@laazik laazik commented Aug 13, 2026

Copy link
Copy Markdown

This adds a Docker Compose deployment that runs estonian-mcp behind nginx, with certbot for Let's Encrypt certificates. Until now the ASGI wrapper in server.py was the only thing between the internet and the Python process, and it supports exactly one bearer token. nginx now terminates TLS and absorbs malformed requests, slow-client attacks, oversized bodies, connection floods and credential stuffing before any of it reaches uvicorn.

It also holds as many tokens as there are clients, each with its own name in the access log, its own rate-limit bucket, and revocation that is one deleted line plus a reload. The app container is no longer published to the host: it is reachable only from nginx over an internal network, and it keeps its own bearer auth on that hop so it is not an open server if the network is ever misconfigured.

The second larger addition is an OAuth facade, because Claude's custom connector cannot send a static Authorization header and runs OAuth discovery instead. nginx serves protected-resource and authorization-server metadata plus authorize and token endpoints.

The token endpoint is the one piece that is not plain nginx config, because Claude authenticates with client_secret_post and nginx core cannot read a request body. That is handled by njs, nginx's own JavaScript module, in about 40 lines; it accepts client_secret_basic as well, so curl and conforming clients keep working.

NB! This is not a full fledged OAuth but rather naive implementation where the client credentials either for individual accounts or team accounts are used to fetch static tokens!

Has been tested in actual live environment and works as expected.

Marek Laasik added 7 commits August 13, 2026 13:26
This commit adds the nginx token frontend to the mcp server, which includes setting up the Docker Compose configuration, creating deployment scripts, and adding documentation. The nginx token frontend provides client authentication and rate control, enhancing the security and performance of the mcp server.
This commit adds an OAuth facade for the Anthropic Claude connector, which cannot send a static Authorization header. The facade allows the connector to authenticate using OAuth credentials instead.
This commit adds an OAuth facade for the Anthropic Claude connector, which cannot send a static Authorization header. The facade allows the connector to authenticate using OAuth credentials instead.
… a map file

The OAuth client secret is now stored as a SHA-256 digest in a map file instead of being stored in an htpasswd file. This change was made to improve security and to make the OAuth client secret handling more consistent with the rest of the system. The njs module will now compare the SHA-256 digest of the client secret presented by the client with the stored digest.
Copilot AI lite review requested due to automatic review settings August 13, 2026 15:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a self-hosting deployment for estonian-mcp using Docker Compose with an nginx edge proxy that terminates TLS (via Let’s Encrypt/certbot), enforces per-client bearer auth + rate limiting, and provides a minimal OAuth facade (implemented with nginx njs) for clients that can’t send static Authorization headers (e.g., Claude custom connectors).

Changes:

  • Add a Compose stack (app + nginx + certbot) that keeps the app off host-published ports and puts TLS, auth, and rate limiting at the edge.
  • Add nginx configuration/templates and njs handler to implement per-client token auth and an OAuth-like token endpoint for discovery-based clients.
  • Add operator scripts + docs for issuing/revoking client credentials and bootstrapping/renewing certificates, plus supporting repo hygiene (.gitignore/.gitattributes/.dockerignore).

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Dockerfile Ensures /data exists and is writable by the non-root runtime user for persisted metrics.
docker-compose.yaml New Compose stack wiring app/nginx/certbot, internal networking, and mounts.
deploy/revoke-client.sh Script to revoke a client across all credential files.
deploy/README.md Deployment/operator documentation for nginx + Compose + OAuth facade.
deploy/nginx/templates/mcp.conf.template Nginx config template: TLS termination, auth, rate limiting, MCP proxying, OAuth metadata endpoints, and token endpoint wiring.
deploy/nginx/secrets/tokens.map.example Example token map file for nginx map-based auth.
deploy/nginx/reload-loop.sh Periodic nginx reload script to pick up renewed certificates.
deploy/nginx/njs/oauth.js njs token endpoint implementation to support client_secret_post and client_secret_basic.
deploy/nginx/https-port-suffix.envsh Entrypoint hook to compute a redirect port suffix for non-443 HTTPS.
deploy/nginx/Dockerfile Custom nginx image with njs module and entrypoint hooks.
deploy/new-token.sh Script to mint a static bearer token client entry.
deploy/new-oauth-client.sh Script to mint OAuth facade client credentials (secret + access token + bearer token map line).
deploy/local-cert.sh Helper to create a self-signed cert for local testing on non-80/443 ports.
deploy/lib.sh Shared credential/map-file helper functions.
deploy/init-letsencrypt.sh Bootstrap script to obtain the initial Let’s Encrypt cert by starting nginx with a throwaway cert.
.vscode/settings.json Editor excludes for common generated/config files.
.gitignore Ignore deployment secrets/state and local editor config (with allowlist exceptions).
.gitattributes Enforces LF line endings for scripts/templates to avoid CRLF issues in containers.
.env.example New example env file for Compose deployment variables.
.dockerignore Excludes deployment artifacts and env files from the app image build context.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread deploy/nginx/reload-loop.sh Outdated
Comment thread deploy/nginx/templates/mcp.conf.template Outdated
Comment thread docker-compose.yaml
Comment thread deploy/new-oauth-client.sh Outdated
Marek Laasik added 3 commits August 13, 2026 18:41
The OAuth authorization endpoint is added to handle client authorization requests. The rate limiting documentation is improved to better explain the rate limiting mechanism. The phase ordering is enhanced to ensure that rate limiting is applied correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants