DEV Community

Cover image for Self-Hosted Deployment Automation for Windows: What IIS Pipelines Reveal About Agent Execution Boundaries
mech.app
mech.app

Posted on Originally published at mech.app

Self-Hosted Deployment Automation for Windows: What IIS Pipelines Reveal About Agent Execution Boundaries

Most agentic deployment tooling assumes Linux containers and ephemeral cloud infrastructure. fDeploy spent seven years solving the opposite problem: self-hosted Windows deployments to IIS, where state must survive service restarts, credentials live in Active Directory and certificate stores, and rollback means restoring app pool configurations rather than swapping container tags.

The architecture exposes plumbing constraints that any agent-driven deployment system faces when it cannot rely on cloud abstractions. Financial services, healthcare, and enterprise shops run Windows. Understanding how deployment state persists across reboots, how agents vault credentials without admin privileges, and how rollback works when IIS app pools can recycle mid-deployment matters for building robust automation.

Architecture: Server, Agent, and the State Boundary

fDeploy splits into two Windows services:

fDeploy Server runs the control plane on one machine. It hosts the dashboard, REST API, NuGet package repository, and release history. Projects, environments, target roles, variables, and deployment processes all live here.

fDeploy Agent runs on every deployment target. It receives packages over an authenticated channel, performs variable substitution, applies XDT transforms, configures IIS, and executes PowerShell scripts locally.

The boundary matters. The Server holds intent (what should deploy, where, and when). The Agent holds execution context (local file paths, IIS app pool state, Windows service handles). When an Agent restarts mid-deployment, it must either resume or fail cleanly. The Server cannot reach into the Agent's file system or registry to fix partial state.

State Persistence Across Windows Service Restarts

Windows services restart for patching, app pool recycling, or system reboots. A deployment agent must handle interruption at any step:

  • Package downloaded but not extracted
  • Files extracted but IIS not reconfigured
  • IIS reconfigured but health check not run
  • Health check passed but release not marked complete

fDeploy uses release snapshots. Creating a release freezes the deployment process, variable values, and package references. Deploying an older release uses its snapshot, not current project state. This means the Server can reconstruct intent after an Agent restart, but the Agent must track its own execution position.

The Agent likely writes checkpoint state to disk (a SQLite database or JSON file in a known location). On restart, it reads the checkpoint, determines which step failed, and either retries or reports failure to the Server. The Server does not store per-step execution state because it cannot know if the Agent's local file system is consistent.

Credential Vaulting in Windows Environments

Self-hosted agents must authenticate to:

  • The fDeploy Server (to pull packages and report status)
  • IIS (to configure app pools and bindings)
  • File shares (to copy artifacts)
  • Databases (to run migrations)
  • Active Directory (to impersonate service accounts)

fDeploy uses an "authenticated, encrypted channel" between Server and Agent. This likely means mutual TLS with certificate-based authentication. Certificates live in the Windows certificate store, which the Agent service account must have read access to.

For IIS configuration, the Agent runs as a Windows service account with permissions to modify applicationHost.config and app pool identities. It does not require full admin rights, but it needs membership in IIS_IUSRS and specific ACLs on IIS configuration files.

For database migrations or external API calls, the Agent must retrieve credentials from somewhere. Options:

  • Windows Credential Manager (encrypted per-user, requires the service account to have stored credentials)
  • Environment variables in the deployment process (visible in logs, risky)
  • Linked variable sets in the Server (encrypted at rest, decrypted on the Agent during deployment)

The third option is safest. The Server encrypts secrets using DPAPI or a master key, sends them to the Agent over TLS, and the Agent decrypts them in memory for the duration of the deployment step.

Rollback Orchestration for IIS App Pools

Rollback in containerized deployments means swapping a tag or reverting a Kubernetes manifest. Rollback in IIS means:

  1. Stopping the app pool
  2. Restoring the previous version's files
  3. Reverting web.config and XDT transforms
  4. Restoring IIS bindings and app pool settings
  5. Starting the app pool
  6. Running health checks

fDeploy's release snapshots enable this. Each release carries a frozen process and variable snapshot. Rolling back to release N means re-running the deployment process for release N, which references the old package version and old variable values.

The Agent must handle partial rollback failures. If the app pool stops but file restoration fails (disk full, file locked by another process), the Agent cannot leave the site in a broken state. It must either complete the rollback or restore the current version and report failure.

Rollback Challenge Container Deployment IIS Deployment
State to restore Image tag, environment variables Files, web.config, app pool settings, bindings
Atomicity Kubernetes reconciliation loop retries Agent must implement retry logic
Health check Readiness probe HTTP request to IIS site, custom PowerShell script
Concurrent traffic Load balancer drains old pods IIS app pool recycle interrupts active requests
Failure mode Old pods keep running Site may be down until manual intervention

Observability Hooks Without Admin Privileges

Agents need to report:

  • Deployment start, progress, and completion
  • Step-level success or failure
  • Health check results
  • Performance metrics (deployment duration, package size, file count)

The Server exposes a REST API. The Agent calls it to report status. This requires the Agent to authenticate (certificate or API key) and handle transient network failures (retry with exponential backoff).

For local observability, the Agent writes to the Windows Event Log. This does not require admin privileges if the service installer pre-creates the event source. Monitoring tools (Splunk, Datadog, Azure Monitor) can scrape the Event Log for deployment events.

The Agent cannot instrument IIS request logs or performance counters without additional permissions. If the deployment process includes a PowerShell step that writes custom metrics, the Agent can execute it, but the script must handle its own credential management and error reporting.

Concurrent Agent Requests and IIS App Pool Recycling

Multiple releases can deploy to different environments concurrently. The Server must track which Agent is deploying which release to which environment. The Agent must reject concurrent deployments to the same target.

IIS app pool recycling complicates this. If an app pool recycles during a deployment, the Agent's PowerShell scripts may fail mid-execution. The Agent must detect this (exit code, exception, timeout) and decide whether to retry or fail.

fDeploy's progression model helps. A progression is an ordered phase pipeline assigned to a project. A release cannot deploy to a phase until every environment in the preceding phase has deployed successfully. This prevents deploying to production while staging is still broken, but it does not prevent concurrent deployments to independent environments.

The Agent likely uses file-based locking (a .lock file in the deployment directory) to prevent concurrent deployments to the same target. If the Agent crashes, the lock file persists, and the next deployment attempt must either delete it (risky, may overwrite a running deployment) or fail (safe, requires manual intervention).

Code Example: Agent Checkpoint State

This is speculative, but a checkpoint file might look like this:

{
  "releaseId": "rel-12345",
  "projectId": "proj-67890",
  "environment": "staging",
  "currentStep": 3,
  "steps": [
    {"name": "Download package", "status": "completed", "timestamp": "2026-09-08T10:05:00Z"},
    {"name": "Extract files", "status": "completed", "timestamp": "2026-09-08T10:05:15Z"},
    {"name": "Apply XDT transforms", "status": "completed", "timestamp": "2026-09-08T10:05:30Z"},
    {"name": "Configure IIS", "status": "in-progress", "timestamp": "2026-09-08T10:05:45Z"},
    {"name": "Run health check", "status": "pending", "timestamp": null}
  ],
  "rollbackSnapshot": {
    "previousPackageVersion": "1.2.3",
    "appPoolState": "started",
    "bindings": [{"protocol": "https", "port": 443, "hostname": "app.example.com"}]
  }
}
Enter fullscreen mode Exit fullscreen mode

On restart, the Agent reads this file, sees that "Configure IIS" was in progress, and either retries from that step or rolls back to the previous package version.

Licensing Model and Target Audience

fDeploy is free for commercial use up to $1M ARR. This targets smaller teams, side projects, and startups that cannot justify Octopus Deploy or Azure DevOps licensing costs. The self-hosted model means no per-seat fees, no cloud egress charges, and no dependency on external SaaS uptime.

The tradeoff is operational burden. You run the Server and Agents. You back up the release history database. You rotate TLS certificates. You patch Windows on all deployment targets. For teams already running Windows infrastructure, this is acceptable. For teams migrating from cloud-native tooling, it is a step backward.

Technical Verdict

Use fDeploy when:

  • You deploy .NET applications to Windows/IIS and cannot migrate to containers
  • You need deployment state to survive server reboots and service restarts
  • You must vault credentials in Active Directory or Windows certificate stores
  • You want release snapshots that freeze process, variables, and package references
  • You have fewer than $1M ARR and want uncrippled deployment automation

Avoid fDeploy when:

  • You deploy containerized applications (use Kubernetes, Nomad, or ECS)
  • You need clustered high availability for the control plane (fDeploy Server is single-instance)
  • You want cloud-managed secrets (use AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault)
  • You need multi-tenancy (one Server instance per installation)
  • You want agent execution to resume mid-step after a crash (checkpoint granularity is per-step, not per-operation)

The seven-year development timeline suggests hard-won lessons about Windows service lifecycle, IIS configuration edge cases, and rollback failure modes. The architecture is honest about its constraints: no cloud abstractions, no clustered control plane, no magic resumption of interrupted deployments. For teams that need Windows deployment automation and can accept those tradeoffs, fDeploy exposes the plumbing clearly.

Source Links

Top comments (0)