1 Background and motivation
My self-hosted applications had different access requirements. Some pages needed to remain public, while dashboards and internal tools needed a login. Adding authentication separately to each application would duplicate account handling and make it harder to revoke access consistently. Gatehouse places that decision at the reverse proxy, allowing an application to sit behind a common login without implementing its own sign-in interface.
The scope was deliberately small: protect services running under related subdomains using the proxy already in front of them. A parent-domain cookie lets one login cover those services, while per-site configuration determines which routes need verification. This makes the access boundary an infrastructure concern instead of a repeated feature in every project.
2 Verification flow
Before forwarding a request to a protected service, the reverse proxy sends an authentication subrequest to Gatehouse’s verify endpoint. The service evaluates the target domain, public-path exceptions, IP allowlists, and the caller’s session. An accepted request continues to the configured upstream; a browser without a valid session is directed to the login page.
Sessions are recorded in SQLite as well as represented by signed tokens. The database record matters because revocation must take effect before a token’s expiry: removing an active session causes a subsequent verification to fail. The browser dashboard exposes users, registered sites, and active sessions so that the same policy can be managed without editing every application.
3 Configuration and deployment
An interactive CLI collects the authentication domain, cookie domain, upstream services, and protection rules. It writes a common configuration together with environment settings, Docker Compose configuration, and the selected proxy’s routing rules. Caddy, Nginx, and Traefik use different forward-auth mechanisms, but they call the same verification service.
The authentication service runs in one Node container with SQLite, avoiding a separate database server for this workload. Application containers join the proxy network and are addressed by their service names and ports. Keeping policy generation in the CLI reduces the number of independently maintained configuration files, while the dashboard supports routine changes such as revoking a session.
4 Operational considerations
Gatehouse protects the proxy path, so exposing an application’s upstream port separately would bypass that boundary. Shared cookies also make the parent domain a trust boundary: the arrangement is intended for subdomains operated together. Availability of the gateway becomes a dependency for protected requests, and the SQLite data contains the persistent account and session state. Those are the tradeoffs behind simplifying authentication for the individual applications.