PDNS Manager

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-*.js returns 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=true is required in .env.
  • Reverse proxy mis-set? Forward X-Forwarded-Proto, X-Forwarded-For.
  • SameSite issues? Default lax works; only embedded cross-site (iframe) needs none + 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.conf doesn't match the one in the panel.
  • Connection refused: webserver=yes? webserver-address bound on the right interface? Reachable from inside the backend container?
  • 403 Forbidden: webserver-allow-from blocks 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 dig really 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

  1. DS at the registrar missing or stale → read the current DS in the panel and update at the registrar.
  2. NS records at the registrar point to the wrong servers (e.g. old provider NS).
  3. 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 backend for the exact error.
  • Disk full → df -h, prune old images with docker 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.