Skip to content

Docker Compose OAuth

This example deploys FrontMark as a static Nginx site and adds the dedicated OAuth/API proxy container for Sveltia CMS. The public CMS URL stays:

https://sigmax.dev/frontmark/admin/

Build the static image and the OAuth sidecar:

Terminal window
make image IMAGE=registry.example.com/frontmark:latest
make image_oauth OAUTH_IMAGE=registry.example.com/frontmark-oauth:latest

The generated CMS backend should contain:

api_root: https://sigmax.dev/frontmark/api/forgejo/v1
base_url: https://sigmax.dev/frontmark/oauth/forgejo
auth_methods:
- oauth
- token
services:
traefik:
image: traefik:v3.1
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.email=admin@example.com
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-letsencrypt:/letsencrypt
networks:
- frontmark
frontmark:
image: registry.example.com/frontmark:latest
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.http.routers.frontmark.rule=Host(`sigmax.dev`) && PathPrefix(`/frontmark`)
- traefik.http.routers.frontmark.entrypoints=websecure
- traefik.http.routers.frontmark.tls.certresolver=letsencrypt
- traefik.http.routers.frontmark.priority=10
- traefik.http.services.frontmark.loadbalancer.server.port=4321
networks:
- frontmark
frontmark-oauth:
image: registry.example.com/frontmark-oauth:latest
restart: unless-stopped
environment:
PUBLIC_GIT_ORIGIN: https://gitea.newkube.ia86.cc
FRONTMARK_BASE_PATH: /frontmark
SVELTIA_ALLOWED_ORIGINS: https://sigmax.dev
# Optional for confidential OAuth applications:
# GITEA_CLIENT_SECRET: ${GITEA_CLIENT_SECRET}
labels:
- traefik.enable=true
- traefik.http.routers.frontmark-oauth.rule=Host(`sigmax.dev`) && (PathPrefix(`/frontmark/oauth/forgejo`) || PathPrefix(`/frontmark/api/forgejo/v1`))
- traefik.http.routers.frontmark-oauth.entrypoints=websecure
- traefik.http.routers.frontmark-oauth.tls.certresolver=letsencrypt
- traefik.http.routers.frontmark-oauth.priority=100
- traefik.http.services.frontmark-oauth.loadbalancer.server.port=4321
networks:
- frontmark
volumes:
traefik-letsencrypt:
networks:
frontmark:
name: frontmark

The OAuth/API router has priority 100; the static catch-all has priority 10. That order matters because /frontmark/oauth/forgejo/* and /frontmark/api/forgejo/v1/* must never land on the static Nginx container.

Configure the Forgejo OAuth application with this redirect URI:

https://sigmax.dev/frontmark/admin/

If the OAuth app requires a confidential client secret, keep it only on the proxy container:

GITEA_CLIENT_SECRET=...

The static FrontMark container does not need the secret.

After docker compose up -d, check:

Terminal window
curl -I https://sigmax.dev/frontmark/admin/
curl https://sigmax.dev/frontmark/admin/config.json
curl https://sigmax.dev/frontmark/api/forgejo/v1/version

Expected results:

URLResult
/frontmark/admin/Static admin page.
/frontmark/admin/config.jsonapi_root points to /frontmark/api/forgejo/v1.
/frontmark/api/forgejo/v1/versionJSON response from Forgejo through the proxy.
/frontmark/oauth/forgejo/login/oauth/authorizeRedirects to the configured Forgejo OAuth authorization endpoint.