{"id":2499,"date":"2026-09-12T12:21:45","date_gmt":"2026-09-12T12:21:45","guid":{"rendered":"https:\/\/ukspeed.co.uk\/blog\/self-hosted-cicd-uk-vps-gitea-actions-vs-woodpecker-vs-drone-2026\/"},"modified":"2026-09-12T12:43:28","modified_gmt":"2026-09-12T12:43:28","slug":"self-hosted-cicd-uk-vps-gitea-actions-vs-woodpecker-vs-drone-2026","status":"publish","type":"post","link":"https:\/\/ukspeed.co.uk\/blog\/self-hosted-cicd-uk-vps-gitea-actions-vs-woodpecker-vs-drone-2026\/","title":{"rendered":"Self-Hosted CI\/CD on UK VPS: Gitea Actions vs Woodpecker vs Drone 2026"},"content":{"rendered":"<p>Setting up self-hosted CI\/CD on a UK VPS gives your team automated builds, tests and deployments without paying per-minute fees to a SaaS platform or shipping your source code to servers you do not control. For UK developers, DevOps engineers and agencies watching both costs and data residency, running your own pipeline on a modest virtual server is increasingly practical. This guide explains what self-hosting CI\/CD really means, why teams choose it, and how three lightweight tools \u2014 Gitea Actions, Woodpecker CI and Drone CI \u2014 compare, install and secure on a UK VPS.<\/p>\n\n<h2 class=\"wp-block-heading\">What Is Self-Hosted CI\/CD?<\/h2>\n\n<p>CI\/CD stands for continuous integration and continuous delivery (or deployment). In plain terms, it means automatically building, testing and deploying your code every time you push a commit or open a pull request. A CI\/CD server watches your Git repository, and when something changes it runs a series of steps you have defined \u2014 install dependencies, run tests, build an artefact, and push it to a server.<\/p>\n\n<p>The &#8220;self-hosted&#8221; part simply means you run that CI server and its build agents on your own infrastructure \u2014 a UK VPS, for example \u2014 rather than relying on a hosted service such as GitHub Actions or GitLab.com. Every build spins up a short-lived Docker container on a machine you own, so your build artefacts, environment variables and source code never leave your control. If you already run your own Git server, self-hosting the pipeline that sits on top of it is a natural next step.<\/p>\n\n<h2 class=\"wp-block-heading\">Why Self-Host Your CI\/CD Pipeline<\/h2>\n\n<p>The most common reason is cost. Hosted CI platforms bill by the build minute, and a busy team with frequent pushes and long test suites can burn through free tiers quickly. A self-hosted CI\/CD pipeline on a fixed-price VPS removes per-minute billing entirely: you pay for the server, and you can run as many builds as the hardware allows.<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>No per-minute fees<\/strong> \u2014 a flat monthly VPS cost instead of metered build minutes.<\/li><li><strong>UK data and code residency<\/strong> \u2014 source, secrets and build artefacts stay on UK-based servers, which matters for compliance and client contracts.<\/li><li><strong>Control<\/strong> \u2014 you choose the exact runtime, tooling versions, caching strategy and network access.<\/li><li><strong>Private runners<\/strong> \u2014 builds run on your own agents, so nothing touches a shared multi-tenant fleet.<\/li><li><strong>A clean <a href=\"https:\/\/ukspeed.co.uk\/blog\/self-host-git-uk-vps-gitea-vs-forgejo-vs-gitlab-ce-2026\/\">GitHub Actions alternative<\/a><\/strong> that pairs with a Git server you also host.<\/li><\/ul>\n\n<h3 class=\"wp-block-heading\">What You Need for Self-Hosted CI\/CD<\/h3>\n\n<p>Getting started with self-hosted CI\/CD is refreshingly light. You need a UK VPS running a recent Linux distribution, Docker and Docker Compose installed, a Git server (self-hosted Gitea, Forgejo, GitLab CE, or a remote forge), and a domain with HTTPS so your CI web interface is reachable securely. Because each build runs in an ephemeral container, a 2 vCPU \/ 4 GB VPS is comfortable for small to mid-sized teams; heavy parallel builds simply want more RAM and CPU. If you are already running <a href=\"https:\/\/ukspeed.co.uk\/blog\/docker-compose-wordpress-production-on-uk-vps-full-stack-setup-guide-2026\/\">Docker Compose on a UK VPS<\/a>, you have almost everything in place.<\/p>\n\n<h2 class=\"wp-block-heading\">Gitea Actions vs Woodpecker vs Drone<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/ci1-compare.svg\" alt=\"Self-hosted CI\/CD compared: Gitea Actions vs Woodpecker vs Drone on syntax, footprint and governance\" class=\"wp-image-2501\" \/><figcaption class=\"wp-element-caption\">Gitea Actions, Woodpecker and Drone compared &mdash; all run pipelines as Docker steps on your own UK VPS.<\/figcaption><\/figure>\n\n\n<p>All three tools share the same core model: pipelines are defined in a YAML file inside your repository, steps run as Docker containers on a runner, and you register that runner against the CI server with a token. Where they differ is heritage, syntax and how tightly they couple to your Git server.<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>Gitea Actions<\/strong> is built directly into Gitea and Forgejo. It uses GitHub-Actions-compatible workflow syntax in <code>.gitea\/workflows\/*.yml<\/code> and runs on <code>act_runner<\/code>. If you already self-host Gitea, it is the least additional software to manage.<\/li><li><strong>Woodpecker CI<\/strong> is a lightweight open-source project with roots in the Drone codebase, now community-governed. Pipelines live in <code>.woodpecker.yml<\/code>, steps are Docker-based, and it connects to Gitea, GitHub or GitLab as the &#8220;forge&#8221;. It is very light and well documented.<\/li><li><strong>Drone CI<\/strong> is mature and container-native, with pipelines in <code>.drone.yml<\/code> and a large plugin ecosystem. Its ownership moved under Harness, and while the open-source edition still exists, development focus shifted \u2014 which is partly why Woodpecker forked. Weigh that governance question against its plugin maturity.<\/li><\/ul>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Tool<\/th><th>Pipeline file<\/th><th>Runner<\/th><th>Best when<\/th><th>Governance<\/th><\/tr><\/thead><tbody><tr><td>Gitea Actions<\/td><td>.gitea\/workflows\/*.yml<\/td><td>act_runner<\/td><td>You already run Gitea\/Forgejo<\/td><td>Gitea project (OSS)<\/td><\/tr><tr><td>Woodpecker CI<\/td><td>.woodpecker.yml<\/td><td>Woodpecker agent<\/td><td>Light standalone CI, clean YAML<\/td><td>Community-governed (OSS)<\/td><\/tr><tr><td>Drone CI<\/td><td>.drone.yml<\/td><td>Drone runner<\/td><td>You need mature plugins<\/td><td>Harness-owned<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<h2 class=\"wp-block-heading\">How to Install Gitea Actions on UK VPS<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/ci2-flow.svg\" alt=\"A self-hosted CI\/CD pipeline flow from git push to automated deploy on a UK VPS\" class=\"wp-image-2503\" \/><figcaption class=\"wp-element-caption\">A self-hosted CI\/CD pipeline: push triggers build and test in a runner, then auto-deploys &mdash; no per-minute billing.<\/figcaption><\/figure>\n\n\n<p>If your Git server is Gitea, enabling Actions is the fastest route. First, switch the feature on in <code>app.ini<\/code>, then register a runner and start its daemon. The runner is what actually executes your Docker-based steps.<\/p>\n\n<pre class=\"wp-block-code\"><code># In Gitea's app.ini\n[actions]\nENABLED = true\n\n# On the runner host (as a non-root user):\nact_runner register \n  --instance https:\/\/git.example.co.uk \n  --token &lt;REGISTRATION_TOKEN&gt; \n  --name uk-vps-runner \n  --labels ubuntu-latest:docker:\/\/node:20-bookworm\n\nact_runner daemon<\/code><\/pre>\n\n<p>The registration token comes from your Gitea admin or repository settings. Once the daemon is running, any workflow file under <code>.gitea\/workflows\/<\/code> is picked up automatically. Because the syntax mirrors GitHub Actions, many existing workflow files run with little or no change, which makes Gitea Actions a comfortable GitHub Actions alternative for teams migrating in-house. For deeper background on standing up the Git server itself, the <a href=\"https:\/\/woodpecker-ci.org\/docs\/intro\" rel=\"noopener\" target=\"_blank\">Woodpecker CI documentation<\/a> is also a useful reference for how forges and CI servers connect, even if you ultimately choose Gitea Actions.<\/p>\n\n<h2 class=\"wp-block-heading\">How to Set Up Woodpecker and Drone<\/h2>\n\n<p>Woodpecker and Drone both run as a server plus one or more agents, and both install cleanly with Docker Compose. The server handles the web UI and talks to your forge over OAuth; the agent runs the actual build containers. Below is a trimmed Woodpecker example pointing at a self-hosted Gitea.<\/p>\n\n<pre class=\"wp-block-code\"><code>services:\n  woodpecker-server:\n    image: woodpeckerci\/woodpecker-server:latest\n    environment:\n      - WOODPECKER_HOST=https:\/\/ci.example.co.uk\n      - WOODPECKER_GITEA=true\n      - WOODPECKER_GITEA_URL=https:\/\/git.example.co.uk\n      - WOODPECKER_GITEA_CLIENT=&lt;OAUTH_CLIENT_ID&gt;\n      - WOODPECKER_GITEA_SECRET=&lt;OAUTH_SECRET&gt;\n      - WOODPECKER_AGENT_SECRET=&lt;LONG_RANDOM_STRING&gt;\n    ports:\n      - 8000:8000\n  woodpecker-agent:\n    image: woodpeckerci\/woodpecker-agent:latest\n    environment:\n      - WOODPECKER_SERVER=woodpecker-server:9000\n      - WOODPECKER_AGENT_SECRET=&lt;LONG_RANDOM_STRING&gt;\n    volumes:\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock<\/code><\/pre>\n\n<p>You create the OAuth application inside Gitea, paste the client ID and secret into the server environment, and share one <code>WOODPECKER_AGENT_SECRET<\/code> between server and agent. Drone follows an almost identical pattern \u2014 a <code>drone-server<\/code> container with your forge OAuth details plus a <code>drone-runner-docker<\/code> container registered with an RPC secret. Self-hosting CI\/CD this way keeps the whole toolchain \u2014 Git, CI server and runners \u2014 on one UK VPS.<\/p>\n\n<h2 class=\"wp-block-heading\">Build Your First Pipeline<\/h2>\n\n<p>A CI\/CD pipeline is just a YAML file committed to your repository. The example below, in Woodpecker&#8217;s format, clones the code, runs tests, builds the project and deploys on the main branch. Every step names a Docker image, so the runner pulls that image and runs your commands inside it.<\/p>\n\n<pre class=\"wp-block-code\"><code>steps:\n  test:\n    image: node:20-bookworm\n    commands:\n      - npm ci\n      - npm test\n  build:\n    image: node:20-bookworm\n    commands:\n      - npm run build\n  deploy:\n    image: appleboy\/drone-ssh\n    settings:\n      host: deploy.example.co.uk\n      username: deployer\n      key:\n        from_secret: ssh_key\n      script:\n        - cd \/srv\/app &amp;&amp; git pull &amp;&amp; systemctl restart app\n    when:\n      branch: main<\/code><\/pre>\n\n<p>Notice that the SSH key is pulled <code>from_secret<\/code> rather than written into the file. The Gitea Actions equivalent uses the familiar <code>jobs:<\/code> and <code>steps:<\/code> structure with <code>runs-on: ubuntu-latest<\/code>. Once committed, the pipeline runs automatically on your next push. Pipelines like this can just as easily deploy containers, sync <a href=\"https:\/\/ukspeed.co.uk\/blog\/self-hosted-n8n-on-uk-vps-workflow-automation-setup-guide-2026\/\">a self-hosted n8n instance<\/a>, or roll out to an orchestrator if you have chosen one.<\/p>\n\n<h2 class=\"wp-block-heading\">Secure Your Runners and Secrets<\/h2>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/ukspeed.co.uk\/blog\/wp-content\/uploads\/2026\/09\/ci3-secure.svg\" alt=\"Securing CI\/CD runners and secrets on a self-hosted UK VPS\" class=\"wp-image-2505\" \/><figcaption class=\"wp-element-caption\">Runners execute repo code, so isolate them, run as non-root, and keep secrets in the CI store &mdash; never in the YAML.<\/figcaption><\/figure>\n\n\n<p>Runners execute arbitrary code from your repositories, so treat them as the most sensitive part of the system. A compromised or careless runner can expose secrets or take over the host. The safeguards are straightforward but non-negotiable.<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>Isolate runners<\/strong> \u2014 run them on a dedicated user, ideally a separate VPS or an isolated container, never as root on the host.<\/li><li><strong>Use dedicated runner tokens<\/strong> \u2014 one token per runner, revocable independently.<\/li><li><strong>Store secrets in the CI secret store<\/strong> \u2014 reference them with <code>from_secret<\/code>; never hard-code credentials in your YAML.<\/li><li><strong>Keep the CI behind HTTPS<\/strong> \u2014 terminate TLS at a reverse proxy and restrict admin access.<\/li><li><strong>Harden the host<\/strong> \u2014 follow standard <a href=\"https:\/\/ukspeed.co.uk\/blog\/how-to-harden-ssh-on-a-linux-vps-10-security-steps-beyond-just-changing-the-default-port\/\">SSH hardening steps<\/a> and firewall everything that does not need to be public.<\/li><\/ul>\n\n<p>Mounting the Docker socket into an agent gives it broad control of the host, so limit who can push pipeline changes and review pull-request builds from untrusted forks carefully.<\/p>\n\n<h2 class=\"wp-block-heading\">Choose the Right CI\/CD Tool<\/h2>\n\n<p>The decision usually comes down to what you already run and how much plugin ecosystem you need. All three are light enough for a small VPS because builds are ephemeral containers.<\/p>\n\n<ul class=\"wp-block-list\"><li><strong>Choose Gitea Actions<\/strong> if you already self-host Gitea or Forgejo \u2014 it is the least extra software and reuses GitHub Actions syntax.<\/li><li><strong>Choose Woodpecker CI<\/strong> if you want a light, standalone CI server with clean YAML and active community governance.<\/li><li><strong>Choose Drone CI<\/strong> if you rely on its mature plugin ecosystem, while keeping the Harness ownership question in mind.<\/li><\/ul>\n\n<p>If containers are central to your stack, it is also worth reading up on <a href=\"https:\/\/ukspeed.co.uk\/blog\/kubernetes-vs-docker-swarm-in-2026-which-container-orchestrator-should-you-self-host\/\">Kubernetes vs Docker Swarm<\/a>, since your CI\/CD pipeline will often be the thing that deploys to them.<\/p>\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n<p>Self-hosted CI\/CD is no longer heavyweight or expensive. With Docker, a Git server and a modest UK VPS, any team can run private, fixed-cost pipelines that keep code and artefacts in the UK. Gitea Actions, Woodpecker and Drone each hit a slightly different sweet spot, but all three prove that owning your build automation is well within reach.<\/p>\n\n<p>A UK Speed VPS gives you the fixed-price, UK-based foundation to run any of them comfortably.<\/p>\n\n<ul class=\"wp-block-list\"><li>Provision a 2 vCPU \/ 4 GB UK VPS and install Docker and Docker Compose.<\/li><li>Stand up or connect your Git server, then pick the CI tool that matches it.<\/li><li>Register a runner with a dedicated token and put the web UI behind HTTPS.<\/li><li>Commit a small pipeline YAML and watch your first automated build run.<\/li><\/ul>\n\n\n<div class=\"wp-block-group uks-cta-box has-border-color\" style=\"border-color:#bfdbfe;border-style:solid;border-width:1px;border-radius:14px;background-color:#eff6ff;padding:30px\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n\n<h3 class=\"wp-block-heading has-text-color\" style=\"color:#0f172a\">Run your CI\/CD on a UK Speed VPS<\/h3>\n\n\n<p class=\"has-text-color\" style=\"color:#334155\">Get the CPU, RAM and full root access to run Gitea Actions, Woodpecker or Drone on high-performance AMD EPYC hardware, hosted in the UK with no per-minute billing.<\/p>\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-text-color has-background wp-element-button\" href=\"https:\/\/ukspeed.co.uk\/vps-high-performance\" style=\"border-radius:8px;color:#ffffff;background-color:#2563eb\">Explore high-performance UK VPS &rarr;<\/a><\/div>\n<\/div>\n\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Setting up self-hosted CI\/CD on a UK VPS gives your team automated builds, tests and deployments without paying per-minute fees to a SaaS platform\u2026<\/p>\n","protected":false},"author":3,"featured_media":2519,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[105],"tags":[147,146,113,141,136,140],"class_list":["post-2499","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-docker","tag-linux","tag-performance","tag-security","tag-ssl","tag-vps"],"_links":{"self":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2499","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=2499"}],"version-history":[{"count":4,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2499\/revisions"}],"predecessor-version":[{"id":2513,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/posts\/2499\/revisions\/2513"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/media\/2519"}],"wp:attachment":[{"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=2499"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=2499"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ukspeed.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=2499"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}