Skip to content

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

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 SecuritySSH 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:

  1. During server creation in Hetzner Cloud, you can set a root password
  2. Hetzner will email you the root password
  3. 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

  • 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

  1. Log into Hetzner Cloud Console: https://console.hetzner.cloud
  2. Navigate to ServersAdd Server
  3. Select location (Nuremberg, Falkenstein, or Helsinki)
  4. Choose server type (CPX32 recommended)
  5. Select Ubuntu 22.04 as the image
  6. Configure SSH keys for secure access
  7. 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

sudo apt update && sudo apt upgrade -y

Install Prerequisites

sudo apt install -y curl wget git build-essential ca-certificates gnupg lsb-release

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:

  1. Navigate to Organization SettingsAgent PoolsHetzner-Linux
  2. Select your agent
  3. Go to Capabilities tab
  4. Add custom capabilities:
  5. Agent.OS: Linux
  6. Agent.Version: 3.248.0
  7. Docker: true (if Docker installed)
  8. DotNet: 9.0.x
  9. Node: 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

  1. In Azure DevOps, navigate to Organization SettingsAgent Pools
  2. Select Hetzner-Linux pool
  3. Verify your agent appears in the list
  4. 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

References