Fix: Coolify Not Working — Deployment Failing, SSL Not Working, or Containers Not Starting
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix Coolify self-hosted PaaS issues — server setup, application deployment, Docker and Nixpacks builds, environment variables, SSL certificates, database provisioning, and GitHub integration.
The Problem
Deployment starts but the build fails:
Build failed: Error during build — exit code 1Or the app deploys but isn’t accessible:
502 Bad Gateway — or — connection refusedOr SSL certificates don’t work:
NET::ERR_CERT_AUTHORITY_INVALID — or —
Let's Encrypt verification failedOr the database service won’t start:
Container 'postgres' is restarting — health check failingWhy This Happens
Coolify is a self-hosted alternative to Vercel, Netlify, and Railway. It runs on your own server and manages deployments, databases, and SSL through a single dashboard.
Coolify orchestrates Docker containers behind the scenes. The server needs Docker and enough free resources. A VPS with less than 2GB of RAM, a nearly full disk, or a missing Docker daemon causes builds to fail early or containers to die during startup. The default install script provisions Docker, Traefik, and the Coolify dashboard in one shot, so partial installs (interrupted SSH sessions, missing kernel modules on minimal images) leave the stack in a broken state where commands appear to succeed but services refuse traffic.
Build packs decide how your code becomes a container. Coolify uses Nixpacks for auto-detection — the same engine Railway popularized — or a Dockerfile when one exists in the repo root. If detection picks the wrong runtime (Bun vs Node, Python 3.10 vs 3.12), the build either fails immediately or produces a container that crashes at startup. Memory limits during npm install and next build are the second most common cause: a 2GB VPS hits the OOM killer during webpack compilation and the build log shows a non-obvious “exit code 137”.
Ports and DNS finish the chain. Coolify’s reverse proxy — Traefik by default, Caddy as an alternative — routes incoming HTTPS traffic to your container based on the domain you configured. If the app listens on port 8080 but Coolify expects 3000, you get a 502. If the DNS A record points to the wrong IP, Let’s Encrypt fails the HTTP-01 challenge and SSL provisioning loops forever.
Version History: How Coolify Got Here
Coolify shipped its first public release in 2021 as a Heroku-like wrapper around Docker. The early v2 builds were Sveltekit-based and rough — they worked for hobby projects but lacked multi-server support, secrets management, and the Docker Compose flow developers expected from Railway. Documentation lived mostly in Discord screenshots.
Coolify v4 reached general availability in February 2024 and is the version most current tutorials and bug reports reference. The v4 rewrite moved the codebase to Laravel + Livewire, introduced first-class support for Docker Compose resources, added shared environment variables across services, and rewrote the proxy layer to use Traefik v2 by default. If you are following a guide written before February 2024 and your dashboard still says v3, the API surface, environment variable scoping, and proxy logs are different — that mismatch alone causes most “the docs don’t match my UI” support tickets.
The v3-to-v4 migration is not in-place. You provision a new server, install v4, then export and re-import resources. The legacy v3 branch continues to receive security patches but does not get new features like the Cloudflare Tunnel integration or the Bun runtime preset. If you compare Coolify to alternatives in this space, the closest peers are Dokku (the original Heroku-on-your-server, single-host, buildpacks-based, no UI), CapRover (Docker Swarm-based, ships with a UI, opinionated about apps as captain definitions), and Portainer (general Docker UI, not opinionated about app workflow). Coolify v4 is the only one in this list that treats Docker Compose as a first-class deployable resource with auto-generated SSL per service.
Subsequent v4 minor releases have added significant capabilities. The 4.0.0-beta line through the GA release in February 2024 was about stability. The mid-2024 releases added the Bun runtime preset, S3-compatible backups for managed databases, GitHub OAuth login for the dashboard, and the ability to attach multiple Git sources to a single server. Late 2024 saw the introduction of preview deployments (a branch push provisions a temporary environment with its own SSL), team management with role-based access, and an improved logs viewer that streams from Docker directly instead of polling. If you are reading documentation that does not mention preview deployments or teams, it is targeting an early v4 release; check the version in your dashboard footer before assuming the docs apply.
The deployment model under the hood is worth understanding because it explains most production debugging sessions. Coolify watches your Git branch and runs a build on the server when a push lands. The build runs inside a temporary container, the output image is tagged with the commit SHA, and Traefik is reconfigured to route traffic to the new container before the old one is stopped. If the new container fails to start (bad env var, missing migration, port mismatch), Coolify keeps the old container serving traffic and surfaces the failure in the deployment log. That zero-downtime behavior is a v4 addition — v3 did a stop-then-start cycle that left a brief 502 window. Knowing this helps when a deployment “looks stuck”: the build finished, the image was pushed, but the new container never passed its health check, so Traefik never swapped over.
Fix 1: Server Setup
# Install Coolify on a fresh VPS (Ubuntu 22.04+)
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
# Requirements:
# - Ubuntu 22.04+ or Debian 12+
# - 2GB+ RAM (4GB recommended)
# - 30GB+ disk space
# - Ports 80, 443, 8000 open
# After install, access the dashboard:
# http://your-server-ip:8000Initial configuration steps:
- Create an admin account at
http://your-server-ip:8000 - Add your server (localhost is auto-detected)
- Validate the server connection
- Configure a wildcard domain or individual domains
- Set up Git source (GitHub/GitLab/Bitbucket)
Fix 2: Deploy a Next.js / Node.js Application
Through the UI:
- New Resource → Application
- Select Git source → choose repository
- Coolify auto-detects the framework (Nixpacks)
- Configure:
- Build pack: Nixpacks (auto) or Dockerfile
- Port: 3000 (Next.js default)
- Domain:
myapp.example.com - Environment variables: Add from the UI
Or with a Dockerfile:
# Dockerfile — for full control over the build
FROM node:20-slim AS base
WORKDIR /app
FROM base AS deps
COPY package*.json ./
RUN npm ci
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]// next.config.mjs — required for standalone Docker builds
const nextConfig = {
output: 'standalone', // Generates a minimal server
};
export default nextConfig;Fix 3: Fix Build Failures
# Common Nixpacks build issues:
# 1. Node.js version mismatch
# Create .node-version or .nvmrc in project root
echo "20" > .node-version
# 2. Build command not found
# Coolify reads package.json scripts
# Ensure "build" script exists:
# "build": "next build"
# "start": "next start"
# 3. Memory issues during build
# Add to environment variables in Coolify:
# NODE_OPTIONS=--max-old-space-size=4096
# 4. Private npm packages
# Add NPM_TOKEN as environment variable in Coolify
# Create .npmrc: //registry.npmjs.org/:_authToken=${NPM_TOKEN}Custom Nixpacks configuration:
# nixpacks.toml — customize the build
[phases.setup]
nixPkgs = ["nodejs_20", "npm"]
[phases.install]
cmds = ["npm ci"]
[phases.build]
cmds = ["npm run build"]
[start]
cmd = "npm start"Fix 4: Environment Variables and Secrets
# In Coolify dashboard: Application → Environment Variables
# Build-time variables (available during npm run build)
NEXT_PUBLIC_API_URL=https://api.myapp.com
NEXT_PUBLIC_SITE_URL=https://myapp.com
# Runtime variables (available when app runs)
DATABASE_URL=postgresql://user:pass@db:5432/mydb
REDIS_URL=redis://redis:6379
API_SECRET=your-secret-key
# Shared variables — reuse across services
# Create in Environment → Shared Variables
# Reference with {{SHARED.DATABASE_URL}}Connect to Coolify-managed databases:
# Coolify provisions databases as Docker containers
# Connection URLs use Docker internal network hostnames
# PostgreSQL provisioned by Coolify:
DATABASE_URL=postgresql://postgres:generated-password@app-name-db:5432/postgres
# Redis:
REDIS_URL=redis://app-name-redis:6379
# The hostname is the container name on Coolify's internal Docker networkFix 5: SSL and Domains
# Step 1: Point DNS to your Coolify server
# A record: myapp.example.com → your-server-ip
# Or wildcard: *.example.com → your-server-ip
# Step 2: Configure domain in Coolify
# Application → Settings → Domains
# Add: myapp.example.com
# Step 3: SSL is automatic with Let's Encrypt
# Coolify's proxy (Traefik/Caddy) handles cert provisioning
# If SSL fails:
# - Check DNS propagation: dig myapp.example.com
# - Ensure ports 80 and 443 are open
# - Check Traefik/Caddy logs in Coolify dashboard
# - Rate limits: Let's Encrypt allows 50 certs per domain per weekCustom SSL certificate (if Let’s Encrypt doesn’t work):
Upload your certificate in Coolify → Settings → SSL → Custom Certificate.
Fix 6: Database and Service Provisioning
# Coolify can provision databases as Docker services
# PostgreSQL
# New Resource → Database → PostgreSQL
# Coolify creates the container and generates credentials
# Redis
# New Resource → Database → Redis
# MySQL / MariaDB / MongoDB — same pattern
# Connect from your app using the internal hostname
# The hostname is shown in the database resource settingsDocker Compose for complex setups:
# docker-compose.yml — deploy as a Docker Compose resource in Coolify
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
worker:
build: .
command: npm run worker
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
pgdata:Still Not Working?
502 Bad Gateway after deployment — the app container started but the port doesn’t match. Check what port your app listens on (Next.js: 3000, Vite: 5173, custom: whatever PORT env says). Set the correct port in Coolify’s application settings. Also check container logs for startup errors.
Build succeeds but container keeps restarting — the start command is wrong or the app crashes on startup. Check the container logs in Coolify dashboard. Common causes: missing environment variables, database not reachable, or wrong start command in package.json.
Let’s Encrypt SSL fails — DNS must point to your server before requesting a certificate. Let’s Encrypt verifies domain ownership via HTTP challenge on port 80. Ensure: DNS A record is correct, port 80 is open, and no firewall blocks the verification request.
Database connection refused from app — use the Docker internal hostname (container name), not localhost. Coolify’s databases and apps run in the same Docker network. The hostname is shown in the database resource’s connection details.
Build dies with exit code 137 and no other message — the build container hit the OOM killer. Webpack and Next.js builds spike memory hard around the static optimization step. On a 2GB VPS, set NODE_OPTIONS=--max-old-space-size=1536 in the build environment to leave headroom for the kernel, or upgrade to a 4GB instance. Coolify itself also needs around 500MB resident, so the effective budget on a 2GB box is lower than it looks.
Traefik dashboard shows the route but the browser still 502s — Traefik resolved the host but cannot reach the container on the internal network. This happens when the app binds to 127.0.0.1 instead of 0.0.0.0. Inside Docker, 127.0.0.1 only reaches the container itself, not Traefik. Force the app to listen on all interfaces — for Next.js, that means next start -H 0.0.0.0. The container logs will show the bind address it actually used.
v3 dashboard does not match the documentation — you are reading v4 docs against a v3 install. The Coolify v4 GA (February 2024) renamed several concepts (Applications instead of Services, Resources instead of Sources). Either follow the v3 archived docs or provision a fresh server with the current installer and re-add your repos. There is no clean in-place upgrade path.
For related deployment issues, see Fix: Wrangler Not Working, Fix: Docker Secrets Not Working, Fix: Docker Container Keeps Restarting, and Fix: Fly Deploy Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Fly.io Deploy Not Working — fly.toml, Machines, Volumes, Secrets, and Internal DNS
How to fix Fly.io errors — fly.toml app vs name confusion, machines API vs legacy apps, Dockerfile build failures, volume per-region, secrets staging, fly proxy for local access, and internal IPv6 routing.
Fix: Docker Secrets Not Working — BuildKit --secret Not Mounting, Compose Secrets Undefined, or Secret Leaking into Image
How to fix Docker secrets — BuildKit secret mounts in Dockerfile, docker-compose secrets config, runtime vs build-time secrets, environment variable alternatives, and verifying secrets don't leak into image layers.
Fix: Docker Compose Healthcheck Not Working — depends_on Not Waiting or Always Unhealthy
How to fix Docker Compose healthcheck issues — depends_on condition service_healthy, healthcheck command syntax, start_period, custom health scripts, and debugging unhealthy containers.
Fix: Docker Multi-Platform Build Not Working — buildx Fails, Wrong Architecture, or QEMU Error
How to fix Docker multi-platform build issues — buildx setup, QEMU registration, --platform flag usage, architecture-specific dependencies, and pushing multi-arch manifests to a registry.