Tools: How I Set Up a Self-Hosted Azure DevOps Agent on Ubuntu (And What I Learned the Hard Way) - Full Analysis

Tools: How I Set Up a Self-Hosted Azure DevOps Agent on Ubuntu (And What I Learned the Hard Way) - Full Analysis

What a Self-Hosted Agent Actually Is

What I Built

Step 1: Create a Personal Access Token

Step 2: Create the Agent Pool

Step 3: Provision the VM

Step 4: Get the Agent Download URL

Step 5: Install and Configure

Step 6: Verify in Azure DevOps

The Test Pipeline

What I Learned When you are just starting out with Azure DevOps, the managed Microsoft-hosted agents seem like the easy choice. Clean environment, no setup, just works. Then you hit the parallelism limit on a free plan and everything queues. That is what sent me down the path of setting up my own self-hosted agent. Here is exactly what I built and what tripped me up along the way. An agent is the thing that executes your pipeline jobs. When Azure DevOps runs a pipeline, it needs a machine to do the work. Microsoft-hosted agents are temporary VMs that spin up, do the job, and disappear. Convenient but limited. A self-hosted agent is one you run yourself, on infrastructure you control. It stays running between jobs, keeps its installed software, and has no parallelism limits. In Azure DevOps, click your profile picture at the top right, then go to Personal Access Tokens. Create a new one with: Copy it immediately. You will not see it again. Go to Organization Settings, then Pipelines, then Agent Pools. Click Add Pool. I created a Standard_D2s_v3 Ubuntu 22.04 VM on Azure via the portal. The key thing is opening port 443 for outbound communication. The agent talks to Azure DevOps over HTTPS. This is where I ran into my first real obstacle. The standard download domain was not resolving. The fix was to get the download URL directly from the Azure DevOps API: This gives you the exact URL for the latest agent version registered for your organization. Use that URL to download. When prompted, enter your organization URL, PAT, and pool name. Then start it as a service: Go to Organization Settings, then Agent Pools, then SelfHostedPool. Your agent should appear as Online. Run it. Watch all three steps execute on your VM. That green checkmark means your pipeline is running on infrastructure you built. Running as a system service is not optional for real use. If you run the agent interactively with ./run.sh, it dies when your SSH session ends. Install it as a service so it runs permanently. Port 443 must be open outbound, not inbound. The agent calls Azure DevOps, not the other way around. The API download method is more reliable than guessing version numbers. Always use it. This agent pool powered every pipeline in my Azure DevOps series. Projects 2, 3, and 4 all ran on it. Building it first was the right call. Vivian Chiamaka Okose is a DevOps Engineer documenting her learning journey in public. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">curl -s "https://dev.azure.com/YOUR_ORG/_apis/distributedtask/packages/agent/linux-x64?top=1&api-version=3.0" \ -u :YOUR_PAT | grep "downloadUrl" -weight: 500;">curl -s "https://dev.azure.com/YOUR_ORG/_apis/distributedtask/packages/agent/linux-x64?top=1&api-version=3.0" \ -u :YOUR_PAT | grep "downloadUrl" -weight: 500;">curl -s "https://dev.azure.com/YOUR_ORG/_apis/distributedtask/packages/agent/linux-x64?top=1&api-version=3.0" \ -u :YOUR_PAT | grep "downloadUrl" mkdir -p ~/azagent && cd ~/azagent -weight: 500;">curl -fSL "DOWNLOAD_URL_FROM_ABOVE" -o vsts-agent-linux-x64-4.271.0.tar.gz tar zxvf vsts-agent-linux-x64-4.271.0.tar.gz ./config.sh mkdir -p ~/azagent && cd ~/azagent -weight: 500;">curl -fSL "DOWNLOAD_URL_FROM_ABOVE" -o vsts-agent-linux-x64-4.271.0.tar.gz tar zxvf vsts-agent-linux-x64-4.271.0.tar.gz ./config.sh mkdir -p ~/azagent && cd ~/azagent -weight: 500;">curl -fSL "DOWNLOAD_URL_FROM_ABOVE" -o vsts-agent-linux-x64-4.271.0.tar.gz tar zxvf vsts-agent-linux-x64-4.271.0.tar.gz ./config.sh -weight: 600;">sudo ./svc.sh -weight: 500;">install -weight: 600;">sudo ./svc.sh -weight: 500;">start -weight: 600;">sudo ./svc.sh -weight: 500;">status -weight: 600;">sudo ./svc.sh -weight: 500;">install -weight: 600;">sudo ./svc.sh -weight: 500;">start -weight: 600;">sudo ./svc.sh -weight: 500;">status -weight: 600;">sudo ./svc.sh -weight: 500;">install -weight: 600;">sudo ./svc.sh -weight: 500;">start -weight: 600;">sudo ./svc.sh -weight: 500;">status trigger: - main pool: name: SelfHostedPool steps: - script: uname -a displayName: System Info - script: whoami displayName: Current User - script: df -h displayName: Disk Usage trigger: - main pool: name: SelfHostedPool steps: - script: uname -a displayName: System Info - script: whoami displayName: Current User - script: df -h displayName: Disk Usage trigger: - main pool: name: SelfHostedPool steps: - script: uname -a displayName: System Info - script: whoami displayName: Current User - script: df -h displayName: Disk Usage - Ubuntu 22.04 VM on Azure (Standard_D2s_v3) - A custom agent pool called SelfHostedPool - Azure Pipelines agent v4.271.0 installed as a system -weight: 500;">service - A test pipeline that confirmed everything was working - Agent Pools: Read and Manage - Build: Read and Execute - Type: Self-hosted - Name: SelfHostedPool - Grant access to all pipelines: checked