Self-Hosted Azure DevOps Agents - Linux Setup Guide¶
Prerequisites¶
- Hetzner Cloud account with active project
- Ubuntu 22.04 LTS server provisioned on Hetzner Cloud
- SSH access to the server (SSH key or password)
- Azure DevOps organization access
- Personal Access Token (PAT) with Agent Pools (Read & Manage) scope
Step 0: SSH Key Setup (Recommended)¶
Option A: Generate SSH Key (Recommended for Security)¶
SSH keys provide more secure authentication than passwords. Generate a key pair:
On Windows (PowerShell):
# Generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "your-email@example.com"
# When prompted:
# - File location: Press Enter for default (C:\Users\YourUser\.ssh\id_rsa)
# - Passphrase: Optional but recommended for additional security
# View public key (to add to Hetzner Cloud)
Get-Content ~\.ssh\id_rsa.pub
On Linux/Mac:
# Generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "your-email@example.com"
# When prompted:
# - File location: Press Enter for default (~/.ssh/id_rsa)
# - Passphrase: Optional but recommended for additional security
# View public key (to add to Hetzner Cloud)
cat ~/.ssh/id_rsa.pub
Add SSH Key to Hetzner Cloud:
1. Log into Hetzner Cloud Console: https://console.hetzner.cloud
2. Navigate to Security → SSH Keys
3. Click Add SSH Key
4. Paste your public key content (from id_rsa.pub)
5. Give it a name (e.g., "My Laptop")
6. Click Add
Option B: Use Password Authentication¶
If you prefer password authentication:
- During server creation in Hetzner Cloud, you can set a root password
- Hetzner will email you the root password
- Use this password when connecting via SSH
Note: Password authentication is less secure than SSH keys. Consider using SSH keys for production environments.
Step 1: Server Selection and Purchase¶
Recommended Server Types¶
- CPX32: 6 vCPU, 12 GB RAM, 200 GB SSD (~€12-15/month) - Recommended for production builds
- Alternative options:
- CPX31: 4 vCPU, 8 GB RAM, 160 GB SSD (~€8.90/month) - For light builds
- CPX41: 8 vCPU, 16 GB RAM, 240 GB SSD (~€17.90/month) - For heavy builds
- CCX23: Dedicated CPU, 4 vCPU, 8 GB RAM, 160 GB SSD (~€25.90/month) - For consistent performance
Purchase Steps¶
- Log into Hetzner Cloud Console: https://console.hetzner.cloud
- Navigate to Servers → Add Server
- Select location (Nuremberg, Falkenstein, or Helsinki)
- Choose server type (CPX32 recommended)
- Select Ubuntu 22.04 as the image
- Configure SSH keys for secure access
- Add to project and create server
Step 2: Initial Server Configuration¶
Connect to Server¶
Using SSH Key (Recommended):
# Connect using SSH key
ssh root@<server-ip>
# If your SSH key is in a non-default location:
ssh -i ~/.ssh/id_rsa root@<server-ip>
# On Windows (PowerShell):
ssh -i C:\Users\YourUser\.ssh\id_rsa root@<server-ip>
Using Password:
# Connect using password
ssh root@<server-ip>
# Enter password when prompted (password provided by Hetzner)
Troubleshooting Connection: - If connection is refused, wait a few minutes for server to fully boot - Verify server IP address in Hetzner Cloud Console - Check firewall rules allow SSH (port 22) - For Windows, ensure you're using OpenSSH client (included in Windows 10/11)
Update System¶
Install Prerequisites¶
Install Docker (Required for Container Services)¶
Important: Docker is required if your pipelines use container services (redis, mssql, mongodb, etc.). Install Docker before creating the agent user.
# Add Docker's official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Set up repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start Docker service
sudo systemctl start docker
sudo systemctl enable docker
# Verify installation
sudo docker run hello-world
Create Agent User¶
# Create dedicated user for Azure DevOps agent
sudo useradd -m -s /bin/bash azdevops
# Add to sudo and docker groups
sudo usermod -aG sudo,docker azdevops
# Set up password-less sudo (optional, for automation)
echo "azdevops ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/azdevops
Step 3: Install Azure DevOps Agent¶
Download Agent¶
# Switch to agent user
sudo su - azdevops
# Create agent directory
mkdir -p ~/azagent && cd ~/azagent
# Download latest agent (check https://github.com/microsoft/azure-pipelines-agent/releases for latest version)
AGENT_VERSION="4.268.0"
curl -LO https://download.agent.dev.azure.com/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
# Extract agent
tar xzf vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
Configure Agent¶
Before configuring, ensure you have:
- Azure DevOps organization URL (e.g., https://dev.azure.com/dmitrykhaymov/)
- Personal Access Token (PAT) with Agent Pools (Read & Manage) scope
- Agent pool name (e.g., Hetzner-Linux)
# Configure agent
./config.sh \
--url https://dev.azure.com/dmitrykhaymov/ \
--auth pat \
--token 1v8VufvD7tA3FuwLnLfiqJ8wljWfhBTRKhFoiOV4XYgixmlnLSGJJQQJ99ALACAAAAAAAAAAAAASAZDOVMlL \
--pool "Default" \
--agent "hetzner-linux-01" \
--work _work \
--acceptTeeEula \
--unattended \
--replace
Configuration Options:
- --url: Your Azure DevOps organization URL
- --auth pat: Use Personal Access Token authentication
- --token: Your PAT token
- --pool: Agent pool name (create in Azure DevOps first)
- --agent: Unique agent name
- --work: Working directory for agent
- --acceptTeeEula: Accept the Team Explorer Everywhere license
- --unattended: Run without prompts
- --replace: Replace existing agent configuration if present
Install as Systemd Service¶
# Install service
sudo ./svc.sh install azdevops
# Start service
sudo ./svc.sh start
# Check status
sudo ./svc.sh status
# Enable auto-start on boot
sudo systemctl enable 'vsts.agent.dmitrykhaymov.Default.hetzner\x2dlinux\x2d01.service'
Verify Agent Status¶
# Check service status
sudo systemctl status 'vsts.agent.dmitrykhaymov.Default.hetzner\x2dlinux\x2d01.service'
# View agent logs
sudo journalctl -u 'vsts.agent.dmitrykhaymov.Default.hetzner\x2dlinux\x2d01.service' -f
Step 4: Install Build Tools¶
Install .NET SDK¶
# Add Microsoft package repository
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
# Install .NET 9 SDK
sudo apt update
sudo apt install -y dotnet-sdk-9.0
# Verify installation
dotnet --version
Install Node.js (Optional)¶
# Install Node.js 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify installation
node --version
npm --version
Install Additional Tools¶
Based on your pipeline requirements, install additional tools:
# Git (usually pre-installed)
sudo apt install -y git
# Build tools
sudo apt install -y build-essential
# Python (if needed)
sudo apt install -y python3 python3-pip
# Java (if needed)
sudo apt install -y default-jdk
Install Ollama (Optional - For AI Tests)¶
If your pipelines or acceptance tests use AI functionality with Ollama models, install Ollama:
Quick Installation:
# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh
# Start and enable service
sudo systemctl start ollama
sudo systemctl enable ollama
# Pull required models
ollama pull Qwen3-0.6B-GGUF
ollama pull nomic-embed-text
# Verify installation
ollama list
For detailed instructions, see the Ollama Installation Guide.
Note: Ollama is optional but recommended if you run AI acceptance tests. It provides local AI inference without external API dependencies.
Step 5: Configure Agent Capabilities¶
In Azure DevOps:
- Navigate to Organization Settings → Agent Pools → Hetzner-Linux
- Select your agent
- Go to Capabilities tab
- Add custom capabilities:
Agent.OS:LinuxAgent.Version:3.248.0Docker:true(if Docker installed)DotNet:9.0.xNode:20.x(if Node.js installed)
Step 6: Network Configuration¶
Firewall Rules¶
Ensure the server can communicate with Azure DevOps:
# Allow outbound HTTPS (443) - usually allowed by default
# Allow SSH (22) for management
sudo ufw allow 22/tcp
sudo ufw enable
Test Connectivity¶
# Test Azure DevOps connectivity
curl -I https://dev.azure.com
# Test DNS resolution
nslookup dev.azure.com
Step 7: Verify Agent Registration¶
- In Azure DevOps, navigate to Organization Settings → Agent Pools
- Select Hetzner-Linux pool
- Verify your agent appears in the list
- Agent status should be Online (green)
Step 8: Test with a Pipeline¶
Create a simple test pipeline:
pool:
name: 'Hetzner-Linux'
demands:
- Agent.OS -equals Linux
steps:
- script: |
echo "Running on self-hosted Linux agent"
uname -a
df -h
dotnet --version
displayName: 'Test Agent'
Maintenance¶
Update Agent¶
Update Agent¶
# Stop service
sudo ./svc.sh stop
# Download new version
AGENT_VERSION="3.248.0" # Update to latest version
curl -LO https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
tar xzf vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
# Restart service
sudo ./svc.sh start
Uninstall Agent¶
# Stop and remove service
sudo ./svc.sh stop
sudo ./svc.sh uninstall
# Remove agent directory
cd ~
rm -rf ~/azagent
Troubleshooting¶
Agent Not Appearing in Azure DevOps¶
- Verify PAT token has correct permissions
- Check agent configuration:
cat ~/azagent/.agent - Review agent logs:
sudo journalctl -u vsts.agent.*.service -n 50
Agent Offline¶
- Check service status:
sudo systemctl status vsts.agent.*.service - Verify network connectivity:
curl -I https://dev.azure.com - Check firewall rules
- Review agent logs for errors
Build Failures¶
- Verify required tools are installed
- Check disk space:
df -h - Review build logs in Azure DevOps
- Check agent capabilities match pipeline demands
Next Steps¶
- Set up additional Linux agents for redundancy
- Configure Windows agents if needed
- Set up monitoring and maintenance procedures
- Review troubleshooting guide for common issues