Deploying a GitHub repo on Coolify
A start-to-finish walkthrough: connecting GitHub, creating the application, attaching a domain with HTTPS, and getting the first deployment out. Written against a self-hosted Coolify v4 instance deploying this Next.js app.
Before you start
What has to be in place
- A Coolify instance with at least one server added and showing Validated under Servers.
- Ports 80 and 443 open to the internet on that server. Let's Encrypt validates over port 80 — if it is firewalled, certificates never issue.
- Admin rights on the GitHub organisation, so you can install a GitHub App on it.
- A repository whose start script boots a server listening on 0.0.0.0 and the port given by process.env.PORT.
Part 1
Connect GitHub to Coolify
Create a GitHub App source
In Coolify, go to Sources → + Add → GitHub App. Give it a name, pick the organisation that owns your repos, and press Register Now. Coolify hands you off to GitHub to create the App, then back again to install it.
When GitHub asks which repositories to grant access to, prefer Only select repositories and pick the ones you will actually deploy.
Part 2
Create and configure the application
Add the resource
Open (or create) a Project, choose an environment, then + New Resource → Private Repository (with GitHub App). Select the source you just made, pick the repository, and choose the branch to deploy.
Set the build configuration
Coolify detects Next.js and preselects Nixpacks. Leave the three command fields empty — Nixpacks derives them from package.json, and typing them in by hand only creates something else to keep in sync.
Build Pack NixpacksAuto-detected for Next.js. No Dockerfile needed. Branch masterMust match the branch you actually push. This is also what autodeploy watches. Base Directory /Change only for a monorepo, e.g. /apps/web. Install Command (leave blank)Nixpacks runs npm ci from package-lock.json. Build Command (leave blank)Nixpacks runs npm run build. Start Command (leave blank)Nixpacks runs npm run start, i.e. next start. Ports Exposes 3000The port inside the container. Traefik maps 443 to it. Add environment variables
Under Environment Variables, paste your keys. The one distinction that matters: anything the browser needs is compiled into the JavaScript bundle at build time, so it has to be present during the build.
Tick “Build Variable” on these — they are compiled in NEXT_PUBLIC_APP_NAME=Coolify Deployment Demo NEXT_PUBLIC_ENVIRONMENT=staging NEXT_PUBLIC_API_URL=https://api.example.comRuntime only — a restart is enough to pick these up APP_VERSION=1.0.0 COMMIT_SHA=$SOURCE_COMMIT SERVER_NAME=coolify-prod-01 NIXPACKS_NODE_VERSION=22$SOURCE_COMMIT is a Coolify built-in that resolves to the deployed commit, which is what makes the running version identifiable later.
Configure the health check
Point Health Checks at an endpoint that actually exercises the process — this app exposes /health.
Enabled on Path /health Port 3000 Return Code 200 Interval 10s Timeout 5s Retries 3 Start Period 20sGrace window while Node boots, before failures start counting. Without this, Coolify treats a container as healthy the moment it starts, so a process that boots and then fails to serve can replace a working deployment.
Part 3
Point a domain at it
Create the DNS record first
Add an A record for the hostname pointing at your server's public IP — or a wildcard, if you want every future app to get a subdomain for free.
DNS A mumz-app.coolify.mumzstage.com → 203.0.113.10 A *.coolify.mumzstage.com → 203.0.113.10 (wildcard alternative)Set the FQDN in Coolify
In Configuration → General → Domains, enter the full URL including the scheme. The https:// prefix is what tells Traefik to request a certificate; without it you get plain HTTP.
Domains https://mumz-app.coolify.mumzstage.comSave, then enable the HTTPS redirect under Advanced so visitors on http:// are bounced up to TLS. Multiple domains can be comma-separated.
Part 4
Deploy for the first time
Press Deploy and watch the logs
Hit Deploy and open the running deployment to follow the build. Nixpacks moves through four phases — setup, install, build, start — and the log names each one as it goes.
Verify it is really your build
Do not stop at “the page loads”. Check that the container is running the commit you think it is:
Terminal curl -s https://mumz-app.coolify.mumzstage.com/health | jqConfirm commit matches the commit you pushed, and that uptimeSeconds resets to near zero after a restart. If uptime keeps climbing across a redeploy, you are still talking to the old container.
Part 5
Autodeploy on every push
With the GitHub App source and Advanced → Automatic Deployment enabled (the default), a push to the configured branch triggers a fresh build. Three things quietly break it:
- Branch mismatch. Pushing master while Coolify watches maindeploys nothing, silently.
- Watch Paths. If set, only commits touching those paths deploy. Leave it empty unless you are deploying one app out of a monorepo.
- Wrong source type. An app created as a Public Repository has no webhook. Check Webhooks in the sidebar — it shows the URL Coolify expects to be called.
Reference
When it goes wrong
| Symptom | Cause |
|---|---|
| 502 Bad Gateway | App bound to 127.0.0.1 instead of 0.0.0.0, or Ports Exposes does not match the port the server listens on. |
| Page loads with no styling | Nixpacks booted the standalone bundle, which has no copy of .next/static. Remove output: standalone. |
| NEXT_PUBLIC_* change had no effect | Not marked Build Variable, or you restarted instead of redeploying. |
| Certificate stuck on self-signed | DNS not resolving yet, port 80 firewalled, or the FQDN was entered without the https:// scheme. |
| Wrong Node version at runtime | .nvmrc ignored. Pin with NIXPACKS_NODE_VERSION. |
| Build metadata identical across deploys | A page lost export const dynamic = "force-dynamic" and is being prerendered at build time. |
Live
What this container is actually running
Read from the environment of the container serving this request, on every request. Italic not set means the variable is absent in Coolify — which is exactly what step 4 fixes.
Baked in at build time
NEXT_PUBLIC_* values, compiled into the bundle. These require a redeploy to change, and are visible to anyone with DevTools.
- NEXT_PUBLIC_APP_NAME
- mumzworld-coolify-app
- NEXT_PUBLIC_ENVIRONMENT
- production
- NEXT_PUBLIC_API_URL
- not set
Read at runtime
From process.env on each request, never sent to the browser. A restart is enough to change these.
- APP_VERSION
- not set
- COMMIT_SHA
- not set
- DEPLOY_TIME
- not set
- SERVER_NAME
- not set
- NODE_ENV
- production
- PORT
- 3000
- HOSTNAME
- 49928c8b9c75
- process.version
- v24.10.0