When building full-stack applications with Docker Compose, it’s essential to have a reliable way to ship and deploy both frontend and backend services in sync. This article walks through setting up a CI/CD pipeline using GitHub Actions to deploy a multi-container Docker application to Koyeb, a modern platform that supports containerized workloads out of the box.
We’ll use a real project—complete with frontend, backend, and supporting services—as our base. The focus here isn’t just deployment, but doing it cleanly and automatically through GitHub Actions. You’ll see how to:
- Prepare your application with Docker Compose
- Configure GitHub Actions workflows for CI and deployment
- Push both services to Koyeb in a unified pipeline
By the end of this guide, you’ll have a production-grade deployment pipeline that pushes changes from main
to Koyeb, without manual steps or scripts. The project code is available here if you’d like to follow along.
Table of Contents
- Prerequisites
- Dockerfiles and Docker Compose Configuration
- GitHub Actions Configuration and CI/CD Workflow
- Deploying to Koyeb
- Conclusion
Prerequisites
Before you begin, ensure you have the following:
-
A full stack application ready for deployment, with Dockerfile(s) and a
docker-compose.yml
configured to run your services locally. - A Koyeb account — you can sign up for free at here.
- Basic familiarity with Docker and Docker Compose, as this deployment will rely on these tools to containerize and orchestrate your app.
- A GitHub account with admin access to your repository so you can set up GitHub Actions workflows.
- A Koyeb API token, which you will generate from your Koyeb dashboard and add as a secret in your GitHub repository to enable automated deployments.
Dockerfiles and Docker Compose Configuration
Backend Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY ./requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["uvicorn", "main:app", "--port", "8080", "--host", "0.0.0.0"]
This Dockerfile sets up the backend environment using a lightweight Python 3.12 slim image. The key steps are:
- Sets the working directory to
/app
inside the container. - Copies
requirements.txt
and installs Python dependencies without caching to reduce image size. - Copies the backend source code into the container.
- Exposes port
8080
to allow incoming connections. - Runs the FastAPI application using Uvicorn, listening on all network interfaces (
0.0.0.0
) and port8080
.
Frontend Dockerfile
FROM node:22-alpine
WORKDIR /app
COPY ./package*.json /app/
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"]
For the frontend, a minimal Node.js Alpine image is used to keep the container small and fast. This Dockerfile:
- Sets
/app
as the working directory. - Copies package files and installs dependencies via
npm install
. - Copies the full frontend source code into the container.
- Exposes port
3000
to serve the frontend application. - Runs the frontend in development mode, binding to all interfaces on port
3000
.
Docker Compose File
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
build: ./backend
ports:
- "8080:8080"
The docker-compose.yml
orchestrates the two services — backend and frontend — allowing them to run together easily:
- The backend service builds from the
./backend
directory and exposes port8080
. - The frontend service builds from
./frontend
, exposes port3000
, and depends on the backend to ensure proper startup order. - This setup enables the frontend to communicate with the backend seamlessly during development and deployment.
Dockerfile.koyeb
(Main Deployment File)
FROM koyeb/docker-compose
COPY . /app
This file is the core of your deployment on Koyeb. It uses the official Koyeb Docker Compose image, which is pre-configured with Docker Compose for multi-service apps. The key points:
- Copies the entire project into
/app
inside the container. - When deployed on Koyeb, this image automatically runs the
docker-compose.yml
in/app
. - This approach simplifies deployment by handling the orchestration of both backend and frontend services with a single command on Koyeb’s platform.
GitHub Actions CI/CD Configuration
Obtaining the Koyeb API Token
Before the CI/CD pipeline can deploy your app to Koyeb, you need a Koyeb API token. This token authorizes GitHub Actions to interact with your Koyeb account and manage deployments securely.
How to get your Koyeb API token:
- Log in to your Koyeb dashboard.
- Navigate to Account Settings or API Tokens section.
- Generate a new API token with appropriate permissions for deployment.
- Copy the token and add it as a secret in your GitHub repository settings under
Settings > Secrets and variables > Actions > New repository secret
with the nameKOYEB_API_TOKEN
.
Note: If your Koyeb account is banned or inaccessible, you will not be able to generate a token. In that case, consider contacting Koyeb support or using an alternative deployment provider that suits your needs.
GitHub Actions Workflow Explained
Below is the GitHub Actions Workflow YAML for building and deploying your full stack app to Koyeb using Docker Compose. Ensure you place this file in the .github/workflows/
directory.
name: github-actions-docker-compose-koyeb
on:
push:
branches:
- main
jobs:
frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository Code
uses: actions/checkout@v2
- name: Install and configure the Koyeb CLI
uses: koyeb-community/koyeb-actions@v2
with:
api_token: "${{secrets.KOYEB_API_TOKEN}}"
- name: Build and deploy the application to Koyeb
uses: koyeb/action-git-deploy@v1
with:
app-name: glowberry-tax-structure-simulator-gha-docker-compose-koyeb
service-name: glowberry-tax-structure-simulator-gha-docker-compose-koyeb
service-instance-type: free
git-builder: docker
git-docker-dockerfile: Dockerfile.koyeb
service-env: PORT=3000
service-ports: "3000:http"
service-routes: "/:3000"
privileged: true
Step-by-step Breakdown
- Workflow Trigger
on:
push:
branches:
- main
The workflow triggers whenever you push changes to the main
branch, ensuring that your deployment stays up to date with the latest code.
- Job Environment
jobs:
frontend:
runs-on: ubuntu-latest
The job runs on the latest stable Ubuntu environment hosted by GitHub Actions.
- Step 1: Checkout Code
- name: Checkout Repository Code
uses: actions/checkout@v2
This step checks out your repository code so the workflow can access your Dockerfiles and source code.
- Step 2: Install and Configure Koyeb CLI
- name: Install and configure the Koyeb CLI
uses: koyeb-community/koyeb-actions@v2
with:
api_token: "${{secrets.KOYEB_API_TOKEN}}"
This action installs the Koyeb CLI tool and authenticates it with your API token stored securely in GitHub Secrets. This allows subsequent commands to interact with your Koyeb account.
-
Step 3: Build and Deploy the Application to Koyeb — Detailed Explanation
- name: Build and deploy the application to Koyeb uses: koyeb/action-git-deploy@v1 with: app-name: glowberry-tax-structure-simulator-gha-docker-compose-koyeb service-name: glowberry-tax-structure-simulator-gha-docker-compose-koyeb service-instance-type: free git-builder: docker git-docker-dockerfile: Dockerfile.koyeb service-env: PORT=3000 service-ports: "3000:http" service-routes: "/:3000" privileged: true
- app-name: The unique name assigned to your application on Koyeb, used to identify it in the platform.
-
service-name: The name of the specific service instance running your app within the application, often the same as
app-name
. -
service-instance-type: The tier or resource size allocated for the service instance. Commonly set to
free
for small/test deployments. -
git-builder: Specifies the build system to use, here
docker
, which means building Docker images from Dockerfiles. -
git-docker-dockerfile: The Dockerfile path used as the build entry point.
Dockerfile.koyeb
orchestrates the build using the docker-compose setup. -
service-env: Environment variables to set inside the running container. Here,
PORT=3000
configures the app’s listening port. -
service-ports: Maps container ports to protocols for exposure.
"3000:http"
exposes port 3000 over HTTP. -
service-routes: Defines URL routing rules.
"/:3000"
routes root requests/
to port 3000 inside the container. -
privileged: Boolean flag to enable privileged mode (
true
), required for Docker-in-Docker or Docker Compose usage inside the container.
Deploying to Koyeb
Once the CI/CD pipeline is configured and your GitHub repository contains all the necessary files (Dockerfiles, docker-compose.yml
, Dockerfile.koyeb
, and the GitHub Actions workflow), deployment to Koyeb becomes a seamless process.
1. Push to GitHub
With everything in place, initiate a deployment by pushing your code to the main
branch (or the branch specified in the workflow's on.push.branches
section):
git add .
git commit -m "Deploy full stack app to Koyeb using GitHub Actions"
git push origin main
Each push to the
main
branch will automatically trigger a new GitHub Actions workflow run.
2. Monitor the Deployment via GitHub Actions
After pushing, navigate to your GitHub repository in the browser and:
- Click on the Actions tab.
- Locate the latest workflow run at the top of the list.
- Click into the run to see the job steps executing in real-time.
- Ensure all steps complete successfully, especially the Build and deploy the application to Koyeb step.
You should see logs showing successful Docker image builds, Koyeb CLI usage, and confirmation that the deployment was completed.
3. Confirm on Koyeb
Once the workflow completes:
- Go to Koyeb Dashboard.
- Find your application by the
app-name
you defined in the GitHub Actions workflow. - Check the deployment status, logs, and access URL.
- Your app should now be live and accessible via the assigned Koyeb subdomain or custom domain if configured.
Conclusion
With this setup, you now have a production-ready CI/CD pipeline that deploys your full stack Docker Compose application to Koyeb automatically on every push to the main
branch. From defining Dockerfiles for your frontend and backend, orchestrating them with docker-compose.yml
, and packaging the entire setup for Koyeb using a dedicated Dockerfile.koyeb
, each part works together to ensure consistent and reliable deployments.
By leveraging GitHub Actions, you’ve eliminated the need for manual scripts or one-off deployment steps. Once your Koyeb API token is configured as a GitHub secret, the workflow handles the rest—building, pushing, and deploying—without requiring additional effort from your end.
This kind of workflow not only saves time but also enforces best practices for modern DevOps and continuous delivery. It’s a strong foundation for scaling your projects and team collaboration going forward.
Found this guide helpful? Follow EphraimX for more hands-on DevOps walkthroughs. You can also connect with me on LinkedIn or explore more of my work on my portfolio.
Top comments (0)