Dotege is a tool to automatically generate configuration files from templates based on running docker containers, and optionally signal another container when it has done so.
Out of the box it supports writing a HAProxy configuration file with
appropriate entries for all containers with com.chameth.*
labels.
This enables automatic reverse proxying to any container with the
relevant networks.
Dotege 1.0 supported a number of features removed from v2, including specific support for generating ACLs and mechanisms for obtaining and deploying TLS certificates from ACME servers. These features were removed so that Dotege can focus on the core premise of generating templates.
Dotege is configured using environment variables:
DOTEGE_POLL
-
If set, Dotege will poll the Docker engine at this interval. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h", and can be combined e.g.
1m30s
. If not set, Dotege will poll once on startup, and then rely on events from the Docker engine to update its state. DOTEGE_PROXYTAG
-
Only containers with a matching
com.chameth.proxytag
label will be processed by Dotege. This allows you to run multiple instances that handle separate containers. If not specified, any container without acom.chameth.proxytag
label will be included. DOTEGE_SIGNAL_CONTAINER
-
The name of a container that should be sent a signal when the template is changed. No signal is sent if not specified.
DOTEGE_SIGNAL_TYPE
-
The type of signal to send to the
DOTEGE_SIGNAL_CONTAINER
. Defaults toHUP
. DOTEGE_TEMPLATE_DESTINATION
-
Location to write the templated configuration file to. Defaults to
/data/output/haproxy.cfg
. DOTEGE_TEMPLATE_SOURCE
-
Path to a template to use to generate configuration. Defaults to
./templates/haproxy.cfg.tpl
, which is a bundled basic template for generating HAProxy configurations.
Dotege operates by parsing labels applied to docker containers. It understands the following:
com.chameth.headers
-
Specifies response headers to be sent to the client for all requests to the container. Any label with this as a prefix will be used, so multiple headers can be specified as
com.chameth.headers.1
, orcom.chameth.headers-frame-options
, for example. com.chameth.proxy
-
The port on which the container is listening for requests. If
com.chameth.vhost
is specified andcom.chameth.proxy
is not and the container exposes a single non-bound port then Dotege will automatically use that port. That means you do not need to manually label the port for an nginx server, for instance, as the nginx image exposes port 80 (only). com.chameth.proxytag
-
Arbitrary tag to control which containers an instance of Dotege will deal with. If specified, the container will be ignored by any instance of Dotege that does not have the same value passed in using the
DOTEGE_PROXYTAG
env var. Note this should also be set on the container specified in DOTEGE_SIGNAL_CONTAINER if set, or it will be ignored and not restarted. com.chameth.vhost
-
Comma- or space-delimited list of hostnames that the container will handle requests for.
version: '3.5'
services:
dotege:
image: ghcr.io/csmith/dotege
restart: always
volumes:
- data:/data/config
- config:/data/output
- /var/run/docker.sock:/var/run/docker.sock
environment:
DOTEGE_SIGNAL_CONTAINER: dotege_haproxy_1
DOTEGE_SIGNAL_TYPE: USR2
DOTEGE_TEMPLATE_SOURCE: ./templates/haproxy.cfg.tpl
DOTEGE_TEMPLATE_DESTINATION: /data/output/haproxy.cfg
haproxy:
image: haproxy:2.0.1
restart: always
volumes:
- config:/usr/local/etc/haproxy:ro
ports:
- 443:443
- 80:80
networks:
- web
networks:
web:
external: true
volumes:
data:
config:
This creates an instance of Dotege, configured to generate a config for HAProxy using the built-in template.
The haproxy instance has read-only access to the config volume that will be
populated by Dotege, and Dotege will send it the USR2
signal whenever
the config changes. With the default haproxy image this will cause it
to reload the configuration.
Container names must be resolvable from the haproxy container with the default template. This means the haproxy container should be on the same network as the containers it’s proxying to. I recommend creating a global 'web' network (or similar) that all web-facing containers sit in.
Dotege comes with two templates out of the box - one to create a working HAProxy config, and one to output a list of domains suitable for use with a tool like Dehydrated.
Dotege uses Go’s built-in text/template package which provides extensive documentation for the template syntax itself. If you’ve used Smarty, Jinja or other templating systems the syntax should look pretty similar.
Dotege provides the following data to templates:
-
Containers - a map of container IDs to the container’s details:
-
Id - the ID of the container
-
Headers - map of header names to values from
com.chameth.headers
labels -
Labels - map of all label names to values
-
Name - the name of the container
-
Port - the port the container accepts traffic on, or -1 if it couldn’t be determined
-
Ports - all ports exposed by the container
-
ShouldProxy - boolean indicating whether the container has a hostname and port
-
-
Hostnames - a map of known primary hostnames to their details:
-
Alternatives - a map of alternate names for this hostname
-
AuthGroup - the name of the group users must be a member of to access this hostname (if RequiresAuth is true)
-
Containers - all containers that accept traffic for this hostname
-
Headers - map of header names to values from
com.chameth.headers
labels -
Name - the name of the primary hostname
-
Most templates will want to act on the Hostnames
data primarily, as this groups up
containers that accept traffic to the same domains, and avoids having to deal with
containers that aren’t configured for use with Dotege.
Contributions are welcome! Please raise an issue if you have any feature requests or spot a bug, or open a pull request if you want to suggest any code changes.
Dotege is licensed under the MIT licence. A full copy of the licence is available in the LICENCE file.
Dotege makes use of a number of third-party libraries. See the go.mod file
for a list of direct dependencies. Users of the docker image will find a copy of the
relevant licence and notice files under the /notices
directory in the image.