Streamlining CI/CD: How to Configure Gitea Actions for Self-Hosted Docker Builds and GHCR Deployment
Introduction
In the modern DevOps landscape, establishing an efficient, secure, and cost-effective Continuous Integration and Continuous Deployment (CI/CD) pipeline is crucial for software development teams. While major platforms like GitHub Actions and GitLab CI dominate the market, many organizations and independent developers prefer maintaining control over their infrastructure. Leveraging a self-hosted Virtual Private Server (VPS) offers unparalleled privacy, data sovereignty, and cost predictability.
Historically, hosting your own git repository meant sacrificing advanced automation unless you integrated complex external tools. However, with the evolution of Gitea Actions—a built-in CI/CD engine compatible with GitHub Actions workflow syntax—self-hosted automation has become incredibly accessible. This comprehensive guide will demonstrate exactly how to configure Gitea Actions on your private VPS to automatically build, package, and push Docker images directly to the GitHub Container Registry (GHCR).
---Understanding the Architecture
Before diving into the configuration, it is essential to understand how the components interact in this setup. Our architecture consists of three core pillars:
- Gitea Instance: Hosted on your VPS, serving as the central version control system where your source code resides.
- Gitea Runner (Act Runner): A lightweight daemon running on your VPS that listens for workflow jobs triggered by code commits or pull requests, executing them inside isolated environments.
- GitHub Container Registry (GHCR): The target registry hosted by GitHub where our final production-ready Docker images will be securely stored and versioned.
By processing the build workloads directly on your self-hosted VPS while utilizing GHCR for highly available image distribution, you achieve an optimal balance between private infrastructure control and robust delivery mechanics.---
Prerequisites
To follow this tutorial successfully, ensure you have the following prerequisites in place:
- A private VPS running a modern Linux distribution (e.g., Ubuntu 22.04 LTS or later) with a public IP address and a domain configured for your Gitea instance.
- Docker and Docker Compose installed on your VPS.
- A fully functional Gitea instance (version 1.19 or higher, as Gitea Actions requires modern engine support).
- A GitHub account with a Personal Access Token (PAT) generated. This token requires the
write:packages,read:packages, andreposcopes to allow the VPS runner to authenticate and push images to GHCR.
Step 1: Setting Up and Registering the Gitea Runner
Gitea utilizes a separate component called act_runner to execute workflows. Follow these steps to deploy and register the runner on your VPS.
1.1 Enable Actions in Gitea
First, ensure that Actions are enabled globally in your Gitea configuration file (app.ini). Open the configuration and verify or add the following section:
[actions]
ENABLED = trueRestart your Gitea service to apply the changes. Next, navigate to your Gitea site administration panel, go to Actions > Runners, and click Create New Runner. Copy the registration token provided; you will need it in the next step.
1.2 Deploy the Runner via Docker Compose
Create a dedicated directory on your VPS for the runner and establish a docker-compose.yml file to manage it seamlessly:
version: '3.8'
services:
runner:
image: gitea/act_runner:latest
environment:
- GITEA_INSTANCE_URL=[https://your-gitea-domain.com](https://your-gitea-domain.com)
- GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_COPIED_REGISTRATION_TOKEN
- GITEA_RUNNER_NAME=vps-ci-runner
- GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye
volumes:
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sock
restart: alwaysRun docker compose up -d to start the runner. Check your Gitea admin panel to confirm that the runner appears online and is ready to accept jobs.
Step 2: Configuring Secrets in Your Gitea Repository
To securely connect your self-hosted VPS to the GitHub Container Registry, you must store sensitive credentials safely. Hardcoding credentials into your workflow files is a severe security risk.
Navigate to your specific repository in Gitea, then go to Settings > Actions > Secrets. Add the following two secrets:
- GH_USERNAME: Your GitHub account username or organization name.
- GH_PAT: The GitHub Personal Access Token generated during the prerequisite phase.
Step 3: Creating the Gitea Actions Workflow
Gitea Actions seamlessly interprets the declarative YAML syntax used by GitHub Actions. Create a file named .gitea/workflows/build-push.yml within the root directory of your project repository.
Insert the following configuration details into the file:
name: Build and Push Docker Image to GHCR
on:
push:
branches:
- main
tags:
- 'v*'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout Source Code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ secrets.GH_USERNAME }}
password: ${{ secrets.GH_PAT }}
- name: Extract Docker Metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ghcr.io/${{ secrets.GH_USERNAME }}/my-app
tags: |
type=semver,pattern={{version}}
type=sha,format=short
type=ref,event=branch
- name: Build and Push Docker Image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max---Step 4: Executing and Verifying the Pipeline
With the configuration finalized, commit the workflow file and push it to your main branch on your Gitea repository:
git add .gitea/workflows/build-push.yml
git commit -m "ci: add Gitea Actions workflow for GHCR deployment"
git push origin mainOnce pushed, navigate to the Actions tab of your repository in the Gitea web interface. You will observe the workflow initialize in real-time. The runner on your VPS will intercept the task, pull your code, execute the Docker build command locally, authenticate against GitHub, and push the compiled image layers to ghcr.io.
To verify successful delivery, log into your GitHub account, look under your profile packages or organization tab, and check for the presence of the newly minted Docker container image tagged with either the branch name or commit SHA.
---Best Practices for Production Environments
While the basic setup provides immediate functionality, optimizing your self-hosted CI/CD workflow ensures long-term stability and security:
- Implement Cache Management: Notice the
cache-fromandcache-toparameters in our workflow. Utilizing layer caching drastically speeds up subsequent builds by reusing untouched instructions, preserving precious VPS CPU cycles and bandwidth. - Restrict Runner Permissions: Run the
act_runnercontainer under a dedicated, non-root system user wherever possible, and restrict access to the host'sdocker.sockto authorized applications only. - Monitor Disk Space: Continuous Docker building creates dangling images and build caches on your VPS over time. Implement a automated cron job executing
docker system prune -fperiodically to prevent disk exhaustion.
Conclusion
By coupling the lightweight efficiency of Gitea Actions with the scalable distribution architecture of the GitHub Container Registry, you construct an enterprise-grade CI/CD pipeline directly on your private VPS. This hybrid framework eliminates reliance on external execution credits, enhances resource utilization, and ensures your application artifacts remain secure and version-controlled. Implement this pipeline today to unlock autonomous deployment workflows custom-tailored to your infrastructure constraints.
