Set Up a Self-Hosted Linux Agent for Azure DevOps on Ubuntu

A practical step-by-step guide from the DevOps Micro Internship (DMI) Cohort 3 with Agentic AI
A self hosted Azure DevOps agent gives you more control over the machine that executes your CI/CD pipelines. Instead of relying entirely on Microsoft hosted agents, you can run pipeline jobs on your own Ubuntu virtual machine and install the tools, dependencies, and configurations your workloads require.
In this tutorial, we'll build a self hosted Linux agent using:
- Microsoft Azure — cloud platform
- Ubuntu 22.04+ — agent host
- Azure DevOps — CI/CD platform
- Personal Access Token (PAT) — agent registration authentication
- systemd — keeps the agent running as a Linux service
- YAML pipeline — validates the setup
Microsoft describes self hosted agents as machines you manage yourself, giving you greater control over installed dependencies and persistent machine level configuration. Microsoft Learn
Architecture
The basic setup looks like this:
The Azure DevOps agent runs on the Ubuntu VM and waits for jobs from the agent pool.
Prerequisites
Before starting, you'll need:
- An Azure DevOps organization
- An Azure DevOps project
- Permission to manage agent pools
- An Azure subscription
- An Ubuntu VM
- SSH access to the VM
- Internet connectivity from the VM
- A PAT with the required permissions
For current Azure DevOps documentation, Microsoft specifically states that agent registration using a PAT requires the Agent Pools (Read & manage) scope.
Security note: Never publish your PAT in screenshots, Git repositories, blog posts, terminal history, or pipeline logs.
Step 1: Create a Personal Access Token
A Personal Access Token, or PAT, is a credential that Azure DevOps can use to authenticate the agent during registration.
Microsoft recommends using PATs only when necessary because they are credentials that can be leaked or misused.
1. Open Azure DevOps
Sign in to your Azure DevOps organization.
Open your profile menu and select:
Click the User settings icon (top right, next to your profile picture) → Personal access tokens
Click + New Token
2. Configure the token
Give the token a descriptive name, for example:
SelfHostedAgentPAT
Choose the appropriate organization and set an expiration date.
For agent registration, select:
Agent Pools
→ Read & manage
Build
→ Read & Execute
The Microsoft documentation specifically identifies this scope for registering a self hosted agent.
If your particular pipeline operations require additional permissions, configure only the minimum scopes necessary rather than creating an unnecessarily broad token.
3. Create and securely store the PAT
Click Create.
Copy the token immediately and store it securely. Azure DevOps does not display the token value again after creation.
Step 2: Create an Azure DevOps Agent Pool
An agent pool is a collection of agents that can execute pipeline jobs.
From Azure DevOps:
Organization settings → Agent pools
Select: Add pool
Create a pool such as:
SelfhostedPool
Your pipeline will later target this pool.
Example:
Agent pools
SelfhostedPool
Step 3: Provision the Ubuntu VM
Next, create the machine that will run the Azure DevOps agent.
In my implementation, I used Microsoft Azure.
Create an Ubuntu virtual machine using Ubuntu 22.04 or a current supported Ubuntu release.
Configure:
- VM size appropriate for your workload
- SSH authentication
- Network connectivity
- Public IP or DNS name if required for SSH administration
- Appropriate inbound network rules
For a basic lab environment, SSH access is the main administrative requirement.
Step 4: Connect to the Ubuntu VM
From your local terminal, connect using SSH:
ssh <username>@<VM_PUBLIC_IP>
For example:
ssh azureuser@<PUBLIC_IP>
Once connected, verify the operating system:
cat /etc/os-release
You can also check the kernel:
uname -a
And confirm the current user:
whoami
A successful result confirms that you can administer the Ubuntu machine.
Step 5: Prepare the Agent Directory
Create a dedicated directory for the Azure DevOps agent.
For example:
mkdir ~/myagent
cd ~/myagent
The Azure Pipelines documentation recommends downloading the appropriate Linux agent package and extracting it into a directory of your choice before running config.sh
Step 6: Download the Azure DevOps Agent
Go to:
Azure DevOps → Organization settings → Agent pools → SelfhostedPool → Agents → New agent
Select:
Linux
Then choose the appropriate architecture for your VM, such as x64.
Azure DevOps provides the current download link and installation instructions from the New agent dialog. Microsoft Learn
Download the package onto your Ubuntu VM.
The exact filename changes as newer agent versions are released, so it's better to copy the current download command provided by Azure DevOps rather than hard-code an old version.
After downloading the package, extract it:
tar -xzf <agent-package>.tar.gz
Then verify the directory contents:
ls
You should see files including:
config.sh
run.sh
svc.sh
bin/
Step 7: Configure the Agent
From the agent directory, run:
./config.sh
The configuration wizard will ask for information such as:
Server URL:
Authentication type:
Personal access token:
Agent pool:
Agent name:
Work folder:
For the server URL, use your Azure DevOps organization URL:
https://dev.azure.com/<your-organization>
When prompted for authentication, select the PAT option.
Paste your PAT when requested.
Never paste the PAT into this blog post or capture it in a screenshot.
For the agent pool, enter:
SelfhostedPool
Choose an agent name such as:
ubuntu-agent-01
For the work directory, the default is generally fine:
_work
Azure DevOps documents config.sh as the standard configuration process for Linux self-hosted agents. Microsoft Learn
Step 8: Install the Agent as a systemd Service
An agent can be run interactively, but for a persistent build machine, running it as a system service is much more practical.
Azure DevOps provides the svc.sh script specifically for managing a Linux agent as a systemd service. Ubuntu supports this approach. Microsoft Learn
From the agent directory:
sudo ./svc.sh install
Then start the service:
sudo ./svc.sh start
Check its status:
sudo ./svc.sh status
You should see that the service is running.
sudo ./svc.sh status
showing that the agent service is running.
Step 9: Verify the Agent in Azure DevOps
Return to:
Organization settings → Agent pools → SelfhostedPool → Agents
If it does not appear immediately, check the service:
sudo ./svc.sh status
You can also inspect the system logs if troubleshooting is necessary.
This confirms that Azure DevOps can communicate with your self-hosted agent.
Step 10: Create a Test YAML Pipeline
Now let's prove that the agent can actually execute pipeline jobs.
Create a YAML pipeline targeting your self-hosted pool.
trigger: none
pool:
name: SelfhostedPool
steps:
- script: |
echo "Operating System:"
uname -a
echo "Current User:"
whoami
echo "Disk Usage:"
df -h
displayName: "Verify Self-Hosted Ubuntu Agent"
The important part is:
pool:
name: SelfhostedPool
This tells Azure DevOps to run the job using an agent from your custom pool.
The commands provide three simple checks:
uname -a
Confirms the Linux kernel and machine information.
whoami
Shows the account executing the pipeline.
df -h
Displays filesystem and disk usage.
Run the pipeline.
If everything is configured correctly, the job should be picked up by your Ubuntu VM.
Step 11: Verify the Pipeline Output
Open the pipeline run and inspect the job logs.
You should see output similar to:
Operating System:
Linux ...
Current User:
...
Disk Usage:
Filesystem Size Used Avail Use% Mounted on
...
This is the final validation that your Azure DevOps pipeline is executing commands directly on your self-hosted Ubuntu agent.
Screenshot 7
Capture the successful pipeline output showing:
uname -awhoamidf -h- Successful pipeline completion
Troubleshooting
If the agent doesn't appear online, start with the service:
sudo ./svc.sh status
If it isn't running:
sudo ./svc.sh start
If the service still fails, inspect the agent directory and service logs.
Also verify:
- The VM has internet connectivity.
- The agent was configured with the correct organization URL.
- The correct agent pool was selected.
- The PAT has the required Agent Pools (Read & manage) scope.
- The PAT hasn't expired or been revoked.
- The agent isn't already registered under an unexpected name.
Remember that the PAT is primarily used during agent registration when PAT authentication is selected; Microsoft also documents service principal authentication as an alternative. Microsoft Learn+1
Security Considerations
A self-hosted agent gives you more control, but that control also means you are responsible for the machine.
A few practices are especially important:
Never expose your PAT
Don't commit it to Git:
❌ config.yaml
❌ .env
❌ README.md
❌ screenshots
❌ pipeline logs
Microsoft recommends treating PATs with the same level of caution as passwords.
Use the minimum required permissions
Avoid creating a full-access PAT when a narrower scope is sufficient.
Keep the VM updated
Regularly apply Ubuntu security updates and keep the Azure DevOps agent current.
Don't run the agent as root
Microsoft's Linux agent documentation specifically notes that an agent service should not be run as the root user. Microsoft Learn
Protect the agent
A self-hosted agent executes pipeline jobs on your infrastructure. Treat the machine as part of your CI/CD security boundary.
My Implementation
For this DevOps Micro Internship assignment, my setup was:
| Component | Configuration |
|---|---|
| Cloud platform | Microsoft Azure |
| Operating system | Ubuntu |
| CI/CD platform | Azure DevOps |
| Agent pool | SelfhostedPool |
| Agent type | Self-hosted Linux |
| Authentication | Personal Access Token |
| Service manager | systemd |
| Test commands | uname -a, whoami, df -h |
| Issues encountered | None |
The completed workflow was:
PAT
↓
Azure DevOps Agent Pool
↓
Ubuntu VM
↓
Azure DevOps Agent
↓
systemd service
↓
Agent Online
↓
YAML Pipeline
↓
Linux commands executed successfully
What I Learned
The biggest lesson from this exercise was that a self-hosted Azure DevOps agent is more than simply installing an application on a VM.
You are connecting three layers:
Cloud infrastructure → CI/CD platform → execution environment
The Azure VM provides the infrastructure, Azure DevOps manages the pipeline orchestration, and the self-hosted agent provides the bridge that actually executes the job.
That distinction becomes increasingly important when working with DevOps infrastructure, because the environment executing your pipeline can directly affect dependencies, permissions, networking, caching, security, and deployment workflows.
Conclusion
Setting up a self-hosted Linux agent is a useful hands-on exercise for understanding how Azure DevOps, Linux, cloud infrastructure, authentication, systemd, and CI/CD pipelines work together.
Once the basic agent is working, the same foundation can be extended to more realistic DevOps scenarios involving Docker, Terraform, Ansible, security scanning, custom build dependencies, and deployment automation.
P.S. This post is part of the DevOps Micro Internship (DMI) with Agentic AI — Cohort 3 — by [Pravin Mishra](https://www.linkedin.com/in/pravin-mishra-aws-trainer/). My graded progress is public: https://dmi.pravinmishra.com/s/wisegeorge1.html · Start your DevOps journey: https://dmi.pravinmishra.com/?utm_source=student&utm_medium=ps-linkedin&utm_campaign=cohort3
Comments
Join the discussionNo comments yet. Be the first to comment.


