Last updated
Running an Azure DevOps self-hosted agent on Synology NAS
How I moved scheduled publishing work from Microsoft-hosted minutes to a Synology NAS self-hosted Azure Pipelines agent, and what that changed for cost, control, and operations.
- Azure Pipelines Agent
- 4.273.0
- Docker
- 24.0.2
- Node.js
- 24.15.0
On this page
The self-hosted agent work started with a very plain failure message:
Your organization has no free minutes remaining.
The publishing workflow was scheduled correctly, but the job could not even start. The article generation code was not running. The build was not failing. Azure DevOps simply had no hosted execution time available for the organization.
That changed the problem from a CI bug into an execution-capacity decision.
Context
news.hwmoon.com and tech.hwmoon.com are static sites, but the production workflow is not static. The platform needs scheduled article generation, content validation, static builds, search index generation, and Azure Static Web Apps deployment.
The first version used Microsoft-hosted agents:
Azure DevOps schedule
-> Microsoft-hosted Ubuntu agent
-> generation and validation
-> Astro build
-> Static Web Apps deploy
That is a good default. It is easy to start, clean on every run, and requires almost no runner maintenance. The tradeoff is quota. A publishing system that runs many times per day can burn through free hosted minutes faster than expected.
Why Synology NAS
I already had a Synology NAS running continuously. That made it a reasonable execution host for repeatable automation work.
The target model became:
Azure DevOps schedule
-> self-hosted agent pool
-> Synology NAS Docker container
-> generation and validation
-> static build
-> deploy
The agent connects outbound to Azure DevOps. That matters. The NAS does not need to expose an inbound CI endpoint to the internet. Azure DevOps assigns jobs to the registered agent, and the agent pulls the work.
What I Do Not Publish
This is an operational build note, not a secrets dump. The public article intentionally avoids:
| Data | Reason |
|---|---|
| NAS internal IP | internal network identifier |
| SSH port | operational access detail |
| account names | account guessing risk |
| Azure DevOps PAT | secret |
| exact host labels | environment fingerprinting |
The useful public part is the design and the failure mode, not the private coordinates.
Agent Shape
The agent container needs the Azure Pipelines agent runtime, Node.js, Git, and enough build tooling for Astro and the project scripts.
The agent also needs a stable work directory. This becomes more important when deployment helper containers are involved, because some tasks start sibling containers through Docker rather than uploading files directly from the agent process.
The practical rule is:
The agent work directory must be stable from both the agent container view and the NAS host view.
If that rule is ignored, a later deployment task can succeed while uploading stale artifacts.
Benefits
The self-hosted agent solved the immediate hosted-minute problem, but the more valuable outcome was operational control.
| Area | Improvement |
|---|---|
| Cost | scheduled jobs no longer depend on hosted free minutes |
| Runtime | agent image can include the exact tools needed |
| Control | long-running publishing work is not constrained by hosted pool availability |
| Extensibility | future automation can run on the same agent pool |
| Observability | NAS, container, and pipeline state can be monitored together |
This is still not free. The cost moves from Azure hosted minutes to runner operations. The agent must be patched, observed, restarted, and occasionally cleaned up.
Operational Risks
Self-hosted runners add responsibility:
- the NAS can go offline
- the container can exit
- Docker storage can fill
- the agent can become stale
- host path mounts can drift
- credentials can expire
Because of that, the self-hosted agent is not just a cost optimization. It needs watchdog checks, Slack reporting, and clear runbooks.
Verification
The agent is healthy only when all of these are true:
agent registered in Azure DevOps
agent online in the target pool
scheduled pipeline can queue
job runs on the NAS agent
build output is produced in the expected work directory
deploy step updates the public site
public URL returns HTTP 200
The last item is important. A green pipeline is useful, but the public route is the real production signal.
Decision
The NAS self-hosted agent is the right fit for this platform because the workload is predictable, recurring, and under my operational control. Microsoft-hosted agents remain useful for clean validation, but the publishing path benefits from a dedicated runner.
The next layer is automation around the agent itself: watchdog checks, Slack reporting, and safe remediation tasks. A self-hosted agent should not become a server that only works when someone remembers to look at it.
Series
Publisher Infrastructure
Part 2 of 8. This series collects related build notes so the context is easier to follow later.
- 1. Building domain email with Azure DNS and Zoho Mail
- 2. Running an Azure DevOps self-hosted agent on Synology NAS
- 3. Why a successful Static Web Apps pipeline still returned 404
- 4. Using Azure Repos as the primary source and GitHub as a backup mirror
- 5. Automating NAS agent operations with Slack-based AIOps
- 6. Preventing another news.hwmoon.com article publishing outage
- 7. AdSense readiness operations for news.hwmoon.com
- 8. Fixing news.hwmoon.com deployment outages with self-healing agent healthchecks