If you want to run your own Git server and CI/CD pipeline without depending on GitHub or GitLab, Gitea self-hosted CI/CD Docker Compose is one of the best setups you can build. In this guide, you will learn a fully working self-hosted developer platform, including Git hosting, persistent storage, SMTP email, HTTPS, and an Actions runner, all running on your own server.
How to Install Gitea with Docker Compose and Add a Self-Hosted Actions Runner
Table of Contents
- What You Will Need for Gitea self-hosted CI/CD Docker Compose Setup
- Step 1. Create Project Directory and Gitea Docker Compose File
- Step 2. Start Gitea Docker Compose
- Step 3. Set up Nginx Reverse Proxy and HTTPS for Gitea
- Step 4. Access Gitea Web UI and Enable Gitea Actions
- Step 5. Create a Gitea Test Repository
- Step 6. Create the Workflow File in Gitea
- Step 7. Add the Self-hosted Runner
- Step 8. Test the First Workflow
- Security Note about Docker Socket Access in Gitea Runner
- Conclusion

What You Will Need for Gitea self-hosted CI/CD Docker Compose Setup
Before you start, make sure your server has the following:
- A Linux VPS or dedicated server running Ubuntu 24.04. A reliable Linux VPS works perfectly for this setup.
- Docker and Docker Compose are installed on your server.
- A domain name that is pointed at your server's IP address.
- Ports 80, 443, and 222 are open in your firewall.
Verify that Docker is installed correctly:
Step 1. Create Project Directory and Gitea Docker Compose File
First, make a folder for the stack and move into it:
Then, create the main Gitea self-hosted CI/CD Docker Compose file. It uses PostgreSQL, persistent storage, and the Gitea environment variables for server, database, Actions, and SMTP settings.
Replace the domain, passwords, and SMTP values before you start the stack. The mounted folders keep your data safe across container restarts because Gitea stores data in /data and PostgreSQL stores data in its data directory.
Step 2. Start Gitea Docker Compose
At this point, you can start the containers with:
If needed, check the logs with:
You can open your browser and navigate to the URL below:
Step 3. Set up Nginx Reverse Proxy and HTTPS for Gitea
First, you must start with a simple port 80 reverse proxy. This avoids the common Certbot problem where Nginx fails because SSL files do not exist yet.
Install Nginx and Certbot:
Create the Nginx config file for Gitea:
Add the following content with your domain:
Enable the site and test it:
This simple block is enough to proxy requests to Gitea on port 3000 and matches the normal Nginx reverse proxy pattern for Gitea.
To add HTTPS, you must request the certificate with certbot:
After Certbot finishes, test again:
At this point, update Gitea so the public URL uses HTTPS. Edit docker-compose.yml and change:
Then restart Gitea:
Step 4. Access Gitea Web UI and Enable Gitea Actions
At this point, you can open your browser and open Gitea:
Since the database and most settings are already passed in by environment variables, the first setup is much easier. Click Install Gitea.

After this, you must register an admin account:

Now you will see your Gitea dashboard. Gitea Actions has been available as a built-in feature since Gitea 1.19, so you do not need an extra CI server for basic workflows.
Because the Compose file already includes this line, Actions is enabled:
You can confirm it from the Gitea admin side under Site Administration → Actions → Runners.

Step 5. Create a Gitea Test Repository
To test Gitea self-hosted CI/CD Docker Compose, create a new repository in the web UI. The easiest way is to initialize it with a README, because a repository without its first commit cannot create files in the web UI.
You can use these simple settings:
- Owner: your user or organization.
- Repository Name: gitea-actions-test.
- Visibility: public for easier testing, or private if you prefer.
- Check Initialize Repository so Gitea creates the first commit.
- Default Branch: main.
- Leave template, issue labels, license, and .gitignore blank if this is only for testing.
This is the easiest way to get a test repo ready for your first workflow.

Step 6. Create the Workflow File in Gitea
Workflow files should be stored in .gitea/workflows/ inside the repository, and Gitea reads .yml or .yaml files from that folder.
In the repository:
Click Add File or New File. Use this exact file path:
Paste this content:
Then, commit the file to main. The first commit to this file should trigger a workflow run because the workflow listens for pushes to the main branch.

Step 7. Add the Self-hosted Runner
This is where Gitea self-hosted CI/CD Docker Compose becomes a full working platform. Gitea Runner 1.0.0 replaced the older act_runner naming, and the Docker image is now gitea/runner.
First, create a runner registration token in Gitea:
- Log in as admin.
- Open Site Administration.
- Go to Actions → Runners.
- Click Create New Runner.
- Copy the registration token.

Now add this runner service to your docker-compose.yml under services::
This runner uses the internal Docker service name gitea:3000, not the public domain. Putting both services on the same Docker network is important so the runner can reach Gitea correctly.
Start the runner:
Step 8. Test the First Workflow
After the runner is online, go back to your test repository and open the Actions tab. You should see the workflow run created by the commit that added .gitea/workflows/ci.yml.
If the workflow shows a quick failure with a red warning icon, click the run and then open the job logs. The first error usually comes from one of these:
- Workflow YAML syntax issue.
- No runner matched the label self-hosted.
- Runner is offline.
- The runner cannot reach the Gitea instance.
The fastest checks are:
- Open Site Administration → Actions → Runners and make sure the runner is Online.
- Confirm the job uses
runs-on: self-hosted. - Make sure the workflow file is inside
.gitea/workflows/.
Security Note about Docker Socket Access in Gitea Runner
The simplest runner setup mounts /var/run/docker.sock into the runner container so build jobs can start sibling containers. This is common, but it also means workflows can get high access to the Docker host if you run untrusted code.
Use these safety rules:
- Only run trusted repositories on that runner.
- Do not give public users a way to run optional workflows.
- Keep the runner limited to the repos you trust.
Keep Gitea updated because security fixes continue to land in new releases. To update the containers, you can use:
For production, it is smarter to isolate the runner on a separate host. A high-performance server is a better option if you want stronger isolation for CI jobs.
Conclusion
Now you have a complete Gitea self-hosted CI/CD Docker Compose platform, including Gitea, PostgreSQL, persistent storage, SMTP, Nginx, HTTPS, and a self-hosted runner. This setup gives you a private Git and CI system you control, and it is easy to grow from one test repo into a real internal developer platform.
We hope you enjoy this guide. For the official workflow file location and first Actions example, you can check the Gitea Actions Quick Start.
No. Gitea works fine as a Git server without a runner. The runner is only needed when you want to use Gitea Actions for CI/CD.
Because a repo without its first commit cannot create files from the web UI, adding a README makes the workflow setup much easier.
Yes. Gitea Actions is designed to be compatible with GitHub Actions-style workflows in many common cases.