# Caddy on Windows: automatic TLS with one binary

> Use Caddy on Windows for a small site or reverse proxy, with automatic public TLS, internal TLS for a lab, and a Caddyfile you can validate.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29

## The short answer

Caddy is a single Windows binary with **automatic HTTPS** for public DNS names. It is a good fit for:

- a small internal/public site with a real domain;
- a reverse proxy in front of Node/Python;
- a lab where you want TLS without manually issuing certificates.

It is not a drop-in IIS replacement for Windows authentication, IIS modules or ASP.NET-specific features.

## Install

Download the Windows amd64 zip, extract to `C:\caddy`, and put `caddy.exe` on PATH or use the full path.

```bat
C:\caddy\caddy.exe version
C:\caddy\caddy.exe validate --config C:\caddy\Caddyfile
C:\caddy\caddy.exe run --config C:\caddy\Caddyfile
```

`caddy run` stays in the foreground. `caddy start` backgrounds it; `caddy reload` applies a new config; `caddy stop` stops it.

## Caddyfile: static site

```caddyfile
lab.example.com {
    root * C:/sites/lab
    file_server
}
```

With a public DNS record and ports 80/443 reachable, Caddy obtains and renews a certificate automatically. It uses HTTP-01 or TLS-ALPN; no manual CSR.

For a lab name that does not resolve publicly:

```caddyfile
lab.local {
    tls internal
    root * C:/sites/lab
    file_server
}
```

`tls internal` uses Caddy’s local CA; clients must trust it (`caddy trust` on the server, or import the root CA on the client). It is not a public certificate.

## Reverse proxy

```caddyfile
app.example.com {
    reverse_proxy 127.0.0.1:3000
}
```

Caddy sets `X-Forwarded-For`, `X-Forwarded-Proto` and `Host` by default. For WebSocket, `reverse_proxy` handles the upgrade without a separate map.

Headers:

```caddyfile
app.example.com {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        -Server
    }
    reverse_proxy 127.0.0.1:3000
}
```

## Windows service

Caddy does not need a service to run, but production should use one. Wrap `caddy.exe run --config C:\caddy\Caddyfile` with WinSW/NSSM:

- working directory `C:\caddy`;
- account with read on the binary/config/site and write on Caddy’s data dir;
- restart on failure;
- firewall 80/443 only from the intended network.

Do not run two process managers (service + scheduled task) against the same config/ports.

## Verify

```powershell
C:\caddy\caddy.exe validate --config C:\caddy\Caddyfile
curl.exe -I https://lab.example.com/
curl.exe -I --resolve lab.example.com:443:127.0.0.1 https://lab.example.com/ -k
```

Check the certificate issuer/SAN, redirect from HTTP, and `X-Forwarded-*` at the app.

> **Caution: Automatic HTTPS needs a real name and reachable ports**
>
> If DNS does not point at the server, or 80/443 are blocked, automatic public TLS cannot complete. Use `tls internal` only for a lab, and do not present it as a public certificate.

## Lab boundary

E1. Caddy was not installed in this lab. The Caddyfile examples are the starting point; test certificate issuance and service wrapping on Server 2025 before claiming E2.

## Sources

- [Caddy — Install](https://caddyserver.com/docs/install)
- [Caddy — Caddyfile concepts](https://caddyserver.com/docs/caddyfile/concepts)
- [Caddy — Automatic HTTPS](https://caddyserver.com/docs/automatic-https)

---

Source: https://windows.homes/en/server/web/caddy/
