If you deploy Docker-based apps with Coolify, build times on the production server get slow once that server is doing the building and the serving at the same time. Moving the Docker build to GitHub Actions and GitHub Container Registry (GHCR) leaves Coolify with nothing to do but pull and run a pre-built image.
With a default Coolify setup, every deployment means:
That took about 10 minutes, because the server was building and serving the application at once.
Offload the build to GitHub Actions:
The Coolify deployment step now takes about 30 seconds.
Developer pushes to master
|
v
GitHub Actions (CI runner)
|
├── 1. Builds Docker image
├── 2. Pushes image to ghcr.io
└── 3. Triggers Coolify webhook
|
v
Coolify (production server)
|
├── Pulls pre-built image from ghcr.io
└── Restarts the container Go to your GitHub repository, then Settings > Secrets and variables > Actions > Secrets tab > Repository secrets.
Add these two:
| Secret Name | Description |
|---|---|
COOLIFY_WEBHOOK | The webhook URL from Coolify to trigger a deploy |
COOLIFY_TOKEN | The Coolify API token with deploy permission |
GitHub Actions provides GITHUB_TOKEN itself, so that one needs no setup.
deploy permission, which is the minimum requiredCOOLIFY_TOKEN in GitHub secretsCOOLIFY_WEBHOOK in GitHub secretsFor a private repository, the Coolify server needs to authenticate with GHCR before it can pull the image.
Create a GitHub Personal Access Token (Classic) with the read:packages scope, then SSH into your Coolify server:
sudo su -
echo "<YOUR_GITHUB_PAT>" | docker login ghcr.io -u <YOUR_GITHUB_USERNAME> --password-stdin You should see Login Succeeded.
Run this as root. Coolify runs Docker as root, so the credentials have to land in /root/.docker/config.json rather than your own user’s home directory.
Set Coolify to use the Docker Compose build pack. The docker-compose.yml references the pre-built GHCR image directly, with no build: directive, so Coolify pulls instead of building.
Create .github/workflows/deploy.yml:
name: Build and Deploy
on:
push:
branches:
- master
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Trigger Coolify deploy
if: success()
run: |
curl -X GET "${{ secrets.COOLIFY_WEBHOOK }}"
-H "Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}"
--fail --silent --show-error Every build gets tagged with both latest and the commit SHA, which is what makes rollbacks easy. The type=gha cache means later builds only rebuild the layers that changed. And the Coolify webhook fires only when the build succeeds.
Your docker-compose.yml should point at the GHCR image instead of building locally:
services:
wordpress:
image: ghcr.io/your-org/your-repo:latest
networks:
- coolify
volumes:
- ./uploads:/var/www/vhosts/localhost/html/wp-content/uploads
networks:
coolify:
external: true Push to master:
git push origin master Then watch the build in the Actions tab of your GitHub repository.
Docker on the Coolify server isn’t authenticated with GHCR, or the login happened as a non-root user. Run docker login as root on the server.
The repository probably lacks the right GITHUB_TOKEN permissions. Go to Settings > Actions > General > Workflow permissions and set it to Read and write permissions.
Check that both COOLIFY_WEBHOOK and COOLIFY_TOKEN are correct, and that the API token carries deploy permission.
Every build is tagged with its commit SHA, so a rollback is an image tag change in docker-compose.yml:
image: ghcr.io/your-org/your-repo:<commit-sha> Then trigger a redeploy in Coolify, or push the change.
With the build living in GitHub Actions and the image living in GHCR, the production server only pulls and runs. Deploys drop from ten minutes to about thirty seconds, and the server spends its cycles serving the application instead of compiling it.