Run a Self‑Hosted CI/CD Pipeline with GitHub Actions on VPS
Learn how to set up self‑hosted GitHub Actions runners on an AtoZNode VPS in India, covering installation, security, and workflow integration.
6 min read
Running a CI/CD pipeline on your own infrastructure gives you complete control over build environments, network latency, and cost structure. By deploying self‑hosted GitHub Actions runners on a dedicated VPS from AtoZNode, you keep sensitive code inside your data centre while still using GitHub’s workflow engine. This guide walks you through the full process – from provisioning a VPS to registering the runner and linking it to your repositories.
1. Why Use Self‑Hosted Runners on a Dedicated VPS?
Performance control: Choose the exact CPU, RAM, and storage you need for heavy builds or parallel jobs.
Network proximity: Keep traffic within your own region (e.g., Mumbai or Delhi) for faster clone and deployment times.
Custom environment: Pre‑install proprietary tools, licenses, or internal libraries that are not allowed on GitHub‑hosted runners.
Cost predictability: Pay a fixed monthly fee for the VPS instead of per‑minute charges for hosted runners.
2. Prerequisites
AtoZNode dedicated VPS with root (or sudo) access. The steps below cover both Debian/Ubuntu (apt) and AlmaLinux/Rocky/RHEL (dnf).
A GitHub account with admin rights on the repository or organization where you want to add the runner.
Basic knowledge of the Linux command line and SSH.
3. Preparing the VPS
3.1 Update the system
Keeping packages up‑to‑date reduces the risk of missing dependencies later.
Runner name: an identifier that appears in the GitHub UI.
Work folder: where the runner stores job artifacts.
Labels: custom tags you can reference in workflow runs-on clauses.
4.4 Set up the runner as a systemd service
Running the runner as a service ensures it starts on boot and restarts after failures.
Both OS families
$ sudo ./svc.sh install
$ sudo ./svc.sh start
Check the status with systemctl status actions.runner.*. The service runs under the actionsrunner user created earlier.
5. Securing and Scaling Your Runner
5.1 Restrict network access
Limit inbound traffic to SSH (port 22) from your own IP range. On AtoZNode you can adjust firewall rules via the control panel or iptables:
Both OS families (example with iptables)
# iptables -A INPUT -p tcp -s YOUR_IP/32 --dport 22 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j DROP
# iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# iptables -P INPUT DROP
5.2 Use a non‑root Docker socket (if Docker is needed)
Instead of giving the runner full root access, add the runner user to the docker group (see step 3.2). Ensure the Docker daemon is configured with --group docker or the default group is docker.
5.3 Horizontal scaling
For high‑throughput pipelines, spin up additional VPS instances and repeat the registration steps with unique names and labels (e.g., vps-runner-02, vps-runner-03). In your workflow, you can target a specific subset:
runs-on: [self-hosted, linux, vps]
GitHub will distribute jobs across all matching runners, balancing the load automatically.
6. Using the Self‑Hosted Runner in a GitHub Actions Workflow
Below is a minimal example that builds a Node.js app, runs tests, and pushes a Docker image to a private registry. Save it as .github/workflows/ci.yml in your repository.
name: CI on Self‑Hosted VPS
on:
push:
branches: [main]
jobs:
build:
runs-on: [self-hosted, linux, vps] # selects the runners we created
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build Docker image
run: |
docker build -t registry.example.com/myapp:${{ github.sha }} .
docker push registry.example.com/myapp:${{ github.sha }}
Because the runner resides on your VPS, the Docker daemon has direct access to your private registry without additional authentication steps, provided you have configured ~/.docker/config.json for the actionsrunner user.
7. Maintenance Tips
Regular updates: Periodically pull the latest runner release (download, extract, and run ./svc.sh restart) to stay compatible with GitHub.
Log rotation: The runner writes logs to /opt/actions-runner/_diag. Set up logrotate to prevent disk exhaustion.
Backup configuration: Store the .runner folder (contains the registration token) in a secure location; you can reuse it if you need to rebuild the VPS.
Monitor health: Use tools like htop, netstat, or AtoZNode’s monitoring panel to watch CPU, memory, and network usage during peak builds.
Conclusion
Deploying self‑hosted GitHub Actions runners on AtoZNode dedicated VPS instances gives Indian developers a powerful, cost‑effective way to run CI/CD pipelines under full control. By following the steps above – updating the system, installing the runner, securing the environment, and integrating it into your workflows – you can achieve reliable builds, faster deployments, and compliance with internal policies. As your projects grow, simply add more VPS runners and let GitHub’s scheduler balance the workload across them.