onaci/caddy is a http to https proxy based on caddy.
It is set up to:
Contents of this README:
onaci/caddy Internals
This example uses the built-in local user authentication with HTTP challenge validation for requesting LetsEncrypt certificates.
Note: in a docker-compose environment, the labels that are used for routing live on the top-level of the service definition.
Warning: If you deploy Caddy via docker-compose, then the access logs and X-Forwarded-For headers will always contain the IP address of the docker network gateway. This is a limitation of docker networking, and means that docker-compose is NOT a suitable production deployment method for Caddy: please use swarm instead.
version: "3.8"
networks:
caddy-ingress:
attachable: true
name: caddy-ingress
volumes:
caddy-config:
caddy-data:
services:
caddy:
container_name: caddy
image: onaci/caddy:latest
environment:
AUTH_UI_LOGO_URL: https://static.example.com/logo.svg
AUTH_UI_LOGO_DESCRIPTION: "My Authentication Portal"
AUTH_UI_SUPPORT_URL: mailto:[email protected]
DNS_DOMAIN: example.com
TLS_EMAIL: [email protected]
networks:
- caddy-ingress
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy-config:/config
- caddy-data:/data
landing_page:
container_name: "landing"
image: onaci/echo:latest
labels:
# results in https://example.com with no authentication required.
virtual.host: "@"
virtual.port: 80
virtual.link_title: "landing page"
# requires authentication and a specific role to access https://example.com/data/
virtual_0.host: "@"
virtual_0.path: "/data*"
virtual_0.port: 80
virtual_0.auth_roles: "data-viewer"
virtual_0.link_title: "Data Explorer"
virtual_0.link_path: "/data/"
virtual_0.link_icon: "star"
networks:
- caddy-ingress
microservice:
container_name: "api"
image: onaci/echo:latest
labels:
# results in https://api.example.com with authentication required, and
# cross-site access permitted only from the landing page app.
virtual.host: api
virtual.auth: true
virtual.cors_allow_origin: https://example.com
virtual.port: 80
# redirects the /help path on the API app to landing page equivalent.
virtual_0.host: api
virtual_0.path: /help
virtual_0.redirect: "https://example.com{uri} 303"
networks:
- caddy-ingress
This example is similar to the docker-compose example, but uses configs and secrets to securely provide a custom authentication backend-or several, authentication token secret and uses DNS Challenge verificatation via the Gandi LiveDNS API when requesting its LetsEncrypt certificates.
Note: in a docker-swarm stack (or docker service create) environment, the labels that are used for routing live in the deploy section of each service definition.
Warning: to ensure that Caddy is able to identify the real IP address for your end-users, you need to ensure that Caddy is deployed in global mode AND that Caddy's published ports use host mode networking. Without both of these, the requesting IP address will always appear as the IP of the docker network gateway (just like with docker compose). You can use placement constraints to ensure that Caddy only runs on the swarm node(s) that DNS for your applications hostnames resolves to. This is a known issue with docker swarm, and any other swarm-deployed web server (e.g. traefik) will have the same constraint.
Caveat: the above workaround for ensuring Caddy gets the real requester-IP to work with still does not work in the combination of Docker Desktop for Windows and WSL, but should be fine with Docker Engine on Linux.
The following example application stack can be saved to a file called docker-swarm.yml, and then deployed using docker stack deploy -c docker-swarm.yml caddy.
version: "3.8"
secrets:
caddy-auth-backend:
file: /path/to/custom-backend.caddyfile
caddy-secret-key:
file: /path/to/caddy-key.txt
gandi-access-token:
file: /path/to/gandi-key.txt
networks:
caddy-ingress:
attachable: true
name: caddy-ingress
driver: overlay
volumes:
caddy-config:
caddy-data:
services:
caddy:
deploy:
mode: global
placement:
constraints:
- node.role == manager
restart-policy:
condition: any
environment:
AUTH_SETTINGS_GLOBAL: /config/caddy/auth/custom-global-settings.caddyfile
AUTH_SETTINGS_PORTAL: /config/caddy/auth/custom-portal-settings.caddyfile
AUTH_TOKEN_SECRET_FILE: /run/secrets/caddy-secret-key
AUTH_UI_LOGO_URL: https://static.example.com/logo.svg
AUTH_UI_LOGO_DESCRIPTION: "My Authentication Portal"
AUTH_UI_SUPPORT_URL: mailto:[email protected]
DNS_DOMAIN: example.com
GANDI_ACCESS_TOKEN_FILE: /run/secrets/gandi-access-token
TLS_EMAIL: [email protected]
image: onaci/caddy:latest
networks:
- caddy-ingress
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
secrets:
caddy-auth-backend:/config/caddy/auth/custom-backend.caddyfile
caddy-secret-key:/run/secrets/caddy-secret-key
gandi-access-token:/run/secrets/gandi-access-token
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy-config:/config
- caddy-data:/data
landing_page:
container_name: "landing"
image: onaci/echo:latest
deploy:
restart-policy:
condition: on-failure
mode: replicated
replicas: 2
labels:
# results in https://example.com with no authentication required.
virtual.host: "@"
virtual.port: 80
virtual.link_title: "landing page"
# requires authentication and a specific role to access https://example.com/data/
virtual_0.host: "@"
virtual_0.path: "/data*"
virtual_0.port: 80
virtual_0.auth_roles: "data-viewer"
virtual_0.link_title: "Data Explorer"
virtual_0.link_path: "/data/"
virtual_0.link_icon: "star"
networks:
- caddy-ingress
microservice:
container_name: "api"
image: onaci/echo:latest
deploy:
restart-policy:
condition: on-failure
mode: replicated
replicas: 2
labels:
# results in https://api.example.com with authentication required, and
# cross-site access permitted only from the landing page app.
virtual.host: api
virtual.auth: true
virtual.cors_allow_origin: https://example.com
virtual.port: 80
# redirects the /help path on the API app to landing page equivalent.
virtual_0.host: api
virtual_0.path: /help
virtual_0.redirect: "https://example.com{uri} 303"
networks:
- caddy-ingress
onaci/caddy needs to be able to interrogate the labels of all other containers that share its network. To enable this, you need to bind-mount the docker socket of your host to /var/run/docker.sock in the container.
There is always a security risk with this sort of privileged configuration; refer to the following links for more information:
onaci/caddy in the way it needs docker-socket access)
You should mount two persistent volumes to your onaci/caddy container. The mount points are:
/config for all configuration files, including the files that the caddy-docker-proxy module creates on the fly.
Note: there are existing files in this directory which are important, so make sure you do not specify the nocopy attribute on this volume./data for all data files, including generated or downloaded SSL certificates. Having this volume is particularly important if you are using LetsEncrypt certificates or otherwise onaci/caddy will attempt to re-download and request certificates every time it starts, and that will trigger the LetsEncrypt rate limiting, which could lock you out of being able to obtain any certificates for weeks.
The following environment variables may be configured on the onaci/caddy container to control how it behaves:
ACCESS_LOG_FORMAT: the format for the access log messages, which are written to the onaci/caddy container's stdout stream. Must be one of either console or json: The default is json.
ACCESS_LOG_LEVEL: how verbose the access logs will be: accepts values of DEBUG, INFO, WARN, ERROR, PANIC or FATAL. If you omit this variable or set it to an empty string, then Access Logging will be completely disabled. (The default is INFO)
Note 1 Access log messages have levels of INFO for successful access requests and ERROR for unsuccessful requests. Choose your production level accordingly. (and note that you can suppress all access logging by setting this to FATAL)
Note 2: The access logs have been configured to redact sensitive values, such as the user ID (which is often an email address) or the values of the Authorization header and cookies either provided with a request or set by the response.
Note 3: That redaction only applies to access logs written by this container! If your upstream containers are also logging access, then those containers' loggs may container may still contain sensitive information like usernames, user IDs and email addresses which are passed upstream in claims headers. You should be careful to secure all your logs in accordance with privacy laws in your jurisdiction. (For Australia, see the Australian Privacy Principles)
ACL_LOG_ALLOW: The log-level to use for messages related to successful authorizations. Accepts values of DEBUG, INFO, WARN, ERROR, PANIC or FATAL, with the default being DEBUG.
ACL_LOG_DENY: The log-level to use for messages related to failed authorizations. Accepts values of DEBUG, INFO, WARN, ERROR, PANIC or FATAL, with the default being WARN.
ADMIN: set this to 'true' to enable the Caddy Admin API at port 2019. (If you don't need the ADMIN API - and most things don't - then leave this variable unset.)
AUTH_SETTINGS_GLOBAL: see Authentication Backends
AUTH_SETTINGS_PORTAL: see Authentication Backends
AUTH_URL_PATH: The path part of the authentication portal URI after https://auth.${DNS_DOMAIN}. Defaults to /. Set this to /<backend-provider>/<backend-realm> if you are using a custom back end that has its own login dialog (e.g. an OAuth 2.0 or SAML backend) and you wish to bypass caddy's dialog. Leave this unset for local or LDAP backends.
AUTH_COOKIE_LIFETIME: The lifespan of the persistent authentication cookie in seconds. Defaults to 86400 (24 hours). The cookie will be named access_token.
AUTH_TOKEN_LIFETIME: The lifespan of the ephemeral JWT Token in seconds. Defaults to 3600 (one hour).
AUTH_TOKEN_SECRET: The secret key used to verify that the JWT token was created by this application. You should set this with a custom value which is specific to your deployment!
AUTH_TOKEN_SECRET_FILE: If you wish to provide your AUTH_TOKEN_SECRET value by way of a bind-mount or docker-secret file, then you can set this variable to the absolute path of the mounted file, and the container will populate the AUTH_TOKEN_SECRET from the contents of your file as it starts up.
AUTH_UI_CSS_FILE: absolute path to a CSS stylesheet file that you have bind-mounted or config-mounted to the onaci/caddy container to override default authentication dialog styles. Defaults to empty, for no custom CSS in use.
AUTH_UI_JS_FILE: absolute path to a javascript file that you have bind-mounted or config-mounted to the onaci/caddy container and which the authentication dialog should use. Useful for adding Google Analytics or similar code. Defaults to empty, for no custom javascript in use.
AUTH_UI_LOGO_DESCRIPTION: title text for the logo image that is displayed on the authentication dialog. Defaults to Authentication Portal, but you may wish to include the name of your application in that.
AUTH_UI_LOGO_URL: absolute URL for a logo image (hosted elsewhere!) that should be displayed on the authentication dialog. Defaults to the internal URL for the Caddy logo.
AUTH_UI_SUPPORT_URL: absolute URL to your an existing support page for your application which the 'Contact Support' link on the authentication dialog should be redirected to. This can be a mailto URL (like mailto:[email protected] if you do not have an existing support page.
DNS_DOMAIN: the base-domain which should be used for any application which does not configure a .domain label. This must be compatible with any custom SSL certificates you configure (see below).
ERROR_LOG_FORMAT: the format for Caddy's own log messages, which are written to the onaci.caddy container's stderr stream. Must be one of console or json. The default is json.
ERROR_LOG_LEVEL: how verbose Caddy's log (written to stderr) should be. Must be one of DEBUG, INFO, WARN, ERROR, PANIC or FATAL. The default is INFO.
WARN in production!FAVICON_URL: URL for a custom favicon image to be served as /favicon.ico for all applications, including the authentication page(s).
FAVICON_MIME: The MIME type of the custom favicon URL given by FAVICON_URL.
GANDI_ACCESS_TOKEN: the value of a personal access token (PAT) for the Gandi v5 LiveDNS API.
DNS_DOMAIN is registered with gandi.net.DNS_DOMAIN and have the Manage domain name technical configurations permission on that domain.caddy-dns-gandi plugin.GANDI_ACCESS_TOKEN_FILE: If you wish to provide your GANDI_ACCESS_TOKEN value by way of a bind-mount or docker-secret file, then you can set this variable to the absolute path of the mounted file, and the container will populate the GANDI_ACCESS_TOKEN from the contents of your file as it starts up.
HTTPS_MANDATORY_SECONDS: The length of time (in seconds) which client browsers should require hosted sites to remain accessible via HTTPS only. Used for Expect-CT and HSTS headers. Default value is 2592000 (=> 30 days). Explicitly set this to an empty string to stop automatically including those response headers.
LEGACY_COMPATIBILITY_MODE: can be set to true to make onaci/caddy understand container labels that were originally created to work with cirri/infra (the precursor to this image).
MATCHER_HEADER: the name of a custom HTTP header that can be injected into responses to indicate which caddyfile matcher the response was generated from. This will be included in access-log messages, and so can be used to filter verbose access logs. Defaults to X-Caddy-Matcher. Because these headers will be visible to callers, they are only injected for routes being debugged, or for healthcheck requests from trusted reverse proxies.
SMTP_HOSTNAME: The hostname of a SMTP server that your onaci/caddy server can use to send emails, e.g. for password recovery when using a local user backend. Defaults to an empty string, which means email-sending is not supported.
SMTP_PASSWORD: The password to use for authentication with the SMTP_HOSTNAME, if that variable has been configured. Defaults to an empty string (no authentication required).
SMTP_PASSWORD_FILE: If you wish to provide your SMTP_PASSWORD value by way of a bind-mount or docker-secret file, then you can set this variable to the absolute path of the mounted file, and the container will populate the SMTP_PASSWORD from the contents of your file as it starts up.
SMTP_PORT: The port that the SMTP_HOSTNAME server communicates on. Defaults to 25.
SMTP_PROTOCOL: The protocol that the SMTP_HOSTNAME server connection starts with. Defaults to smtp for StartTLS: set this to smtps if you SMTP server needs TLS (no insecure upgrade).
SMTP_SENDER: The email address that emails originating from this server should be from. Defaults to no-reply@${SMTP_HOSTNAME}.
SMTP_USERNAME: The username to use for authentication with the SMTP_HOSTNAME if that variable has been configured. Defaults to an empty string (no authentication required).
TLS_EMAIL: The email address that LetsEncrypt certificates should be registered to.
TLS_LOCAL_CRT: The path to a local, cusom SSL certificate file.
TLS_LOCAL_KEY: The path to a local, custom SSL certificate's key file.
TLS_LOG_LEVEL: The log-level to include for messages related to acquisition and renewal of TLS certificates. Accepts values of DEBUG, INFO, WARN, ERROR, PANIC or FATAL, with the default being INFO, and overrides ERROR_LOG_LEVEL for messages in this category.
TLS_STAGING: Set this to true if all LetsEncrypt certificates should use the ACME v2 Staging Environment, rather than the production one. This is not subject to the same rate limits, and can be useful in development and testing environments. Omit this variable entirely to request production-level certificates.
TRUSTED_PROXIES: Set this to a space-seperated list of IP Ranges (CIDRs) for any reverse proxy servers in front of your Caddy server that you trust to have set the X-Forwarded-For header correctly. Caddy will keep the trusted X-Forwarded-For header when passing requests to application containers instead of setting X-Forwarded-for to Caddy's own IP address. The default value is the empty string (no trusted proxies).
onaci/caddy will always use HTTPS for all its traffic. Depending on which environment variables you configure, it can use any one of 4 different methods of working out which TLS (SSL) Certificates should be used by default.
See the Caddy tls directive docs for more detailed information about how Caddy works with certificates, and the sub-sections below for which environment variables to use for your deployment.
If you already have a SSL certificate and associated key file - e.g. if you are behind a reverse proxy server that has already generated one for you.
TLS_LOCAL_CRT environment variable to the absolute path of your CRT file.TLS_LOCAL_KEY environment variable to the absolute path of your Key file
This only works if your host can accept requests from the public internet: it will not work inside a corporate intranet!
TLS_EMAIL environment variable to a valid email address for a sysadmin that will be looking after this server. The resulting certificate will be registered to that person.TLS_STAGING environment variable to true to force the use of LetsEncrypt staging certificates rather than production ones. These are not subject to the same rate limits, and can be a good idea in testing and staging environments. Omit this variable entirely to use production certificates.Content type
Image
Digest
sha256:1b5a247d2…
Size
49.9 MB
Last updated
3 months ago
docker pull onaci/caddy