homelab-blueprint/docs/TROUBLESHOOTING.md
2026-06-13 17:47:19 +02:00

7.7 KiB

Docker Stack Troubleshooting Guide

Quick diagnostics

Run these first:

docker ps -a
docker stats --no-stream
docker network ls
docker-compose -f docker-compose.arr-stack.yml config

Common issues

1. Variables not substituted

Symptoms:

  • Generated file still contains {{VAR}}
  • Container fails due to missing env values

Fix:

./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml

The script prints any unresolved placeholders. Add missing keys to .env (or provide defaults in templates).

2. Recyclarr errors (base_url must start with http)

Use service names, not localhost:

sonarr:
  sonarr-main:
    base_url: http://sonarr:8989

radarr:
  radarr-main:
    base_url: http://radarr:7878

Generate your file from this repo template:

./substitute_env.sh docker-compose-files/arr-stack/config/recyclarr_template.yml /opt/arr-stack/appdata/recyclarr/recyclarr.yml

2b. Recyclarr errors (Unable to find include template ...)

Symptoms:

  • Unable to find include template with name 'radarr-quality-definition-movie'
  • Similar errors for other include: - template: entries

Cause:

  • You are using an older pre-v8 recyclarr.yml that still has include: - template: entries.
  • Recyclarr v8 removed official include templates from the default provider.

Fix (v8 path used by this repository):

# 1) Regenerate recyclarr config from the v8 template
./substitute_env.sh docker-compose-files/arr-stack/config/recyclarr_template.yml /opt/arr-stack/appdata/recyclarr/recyclarr.yml

# 2) Regenerate compose and recreate recyclarr (v8.6.0 pin)
./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml
docker-compose -f docker-compose.arr-stack.yml pull recyclarr
docker-compose -f docker-compose.arr-stack.yml up -d recyclarr

3. qBittorrent/SAB not using VPN IP

In this template, only download clients are expected behind VPN tunnel.

  • Behind VPN: gluetun, qbittorrent
  • Not behind VPN by default: radarr, sonarr, prowlarr, bazarr, emby, seerr

Checks:

docker logs gluetun | grep -i connected
docker exec qbittorrent curl -s ifconfig.me

4. Dependency/healthcheck startup failures

Symptoms:

  • dependency failed to start
  • Services wait forever on service_healthy

Checks:

docker inspect gluetun | grep -A 20 Health
docker inspect prowlarr | grep -A 20 Health
docker logs <container_name>

Fixes:

  • Increase start_period for slow-start services.
  • Test healthcheck command inside the container.
  • Validate generated compose YAML syntax with docker-compose ... config.

5. Network communication failures

Checks:

docker network inspect vpn_network
docker exec radarr wget -qO- http://prowlarr:9696/ping

Fixes:

  • Ensure relevant services are on vpn-network in generated compose.
  • Recreate stack networks:
docker-compose -f docker-compose.arr-stack.yml down
docker network prune
docker-compose -f docker-compose.arr-stack.yml up -d

5b. qBittorrent stuck in "Created" / network service:gluetun not found

Symptoms:

  • qbittorrent does not start after updates and remains in Created
  • Recreate shows: Error response from daemon: network service:gluetun not found

Cause:

  • network_mode: service:gluetun can fail during single-service recreate/update flows on some Docker setups.

Fix:

# Ensure template uses container mode for qbittorrent:
# network_mode: "container:gluetun"

# Re-render compose and recreate the pair
./substitute_env.sh docker-compose-files/arr-stack/template.yaml docker-compose.arr-stack.yml .env
docker-compose -f docker-compose.arr-stack.yml up -d --force-recreate gluetun qbittorrent

Verify:

docker-compose -f docker-compose.arr-stack.yml ps gluetun qbittorrent
docker-compose -f docker-compose.arr-stack.yml logs --tail 100 qbittorrent

5c. qBittorrent HTTPS 502 after stack updates

Symptoms:

  • qBittorrent opens via HTTPS reverse proxy URL and returns 502 after stack updates/recreates.

Common causes:

  • gluetun and qbittorrent are out of sync after recreate/update and need a paired restart.
  • qBittorrent WebUI can be left in HTTPS mode while your reverse proxy still targets HTTP upstream.

Fix:

# 1) Recreate the VPN + torrent pair together
docker-compose -f docker-compose.arr-stack.yml up -d --force-recreate gluetun qbittorrent

# 2) If 502 persists, force qBittorrent WebUI back to HTTP
CONF="$(find /opt/arr-stack/appdata/qbittorrent -type f -name 'qBittorrent.conf' | head -n1)"
echo "Using config: $CONF"
sudo sed -i 's#^WebUI\\HTTPS\\Enabled=.*#WebUI\\HTTPS\\Enabled=false#' "$CONF"
sudo sed -i 's#^WebUI\\HTTPS\\CertificatePath=.*#WebUI\\HTTPS\\CertificatePath=#' "$CONF"
sudo sed -i 's#^WebUI\\HTTPS\\KeyPath=.*#WebUI\\HTTPS\\KeyPath=#' "$CONF"
docker-compose -f docker-compose.arr-stack.yml restart qbittorrent

Verify:

docker-compose -f docker-compose.arr-stack.yml ps gluetun qbittorrent
docker-compose -f docker-compose.arr-stack.yml logs --tail 120 qbittorrent

6. Data/config persistence problems

Checks:

docker inspect radarr | grep -A 20 Mounts
ls -la /opt/arr-stack/appdata/radarr

Fixes:

mkdir -p /opt/arr-stack/appdata/radarr
chown -R <PUID>:<PGID> /opt/arr-stack/appdata/radarr

For pgAdmin specifically:

chown -R 5050:5050 /volume1/docker/appdata/pgadmin

7. Caddy reverse proxy issues

If Caddy refuses to start, validate syntax first:

./substitute_env.sh docker-compose-files/caddy/Caddyfile_template docker-compose-files/caddy/Caddyfile .env
./substitute_env.sh docker-compose-files/caddy/template.yaml docker-compose.caddy.yml .env
docker compose -f docker-compose.caddy.yml run --rm caddy \
  caddy validate --config /etc/caddy/Caddyfile

If certificate issuance fails with errors like:

  • could not determine zone for domain ... / expected 1 zone, got 0
  • dial tcp 1.0.0.1:53: i/o timeout

these are two distinct failure modes with the same underlying cause: Caddy's DNS-01 resolver cannot reach 1.1.1.1/1.0.0.1 on port 53.

Distinguish the two errors:

Error Meaning
expected 1 zone, got 0 Caddy reached a resolver, but it was Technitium (split-DNS). NAT exception misconfigured or alias IP wrong.
dial tcp 1.0.0.1:53: i/o timeout Caddy's packets are being dropped. A firewall block rule on OPT2 is above the pass rule, or the NAT exception is not set up at all.

Check DNS reachability from the Caddy host:

# Must return Cloudflare SOA, not Technitium SOA (dns01.home.example.com)
dig +short SOA home.example.com @1.1.1.1

# Distinguish firewall drop from redirect:
dig @1.1.1.1 +tcp +time=5 google.com   # timeout = firewall drop
dig @1.1.1.1 +notcp +time=5 google.com # timeout = same; success = TCP-specific block

Keep public resolvers in the Caddy TLS block — do not switch to Technitium as a workaround, as it causes expected 1 zone, got 0 because Technitium is authoritative for the internal zone:

tls you@example.com {
  dns cloudflare {env.CLOUDFLARE_DNS_TOKEN}
  resolvers 1.1.1.1 1.0.0.1
}

If your network forces DNS redirection, exclude Caddy from that redirect and allow it to query public resolvers on TCP and UDP port 53.

If a proxied app fails over HTTPS with self-signed backend certs, ensure the target block uses:

transport http {
  tls_insecure_skip_verify
}

Update flow (safe)

  1. Generate compose files from templates.
  2. Validate with docker-compose -f <file> config.
  3. Pull images.
  4. Recreate services.
  5. Review logs after startup.
docker-compose -f docker-compose.arr-stack.yml pull
docker-compose -f docker-compose.arr-stack.yml up -d

Last Updated: 2026-02-14