Domain + HTTPS setup for Docker services (Nginx + Certbot)
Project description
DomainUp – config-driven reverse proxy for Docker
DomainUp turns a simple YAML file into a running reverse-proxy with HTTPS for your Docker services. It renders Nginx (by default) and obtains Let’s Encrypt certificates via webroot. A Traefik renderer (POC) is included; DNS-01 is planned.
Overview
Why this exists: I kept repeating the same steps when provisioning a server on Hetzner — creating a reverse-proxy, wiring domains, getting HTTPS, and keeping things maintainable. DomainUp captures that workflow in a single, reproducible tool so any developer deploying on Hetzner (or any Docker host) can set up domains with minimal friction and no headaches.
Key ideas:
- Single
domainup.yamlgoverns everything. - Arbitrary number of domains; each maps to one or more Docker upstreams.
- Generic Jinja2 templates for Nginx vhosts (and Traefik dynamic files with basic middlewares).
- Let’s Encrypt via webroot (DNS-01 coming), HSTS optional.
- Per-domain options: websockets, path routes, headers, basic auth (htpasswd files supported), allow-list, simple rate-limit, gzip, CORS passthrough, LB strategy, sticky cookie.
- No hardcoded “types” like monitoring/otlp — fully generic.
Quick Start
Install (editable for local development):
pipx install -e .
Minimal flow:
domainup init --email contact@cirrondly.com # creates domainup.yaml skeleton
domainup plan # validate + print plan
domainup render # generate Nginx configs from YAML
domainup up # start Nginx reverse proxy
domainup cert # obtain certs (webroot)
domainup reload # reload Nginx
domainup deploy # render -> up -> cert -> reload
domainup check --domain api.example.com # quick diagnostics
Local testing tips:
- If ports 80/443 are busy, adjust host ports in
domainup.yamlunderruntime.http_port/https_portthenrender+up. - For HTTPS locally, use
mkcertand place certs under./letsencrypt/live/<host>/.
Configuration (domainup.yaml)
version: 1
email: contact@cirrondly.com
engine: nginx # nginx | traefik (poc)
cert:
method: webroot # webroot | dns01 (todo)
webroot_dir: ./www/certbot
staging: false # true to test with LE staging
network: proxy_net
runtime:
http_port: 80
https_port: 443
domains:
- host: api.example.com
upstreams:
- name: app1
target: back_web_1:8000
weight: 1
paths:
- path: /
upstream: app1
websocket: true
strip_prefix: false
headers:
hsts: true
extra:
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
security:
basic_auth:
enabled: false
users: []
allow_ips: []
rate_limit:
enabled: false
requests_per_minute: 600
tls: { enabled: true }
gzip: true
cors_passthrough: false
- host: console.example.com
upstreams:
- name: console
target: console:3000
paths:
- path: "/"
upstream: console
security:
basic_auth:
enabled: true
users: ["admin:{SHA}..."]
tls: { enabled: true }
- host: data.example.com
upstreams:
- name: otel
target: otel:4318
paths:
- path: "~* ^/(v1/|otlp/v1/)(traces|logs|metrics)"
upstream: otel
body_size: 20m
tls: { enabled: true }
Usage Examples
- Generate configs for Nginx and start the proxy:
domainup render && domainup up
- Obtain certificates (webroot):
domainup cert && domainup reload
- Check DNS and TLS quickly:
domainup check --domain api.example.com
- Print DNS records to create in your provider (e.g., Hetzner DNS, Vercel DNS, Cloudflare):
domainup dns --ipv4 203.0.113.10 --ipv6 2001:db8::10
Files generated (Nginx engine)
nginx/nginx.confnginx/conf.d/00-redirect.conf(http→https + ACME webroot for all TLS hosts)nginx/conf.d/<host>.confper domainruntime/docker-compose.nginx.ymlto run the proxy
Files generated (Traefik engine)
traefik/traefik.yml(static)traefik/dynamic/<host>.ymlper domain with middlewarestraefik/htpasswd/<host>.htpasswdwhen basic auth enabledruntime/docker-compose.traefik.ymlto run the proxy
Contributing
Set up dev environment:
pip install -e .[dev]
pytest -q
Coding standards:
- Format: black, lint: ruff, types: mypy
- Tests: pytest; add unit tests for new behaviors
- PRs: include a brief description, motivation (what problem you solved), and tests
Security
- Don’t expose Basic Auth user/passwords in the repo; use htpasswd files or safe secret storage.
- HTTP-01 requires port 80. If you can’t open it, prefer DNS-01 (on roadmap).
- Review Nginx config before going to production; adjust rate limits and headers as needed for your threat model.
License & Branding
MIT License. See LICENSE for details.
Created by Cirrondly (cirrondly.com) — a tiny startup by José MARIN.
Roadmap
- DNS provider API integrations (Vercel, Cloudflare)
- ACME DNS-01 support
- Traefik middlewares parity (rate-limit, sticky, advanced headers)
Delivered from roadmap in this release:
- Hetzner DNS automation (A/AAAA upsert) via
domainup dns --provider hetzner --token ... - Cloudflare DNS automation (A/AAAA upsert) via
domainup dns --provider cloudflare --token ... - Optional htpasswd file generation for basic auth (render-time)
- Better CORS passthrough controls
- Traefik basic middlewares: BasicAuth + CORS + RateLimit + Sticky cookie
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file domainup-0.1.1.tar.gz.
File metadata
- Download URL: domainup-0.1.1.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64c9f45536fb7ecea3757a5dde907aa3e2ffb496e4b3279d05c9b53b88f057ff
|
|
| MD5 |
24516a68e7b6bc15eba3c6150bec80c6
|
|
| BLAKE2b-256 |
1756a70be9cb272c6fc975428c74880020ad75d889a3b8d7e7f4083ebe2a80dd
|
File details
Details for the file domainup-0.1.1-py3-none-any.whl.
File metadata
- Download URL: domainup-0.1.1-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6bdd2b1f4fbfc03c13f59536b657a5eb3f1b2a27d538113f3942fa43f6490c8
|
|
| MD5 |
e79fd38b3d77a0195df5e530c39266b5
|
|
| BLAKE2b-256 |
99ea9612ccf557431542f54cc793c179a32cb0d6b678d3d42ad6c6a3e67103d0
|