gerandonk/hera

By gerandonk

Updated 6 days ago

Automates the creation of [Argo Tunnels] Cloudflared

Image
Networking
API management
Web servers
0

635

gerandonk/hera repository overview

Hera
Hera automates the creation of Argo Tunnels to easily and securely expose your local services to the outside world.

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.



Features

  • Automatic Cloudflare login via browser (no manual cert download)
  • Single cloudflared process with dynamic ingress routing
  • Multiple domain support
  • HTTPS origin support with TLS verification control
  • Auto-detect port from container's EXPOSE
  • Stale route cleanup (configurable)
  • Revives tunnels on running containers when Hera restarts
  • Supports Docker standalone and Swarm mode
  • Low memory footprint

How It Works

  1. Hera authenticates with Cloudflare via cloudflared login (opens browser URL)
  2. Creates a named tunnel if it doesn't exist
  3. Monitors Docker container events (start/stop)
  4. When a container with hera.hostname label starts, Hera adds a route to the tunnel
  5. When a container stops, Hera marks the route as stale (removed after configurable days)
  6. Single cloudflared process manages all routes dynamically

Getting Started

Prerequisites

  • Docker with client API version 1.22+
  • An active Cloudflare account with a domain
  • Containers on a shared Docker network with Hera

First Run

  1. Start Hera:
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
  1. Check logs for login URL:
docker logs -f hera
  1. Open the URL in your browser and authorize your domain

  2. Start your containers with labels:

docker run -d \
  --name=nginx \
  --network=hera \
  --label hera.hostname=web.example.com \
  --label hera.port=80 \
  nginx
  1. Access your service at web.example.com

Running Hera

Environment Variables

VariableDefaultDescription
HERA_SWARMfalseEnable Docker Swarm mode
HERA_HOST_LABELhera.hostnameLabel for public tunnel hostname
HERA_PORT_LABELhera.portLabel for container port
HERA_TUNNEL_NAMEheraName of the Cloudflare tunnel
HERA_DATA_DIR/dataDirectory for persistent data
HERA_STALE_DAYS7Days before stale routes are removed (0 to disable)
HERA_DOMAINS(none)Comma-separated additional domains to authorize

Container Labels

LabelRequiredDescription
hera.hostnameYesPublic hostname (e.g. web.example.com)
hera.portNoContainer port (auto-detected if single EXPOSE)
hera.protoNoProtocol: http (default) or https
hera.noTLSVerifyNoSkip TLS verification for self-signed certs (true/false)

Auto-detect Port

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.

HTTPS Origin

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

Multiple Domains

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:

  1. Login for first domain (e.g. example.com)
  2. Login for example2.com
  3. Login for example3.com

After 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.

Examples

Standalone Docker

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

Docker Compose

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:

HTTPS Origin Example

# 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

Swarm Mode

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

Stale Route Cleanup

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.

Tag summary

Content type

Image

Digest

sha256:4139ffd89

Size

31.2 MB

Last updated

6 days ago

docker pull gerandonk/hera