Angie Docker Proxy is a lightweight automatic reverse proxy for Docker Compose. It uses the Docker API to discover
containers, generates an Angie configuration with
docker-gen, redirects HTTP traffic to HTTPS, and obtains TLS certificates
through the Angie ACME module.
The image supports linux/amd64 and linux/arm64.
Before starting, point your domain to the Docker host and make sure ports 80 and 443 are publicly accessible.
services:
angie-proxy:
image: angiesoftware/proxy:latest
environment:
- [email protected]
- ANGIE_PROXY_NETWORK=proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- angie_acme:/var/lib/angie/acme
networks:
- proxy
app:
image: traefik/whoami
environment:
- VIRTUAL_HOST=app.example.com
- VIRTUAL_PORT=80
networks:
- proxy
networks:
proxy:
name: proxy
volumes:
angie_acme:
Start the services:
docker compose up -d
The proxy discovers the app container, obtains a certificate for app.example.com, and forwards HTTPS requests to
port 80 of the container. Configuration changes are applied automatically when containers start or stop.
docker compose logs -f angie-proxy
docker compose down
Certificates are stored in the angie_acme volume. Use docker compose down -v only when you also want to remove
them.
Dockerfile:
FROM ubuntu:24.04
ARG DOCKER_GEN_VERSION=0.16.0
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl tar gnupg \
&& install -d -m 0755 /etc/apt/keyrings \
&& curl --retry 8 --retry-all-errors --retry-delay 3 --connect-timeout 20 -fsSL https://angie.software/keys/angie-signing.gpg -o /etc/apt/keyrings/angie.gpg \
&& chmod 0644 /etc/apt/keyrings/angie.gpg \
&& . /etc/os-release \
&& echo "deb [signed-by=/etc/apt/keyrings/angie.gpg] https://download.angie.software/angie/ubuntu/24.04 ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/angie.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends angie \
&& curl --retry 8 --retry-all-errors --retry-delay 3 --connect-timeout 20 -fsSL "https://github.com/nginx-proxy/docker-gen/releases/download/${DOCKER_GEN_VERSION}/docker-gen-linux-amd64-${DOCKER_GEN_VERSION}.tar.gz" \
| tar -xz -C /usr/local/bin docker-gen \
&& chmod +x /usr/local/bin/docker-gen \
&& rm -rf /var/lib/apt/lists/*
COPY templates/angie.tmpl /etc/docker-gen/templates/angie.tmpl
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80 443
ENTRYPOINT ["/entrypoint.sh"]
docker-gen.entrypoint.sh script and angie.tmpl template.80 and 443 for proxying.entrypoint.sh script.entrypoint.sh:
#!/bin/sh
set -e
export DOCKER_HOST=unix:///tmp/docker.sock
mkdir -p /etc/angie /etc/angie/conf.d
mkdir -p /var/lib/angie/acme
docker-gen -watch=false /etc/docker-gen/templates/angie.tmpl /etc/angie/angie.conf
angie -t -c /etc/angie/angie.conf
angie -c /etc/angie/angie.conf
exec docker-gen -watch -notify "angie -s reload" /etc/docker-gen/templates/angie.tmpl /etc/angie/angie.conf
Angie reloads the configuration gracefully: existing connections continue to be handled by the old workers while new workers start using the updated configuration.
Inside the container, entrypoint.sh specifies where the Docker API is located:
export DOCKER_HOST=unix:///tmp/docker.sock
Creating directories for angie.conf and ACME.
Starting docker-gen in -watch mode.
templates/angie.tmpl:
events {}
http {
{{ $acmeURL := or (index .Env "ANGIE_ACME_URL") "https://acme-v02.api.letsencrypt.org/directory" }}
{{ $acmeEmail := or (index .Env "ANGIE_ACME_EMAIL") "[email protected]" }}
{{ $resolver := or (index .Env "ANGIE_RESOLVER") "1.1.1.1 8.8.8.8" }}
{{ $resolverValid := or (index .Env "ANGIE_RESOLVER_VALID") "300s" }}
{{ $proxyNetwork := or (index .Env "ANGIE_PROXY_NETWORK") "proxy" }}
resolver {{ $resolver }} valid={{ $resolverValid }};
{{ range $host, $containers := groupByMulti . "Env.VIRTUAL_HOST" "," }}
{{ $slug := replace (replace (toLower $host) "." "_" -1) "-" "_" -1 }}
acme_client {{ $slug }} {{ $acmeURL }}
email={{ $acmeEmail }}
challenge=http;
{{ end }}
access_log /dev/stdout;
error_log /dev/stderr notice;
server {
listen 80 default_server;
server_name _;
return 404;
}
{{ range $host, $containers := groupByMulti . "Env.VIRTUAL_HOST" "," }}
{{ $container := index $containers 0 }}
{{ $port := or (index $container.Env "VIRTUAL_PORT") "80" }}
{{ $slug := replace (replace (toLower $host) "." "_" -1) "-" "_" -1 }}
{{ range $network := $container.Networks }}
{{ if eq $network.Name $proxyNetwork }}
server {
listen 80;
server_name {{ $host }};
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name {{ $host }};
acme {{ $slug }};
ssl_certificate $acme_cert_{{ $slug }};
ssl_certificate_key $acme_cert_key_{{ $slug }};
location / {
proxy_pass http://{{ $network.IP }}:{{ $port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
}
}
{{ end }}
{{ end }}
{{ end }}
}
templates/angie.tmpl is a Go template for docker-gen. It is used to generate the final Angie configuration at
/etc/angie/angie.conf.
The template reads container metadata from Docker and selects services that have VIRTUAL_HOST and VIRTUAL_PORT
configured.
For every domain it finds, the template:
acme_client.example-demo.example.com -> example_demo_example_com.server block on port 443.$acme_cert_<slug> and $acme_cert_key_<slug>.proxy network.proxy_pass for the container's internal port specified by VIRTUAL_PORT.The template also uses the following settings from the proxy container:
ANGIE_ACME_EMAIL.ANGIE_ACME_URL.ANGIE_RESOLVER.ANGIE_RESOLVER_VALID.ANGIE_PROXY_NETWORK.When a new container with VIRTUAL_HOST and VIRTUAL_PORT appears, docker-gen regenerates angie.conf, after which
Angie reloads the configuration with angie -s reload.
Content type
Image
Digest
sha256:ce30651a5…
Size
44.8 MB
Last updated
about 2 months ago
docker pull angiesoftware/proxy