Automates the creation of [Argo Tunnels] Cloudflared
635
Hera monitors your Docker containers and automatically creates Cloudflare tunnels when containers start. When containers stop, tunnels are cleaned up automatically.
Single cloudflared process - Unlike the original Hera, this version uses one cloudflared process with dynamic ingress routing instead of one process per container. More efficient and easier to manage.
cloudflared login (opens browser URL)hera.hostname label starts, Hera adds a route to the tunneldocker run -d \
--name=hera \
--network=host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v hera-data:/data \
-e HERA_DOMAINS=example.com \
gerandonk/hera:latest
docker logs -f hera
Open the URL in your browser and authorize your domain
Start your containers with labels:
docker run -d \
--name=nginx \
--network=hera \
--label hera.hostname=web.example.com \
--label hera.port=80 \
nginx
web.example.com| Variable | Default | Description |
|---|---|---|
HERA_SWARM | false | Enable Docker Swarm mode |
HERA_HOST_LABEL | hera.hostname | Label for public tunnel hostname |
HERA_PORT_LABEL | hera.port | Label for container port |
HERA_TUNNEL_NAME | hera | Name of the Cloudflare tunnel |
HERA_DATA_DIR | /data | Directory for persistent data |
HERA_STALE_DAYS | 7 | Days before stale routes are removed (0 to disable) |
HERA_DOMAINS | (none) | Comma-separated additional domains to authorize |
| Label | Required | Description |
|---|---|---|
hera.hostname | Yes | Public hostname (e.g. web.example.com) |
hera.port | No | Container port (auto-detected if single EXPOSE) |
hera.proto | No | Protocol: http (default) or https |
hera.noTLSVerify | No | Skip TLS verification for self-signed certs (true/false) |
If your container exposes exactly one port via EXPOSE, Hera will auto-detect it. No need to set hera.port label.
# This works without hera.port label
docker run -d \
--name=nginx \
--network=hera \
--label hera.hostname=web.example.com \
--expose 80 \
nginx
If multiple ports are exposed, you must specify hera.port.
If your container serves HTTPS (e.g. port 443 with TLS), set hera.proto=https:
docker run -d \
--name=myapp \
--network=hera \
--label hera.hostname=secure.example.com \
--label hera.port=443 \
--label hera.proto=https \
myapp
For self-signed certificates, add hera.noTLSVerify=true:
docker run -d \
--name=myapp \
--network=hera \
--label hera.hostname=secure.example.com \
--label hera.port=443 \
--label hera.proto=https \
--label hera.noTLSVerify=true \
myapp
The generated cloudflared config:
ingress:
- hostname: secure.example.com
service: https://172.17.0.2:443
originRequest:
noTLSVerify: true
Set HERA_DOMAINS with comma-separated domain list:
docker run -d \
--name=hera \
--network=host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v hera-data:/data \
-e HERA_DOMAINS=example.com,example2.com,example3.com \
gerandonk/hera:latest
On first run:
example.com)example2.comexample3.comAfter all domains are authorized, restarts don't require login. Certificates are stored per-domain in /data/<domain>.pem.
Note: Each domain must be on the same Cloudflare account.
docker run -d \
--name=hera \
--network=host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v hera-data:/data \
-e HERA_DOMAINS=example.com \
gerandonk/hera:latest
version: '3.8'
services:
hera:
image: gerandonk/hera:latest
container_name: hera
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- hera-data:/data
environment:
- HERA_DOMAINS=example.com,example2.com
- HERA_STALE_DAYS=7
webapp:
image: nginx:latest
networks:
- hera
labels:
hera.hostname: webapp.example.com
hera.port: 80
api:
image: node:alpine
networks:
- hera
labels:
hera.hostname: api.example2.com
# hera.port not needed if single EXPOSE
secure:
image: nginx:alpine
networks:
- hera
labels:
hera.hostname: secure.example.com
hera.port: 443
hera.proto: https
hera.noTLSVerify: "true"
volumes:
hera-data:
networks:
hera:
# Container with valid TLS cert
docker run -d \
--name=webapp \
--network=hera \
--label hera.hostname=web.example.com \
--label hera.port=443 \
--label hera.proto=https \
nginx
# Container with self-signed cert
docker run -d \
--name=internal \
--network=hera \
--label hera.hostname=internal.example.com \
--label hera.port=8443 \
--label hera.proto=https \
--label hera.noTLSVerify=true \
myapp
version: "3.8"
services:
hera:
image: gerandonk/hera:latest
environment:
- HERA_SWARM=1
- HERA_DOMAINS=example.com
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- hera-data:/data
networks:
- hera
deploy:
placement:
constraints:
- node.role == manager
nginx:
image: nginx
networks:
- hera
deploy:
labels:
- "hera.hostname=web.example.com"
- "hera.port=80"
volumes:
hera-data:
networks:
hera:
external: true
By default, stopped container routes are removed after 7 days. Configure with HERA_STALE_DAYS:
# Remove after 3 days
docker run -d ... -e HERA_STALE_DAYS=3 ...
# Disable cleanup (routes stay forever)
docker run -d ... -e HERA_STALE_DAYS=0 ...
When a container stops, Hera logs:
Container offline, route web.example.com will be cleaned up after 7 days
Every hour, Hera checks and removes stale routes.
Content type
Image
Digest
sha256:4139ffd89…
Size
31.2 MB
Last updated
6 days ago
docker pull gerandonk/hera