deeplo
Guides

Troubleshooting

Common problems with webhooks, SSH, deploys, and state — and how to fix them.

Webhook not firing

Symptom: Push a commit, nothing happens in the daemon logs.

  1. Check GitHub webhook delivery history: your repo → Settings → Webhooks → click your webhook → Recent Deliveries. Look for errors or non-2xx responses.

  2. Check daemon logs for incoming webhook events. If nothing appears, the request is not reaching the daemon.

  3. Verify port 8080 (or your configured DEEPLO_WEBHOOK_PORT) is reachable from GitHub's IPs. If you're behind NAT, use polling mode or set up a reverse proxy.

  4. Check that DEEPLO_GITHUB_WEBHOOK_SECRET_FILE contains exactly the same secret set in GitHub. A mismatch causes all requests to return 401 and be silently discarded.

  5. Verify the webhook is configured for push events and the branch in the push event matches the branch in your repo config.

  6. Check watch_paths — if no changed file in the push matches the project's watch_paths, the deploy is intentionally skipped. Check the logs for "no projects matched" or "skipped: no paths match".


Poller not detecting changes

Symptom: Poll mode is configured but deploys aren't firing when commits land.

  1. Check poll state file: DEEPLO_DATA_DIR/state/poll/<repo>-<branch>.json. The last_seen_sha field shows what the poller last observed.

  2. If last_seen_sha is current but no deploy fired, deduplication may have skipped it. Check DEEPLO_DATA_DIR/state/projects.json for an existing success record for that SHA.

  3. Verify the poller is running in the logs: poller started and poller: started repo=... interval=....

  4. Check poll_interval — with the default of 60s, a deploy can be delayed up to a minute.


Host key verification failure

Symptom: Deploy fails with ssh: host key mismatch or ssh: unknown host.

  1. The host's SSH key changed (e.g. the server was rebuilt). Update known_hosts:

    ssh-keyscan 10.0.0.10 >> known_hosts

    Remove the old entry for that host first if it's a key replacement, not an addition.

  2. The wrong known_hosts file is configured. Verify DEEPLO_SSH_KNOWN_HOSTS points to the file that was populated with ssh-keyscan.

  3. The known_hosts file is not mounted into the container. Check the volume mapping in docker-compose.yml.

  4. If you're using DEEPLO_SSH_HOST_KEY_POLICY=accept-new (default) and the key changed, deeplo will reject the connection because the stored key no longer matches. Rerun ssh-keyscan to update the stored key.


SSH authentication failure

Symptom: Deploy fails with ssh: unable to authenticate or permission denied (publickey).

  1. Verify the private key matches the public key installed on the target host.

  2. Verify the key file is mounted and readable:

    docker exec deeplo ls -la /run/secrets/deploy_key
  3. Verify the deploy user exists on the target and the public key is in their authorized_keys.

  4. Check the effective SSH user for that host. Deeplo uses hosts[].user when set, otherwise DEEPLO_SSH_USER.

  5. Check DEEPLO_SSH_PORT if the target runs SSH on a non-standard port.


Repo fetch failure

Symptom: Deploy fails with git fetch or git clone errors.

  1. Check the repo URL. SSH and HTTPS both work; make sure the URL is correct and the branch exists.

  2. For SSH URLs: the private key must have read access to the repository. Test manually:

    GIT_SSH_COMMAND="ssh -i /path/to/deploy_key" git ls-remote git@github.com:yourorg/repo.git
  3. For github.com: ensure github.com is in your known_hosts file. deeplo uses the same DEEPLO_SSH_KNOWN_HOSTS for both host connections and git operations.

    ssh-keyscan github.com >> known_hosts

Compose preflight failure

Symptom: Deploy fails at the preflight step with a validation error from docker compose config.

  1. Missing environment variables — if your compose file uses ${VAR} and the variable isn't set on the remote host, preflight fails. Make sure required variables are available in the remote environment or .env file.

  2. YAML syntax error — check the compose file locally with docker compose config.

  3. File path issues — check that repo_subdir and compose_files in the project config point to the correct paths within the repo.

  4. Compose version mismatch — if your compose file uses features not supported by the Docker Compose version on the target, preflight will fail. Update Docker on the target host.

Preflight failures are clean — the live directory on the target is never touched if preflight fails.


Deploy succeeded but app is unhealthy

Symptom: docker compose up succeeded, but docker compose ps shows containers as exited or restarting.

deeplo runs docker compose ps immediately after up and reports a runtime verification failure if any service is not in the running state. This catches containers that start and immediately exit (bad config, missing file, crash on startup).

To debug:

  1. SSH to the target and run docker compose logs in the project directory.
  2. Run docker compose ps to see current container states.
  3. Fix the application issue and push a new commit to redeploy.
  4. Run deeplo refresh to inspect live runtime state after manual intervention.

Note: deeplo does not perform application-level readiness checks (HTTP probes, etc.), and does not detect containers that crash after starting successfully.


State mismatch after manual intervention

Symptom: deeplo status shows outdated or incorrect information after you ran docker compose commands directly on a host.

Run deeplo refresh to reconnect to all hosts, run docker compose ps for each project, and inspect the live runtime state:

deeplo refresh

deeplo refresh does not rewrite deployment history or create refresh-sourced deployment entries.


Config validation errors

Symptom: deeplo check reports errors.

Common causes:

  • hosts[].address is empty or missing
  • projects[].targets references a host name that isn't in the hosts list
  • repos[].url is empty
  • version is not 1

Run with --probe-hosts to also verify SSH connectivity:

deeplo check --config config.yml --probe-hosts

Increasing log verbosity

Set log level and format via environment variables:

# In docker-compose.yml or EnvironmentFile:
DEEPLO_LOG_LEVEL=debug
DEEPLO_LOG_FORMAT=json

For structured output, DEEPLO_LOG_FORMAT=json makes it easier to filter with jq:

docker compose logs -f | jq 'select(.level == "ERROR")'

On this page