Hostinger DNS Sync
A lightweight Docker container that watches Traefik router labels on your Docker host and automatically creates/updates Hostinger DNS records to point your subdomains at your server's public IP.
How it works
Docker event (container start/stop)
│
▼
Scan all containers for Traefik labels
e.g. traefik.http.routers.myapp.rule=Host(`app.example.com`)
│
▼
Extract hostnames → filter by your DOMAIN
│
▼
Call Hostinger DNS API → upsert A records
On startup it does a full sync, then it listens to Docker events in real-time and re-syncs whenever a container starts or stops.
Prerequisites
- Docker + Docker Compose
- A domain on Hostinger with API access enabled
- Your server's public IP reachable from the internet
Setup
1. Get your Hostinger API key
- Log in to hPanel
- Go to Profile → API Tokens
- Create a new token with DNS read/write permissions
2. Clone & configure
git clone <this-repo>
cd hostinger-dns-sync
cp .env.example .env
nano .env # fill in HOSTINGER_API_KEY and DOMAIN
3. Deploy
docker compose up -d
Check logs:
docker compose logs -f hostinger-dns-sync
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
HOSTINGER_API_KEY |
✅ | — | API token from hPanel |
DOMAIN |
✅ | — | Root domain, e.g. example.com |
PUBLIC_IP |
❌ | auto-detected | Override server IP |
RECORD_TYPE |
❌ | A |
A (IPv4) or AAAA (IPv6) |
TTL |
❌ | 3600 |
DNS TTL in seconds |
DELETE_ORPHANS |
❌ | false |
Delete DNS records no longer in Traefik |
DRY_RUN |
❌ | false |
Preview changes without applying |
Traefik label format
The service reads all containers with a label matching:
traefik.http.routers.<name>.rule=Host(`subdomain.example.com`)
Multi-host rules are supported:
traefik.http.routers.<name>.rule=Host(`a.example.com`) || Host(`b.example.com`)
Orphan cleanup
By default, the service only adds/updates records and never deletes them.
Set DELETE_ORPHANS=true to automatically remove DNS records for subdomains
that are no longer referenced by any Traefik router.
⚠️ Use with care if you manage other records manually on the same domain.
Test without making changes
DRY_RUN=true docker compose up hostinger-dns-sync
Security notes
- The Docker socket is mounted read-only (
:ro) — the container cannot start/stop containers. - The API key is passed via environment variable, never baked into the image.
- Add
.envto your.gitignore.
Description
Languages
Python
97.2%
Dockerfile
2.8%