Troubleshooting
Collected fixes for the things that bite people most often. If your problem isn't here and you fix it, please open an issue with the resolution – we'll add it.
Compose says "DB_PASSWORD is empty …"
Guard rail since v2.3.3: without passwords the DB doesn't initialise. Fix:
./setup.sh # writes a complete .env
# or manually: cp .env.example .env and fill in passwords
docker compose up -d Backend logs "JWT_SECRET_KEY is empty"
echo "JWT_SECRET_KEY=$(openssl rand -hex 64)" >> .env
docker compose up -d Containers don't start / hang
docker compose logs -f
docker compose down
docker compose up -d MariaDB takes a few seconds on first start to become healthy. The backend waits automatically (depends_on: condition: service_healthy).
Backend up, frontend shows blank page
Since v2.3.7 the backend image build verifies index.html, assets/ and a built JS bundle exist – build aborts otherwise. If you still get blank:
- Clear the browser cache or try an incognito tab.
- In DevTools → Network check whether
/assets/index-*.jsreturns 200 or 404. - 404? Rebuild the backend image:
./update.sh --rebuild.
Login fails ("429 Too Many Requests")
The login rate limit kicked in. Wait a few minutes, then use the right password. The Retry-After header tells you exactly how long.
Login fails, no 429 – cookie not set
- HTTPS in front? Then
AUTH_COOKIE_SECURE=trueis required in.env. - Reverse proxy mis-set? Forward
X-Forwarded-Proto,X-Forwarded-For. - SameSite issues? Default
laxworks; only embedded cross-site (iframe) needsnone+secure.
"Captcha invalid" on login (lockout)
If captcha is misconfigured and locks you out, drop it via SQL:
docker compose exec -T mariadb mysql -u root -p"$DB_ROOT_PASSWORD" dns_manager <<SQL
UPDATE system_settings SET value='false' WHERE key_name='captcha.enabled';
SQL Then sign back in, configure captcha properly, hit the test button and re-enable it.
Forgot the admin password
docker compose exec backend python -c "
from app.core.database import async_session
from app.models.models import User
from app.core.auth import hash_password
import asyncio
async def reset():
async with async_session() as db:
admin = await db.get(User, 1) # user ID 1 = first admin
admin.hashed_password = hash_password('new-password')
await db.commit()
print('Password reset.')
asyncio.run(reset())
" PowerDNS connection test red
- HTTP 401: API key in
pdns.confdoesn't match the one in the panel. - Connection refused:
webserver=yes?webserver-addressbound on the right interface? Reachable from inside the backend container? - 403 Forbidden:
webserver-allow-fromblocks you. From inside:docker compose exec backend curl -v http://pdns:8081/api/v1/servers. - Timeout: firewall, routing, or PowerDNS hung – check
journalctl -u pdns.
Records exist in the panel but `dig` shows nothing
- Did
digreally query this PowerDNS? Use@<ip>explicitly. - SOA serial bumped?
dig SOA <zone> @<ip> +short– if not, PowerDNS may have rejected the write; check the backend log. - Resolver cache? Wait the TTL or flush.
DNSSEC: resolver returns SERVFAIL
- DS at the registrar missing or stale → read the current DS in the panel and update at the registrar.
- NS records at the registrar point to the wrong servers (e.g. old provider NS).
- Auto-signing off, RRSIG expired → change a record minimally to trigger re-sign.
Test tool: dnsviz.net – shows the whole chain with concrete errors.
Webhook doesn't arrive or is rejected
- URL is private (RFC1918 / localhost)? Blocked by default. Set
WEBHOOK_ALLOW_PRIVATE_URLS=true. - HTTPS endpoint with self-signed cert? Currently not accepted – use a valid cert or internal ACME.
- Receiver verifies the signature wrong and returns 4xx → check that you use the raw body for HMAC.
Update breaks or container won't come up
- DB migration didn't run → check
docker compose logs backendfor the exact error. - Disk full →
df -h, prune old images withdocker system prune -a. - Emergency: roll back to the previous tag (
git checkout v2.3.7 && docker compose build backend && docker compose up -d) and restore the DB backup.