Skip to main content
Run every command below from the directory containing compose.yaml.

Start here: service status

Each of db, api and ui reports a health state, and Compose starts them in order — db, then api, then ui, then nginx. A service stuck in starting or marked unhealthy blocks everything after it, so work on the earliest unhealthy service first. A later service that never started is usually a symptom, not the cause. For the logs of a single service:

Upgrade fails with no space left on device

sudo docker compose pull downloads a complete new set of images before the old ones are released, so an upgrade briefly needs room for both versions at once. On a host that has been upgraded a few times, it is usually the accumulated images from previous releases that fill the disk rather than the new release being large. A pull that runs out of space fails partway through with no space left on device or a write error on one of the layers. Nothing is broken by this — the running deployment is untouched and the pull can be repeated once space is available.

Check what is actually full

df reports the filesystem holding Docker’s data; docker system df breaks that down into images, containers, volumes and build cache, with a RECLAIMABLE column showing how much can be freed without touching anything in use.
Docker’s data directory is not always /var/lib/docker. Confirm it with sudo docker info | grep "Docker Root Dir" and run df -h against that path.

Reclaim space

Start with the safe option — this removes only dangling images, the untagged layers left behind by previous pulls:
If the host has ever built images locally, the build cache is worth clearing too:
Then confirm how much came back and retry the pull:

If that did not free enough

This removes every image that is not associated with a container, rather than only the untagged ones — on a host with several old releases it typically reclaims far more.
Treat -a as a last resort, and mind your rollback path. Images are kept while a container still references them, including a stopped one, so running this between docker compose stop and docker compose pull leaves the current release intact. But if you have run docker compose down, the containers are gone, and -a will delete the images for your current version — rolling back would then mean re-pulling the previous tag.

Watch it during the pull

If space is tight enough that you expect the pull to be close, watch the filesystem from a second terminal while it runs:
Never run docker volume prune or docker system prune --volumes on a Cymph host. Compose keeps the database and API data in named volumes, and once the containers have been removed those volumes look unused — pruning them destroys your data. docker image prune and docker builder prune do not touch volumes, which is why they are the commands used above.
If pruning does not free enough to complete an upgrade, the host is under-provisioned for the deployment. See Requirements for the disk sizing, and take a backup before making further changes — see Backup & restore.

nginx exits immediately on startup

The certificate and key are bind-mounted from host paths recorded in .env. If either path does not exist or is not readable, nginx fails at startup rather than serving without TLS. Check the paths Compose is using, then confirm both files exist on the host:
If a path is wrong, correct it in .env and recreate the container so the new bind mount applies — a plain restart keeps the old mount:
See TLS certificates for the file format and renewal.

Port already in use

nginx is the only service that publishes a host port, on the address and port you chose during setup (BIND_ADDRESS and BIND_PORT in .env, default 0.0.0.0:443). If something else on the host already holds that port, the container cannot bind and Compose reports an allocation failure. Find the conflict:
Either stop the conflicting service, or change BIND_PORT in .env and recreate nginx. Note that binding below port 1024 requires the Docker daemon to run as root, which is why the install steps use sudo.

The database never becomes healthy

Two causes account for most of it:
  • Missing or empty db/secrets.txt. It is passed in as a Compose secret and holds the key generated by env.sh. If setup was interrupted, the file may be absent.
  • Permissions on the data directory, which typically follows a restore where ownership was not preserved. See Backup & restore.

The API never becomes healthy

The API healthcheck calls /api/v1/misc/ping inside the container. Reproduce it directly to separate an API problem from a proxy problem:
If that responds but the browser does not, the problem is in nginx or the network path, not the API. If it does not respond, read the API logs — it fails to start when it cannot reach the database or when required values are missing from .env.

The page loads but every request fails

This is the signature of a URL mismatch. env.sh writes the address you gave it into several variables (CYMPH_APP_BASE_URL, NEXTAUTH_URL, NEXT_PUBLIC_WEBAPP_URL, CYMPH_BACKEND_API_ENDPOINT, NEXT_PUBLIC_BACKEND_API_ENDPOINT) and into the nginx server_name. If you later change the hostname, port or scheme of the deployment, all of them have to agree — the browser is told to call an API address that no longer answers.
After correcting them, recreate the affected services:

Cannot reach the deployment at all

Work outward from the host:
  1. On the host, confirm the port is listening: sudo ss -tlnp | grep :443
  2. From the host, confirm TLS answers: openssl s_client -connect localhost:443 </dev/null
  3. From a client, confirm the host firewall and any network firewall permit the port.
If BIND_ADDRESS is set to 127.0.0.1 rather than 0.0.0.0, the deployment is only reachable from the host itself.

Certificate warnings in the browser

Expected with a self-signed certificate. With a CA-issued certificate it usually means the bundle is incomplete — the server certificate is present but the intermediates are missing, so clients cannot build a chain. Concatenate the full chain into the bundle file and restart nginx.

Integrations fail with 403 or a timeout

The deployment is reaching your endpoint from an address that endpoint does not permit, or not reaching it at all. See Networking.

Features are missing or user creation is blocked

The license controls the global user limit and which features are enabled. Check the uploaded license and its expiry — see Licensing.

Locked out of the administrator account

See Resetting the administrator password.

Collecting information for support

If you need to raise an issue with Cymph, include the service states and recent logs:
Review support.txt before sending it. Logs can contain hostnames, e-mail addresses and integration endpoints from your environment.