[{"data":1,"prerenderedAt":187},["ShallowReactive",2],{"seo-verification":3,"blog-deploy-your-applications-with-caddy-on-a-vps-ma-en":6,"promo-bar-likely":186},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-deploy-your-applications-with-caddy-on-a-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":32,"intro":35,"sections":36,"ctaTitle":128,"ctaBody":129,"ctaButton":130,"ctaUrl":131,"relatedPosts":132},39,"deploy-your-applications-with-caddy-on-a-vps",{"fr":12,"en":10,"ar":13,"es":14},"deployer-avec-caddy","انشر-تطبيقاتك-باستخدام-caddy-على-خادم-vps","desplegar-con-caddy","Caddy as a reverse proxy on VPS: complete guide","Install and configure Caddy as a reverse proxy on your VPS: automatic Let's Encrypt HTTPS, multi-app setup, security hardening and common error troubleshooting.",8,4,false,"2026-05-12T00:00:00+00:00","2026-09-25T23:43:04+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},3,"Deployment","deploiement","bg-success\u002F10 text-success",[28],{"id":23,"name":24,"slug":25,"color":26,"icon":25},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-avec-caddy-poster.svg",{"categorySlug":33,"appSlug":34},"application-deployment-devops","caddy","Caddy is a Go-based web server that handles the entire TLS lifecycle — ACME negotiation, renewal, HTTP → HTTPS redirect — with no dedicated configuration required. Where Nginx requires Certbot, a cron job and a separate vhost per domain, a single ten-line `Caddyfile` is enough to expose multiple applications on the same VPS over HTTPS. This guide covers installation, multi-app configuration, hardening and the most common errors.",[37,41,51,54,79,82,118,121,125],{"type":38,"title":39,"body":40},"h2","Why choose Caddy as a reverse proxy on your VPS?","Most reverse proxies delegate TLS management to an external tool — Certbot, acme.sh or a homemade cron script. Caddy integrates this mechanism end-to-end: as soon as a domain name is declared in the `Caddyfile`, it contacts Let's Encrypt, obtains the certificate and renews it before expiry, without manual intervention. The result is a configuration that reads in a few lines and deploys identically across all your VPS instances, with no external state to synchronise.",{"type":42,"title":43,"items":44},"ul","What Caddy brings to production",[45,46,47,48,49,50],"**Automatic HTTPS**: Let's Encrypt ACME HTTP-01 activated as soon as a domain name is declared — no cron, no plugin to install","**Concise syntax**: a five-line block replaces a forty-line Nginx vhost with its Certbot configuration file","**Zero cold reload**: `caddy reload` applies the new `Caddyfile` without dropping in-flight connections","**HTTP\u002F2 and HTTP\u002F3 (QUIC) by default**: enabled without additional configuration on all 2.x versions","**JSON API**: configuration can be updated live via a REST API, useful for dynamic or containerised environments","**Lightweight official Docker image**: `caddy:2-alpine` weighs under 20 MB and covers most production cases",{"type":38,"title":52,"body":53},"Prerequisites","Before you start, verify that your VPS meets the following requirements.\n\n**Minimum resources**: 512 MB of RAM and 1 vCPU are sufficient for Caddy alone. Allow 1 GB RAM and 2 vCPU if you host several applications behind it.\n\n**Ports 80 and 443 free**: Caddy occupies them for ACME HTTP-01 (port 80) and for HTTPS traffic (port 443). Check that no other process is using them:\n```bash\nss -tlnp | grep -E ':80|:443'\n```\n\n**Domain name pointing to the VPS**: Let's Encrypt validates domain ownership by querying port 80 on your IP. Your DNS `A` record must be active and propagated before starting Caddy.\n\n**Operating system**: Debian 11\u002F12 or Ubuntu 22.04\u002F24.04. Commands in this guide are tested on these distributions.\n\n**Docker (optional)**: if you deploy Caddy in a container, Docker Engine 24+ and Docker Compose v2 are required.",{"type":55,"title":56,"steps":57},"steps","Deploying Caddy as a reverse proxy",[58,61,64,67,70,73,76],{"title":59,"body":60},"Method 1 — Installation via the official APT repository","Caddy provides a signed APT repository. Add it, then install the package:\n```bash\napt install -y debian-keyring debian-archive-keyring apt-transport-https curl\ncurl -1sLf 'https:\u002F\u002Fdl.cloudsmith.io\u002Fpublic\u002Fcaddy\u002Fstable\u002Fgpg.key' \\\n  | gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fcaddy-stable-archive-keyring.gpg\ncurl -1sLf 'https:\u002F\u002Fdl.cloudsmith.io\u002Fpublic\u002Fcaddy\u002Fstable\u002Fdebian.deb.txt' \\\n  | tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fcaddy-stable.list\napt update && apt install caddy\n```\nVerify the installed version: `caddy version` should display `v2.9.x` or higher.",{"title":62,"body":63},"Method 2 — Deployment with Docker Compose","If your applications already run under Docker, a Caddy service in the same `compose.yml` is the simplest approach. Create a `compose.yml` file at the root of your project:\n```bash\nservices:\n  caddy:\n    image: caddy:2-alpine\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n      - \"443:443\u002Fudp\"\n    volumes:\n      - .\u002FCaddyfile:\u002Fetc\u002Fcaddy\u002FCaddyfile\n      - caddy_data:\u002Fdata\n      - caddy_config:\u002Fconfig\n    networks:\n      - proxy\n\nvolumes:\n  caddy_data:\n  caddy_config:\n\nnetworks:\n  proxy:\n    external: true\n```\nCreate the shared network once: `docker network create proxy`. Your other services join this network to be accessible by Caddy.",{"title":65,"body":66},"Create the basic Caddyfile","The `Caddyfile` is the central configuration file. For an APT installation, it lives at `\u002Fetc\u002Fcaddy\u002FCaddyfile`. For Docker, place it next to your `compose.yml`.\n\nHere is a minimal example that exposes an application on port 3000:\n```bash\nmyapp.com {\n    reverse_proxy localhost:3000\n}\n```\nThat's it. Caddy detects that `myapp.com` is a domain name, contacts Let's Encrypt via ACME HTTP-01, obtains a certificate and automatically redirects all HTTP traffic to HTTPS. Certificates are stored in `~\u002F.local\u002Fshare\u002Fcaddy\u002F` (APT) or in the `caddy_data` volume (Docker).",{"title":68,"body":69},"Multi-application configuration (multi-vhost)","Hosting multiple applications on the same VPS only requires additional blocks in the same file:\n```bash\napp1.yourdomain.com {\n    reverse_proxy localhost:3000\n}\n\napp2.yourdomain.com {\n    reverse_proxy localhost:4000\n}\n\nblog.yourdomain.com {\n    reverse_proxy localhost:8080\n}\n```\nEach block gets its own Let's Encrypt certificate. Caddy manages renewals independently for each domain, in parallel, without service interruption.",{"title":71,"body":72},"Apply the Caddyfile without interruption","For APT, reload the configuration without dropping connections:\n```bash\nsystemctl reload caddy\n# or, if you modified the file outside \u002Fetc\u002Fcaddy\u002F:\ncaddy reload --config \u002Fpath\u002Fto\u002FCaddyfile\n```\nFor Docker:\n```bash\ndocker compose exec caddy caddy reload --config \u002Fetc\u002Fcaddy\u002FCaddyfile\n```\nVerify that the syntax is correct before reloading: `caddy validate --config \u002Fetc\u002Fcaddy\u002FCaddyfile`.",{"title":74,"body":75},"Add security headers and rate limiting","Caddy supports native security headers via the `header` directive. Here is a hardened block for a production application:\n```bash\nmyapp.com {\n    reverse_proxy localhost:3000\n\n    header {\n        Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\"\n        X-Content-Type-Options \"nosniff\"\n        X-Frame-Options \"SAMEORIGIN\"\n        Referrer-Policy \"strict-origin-when-cross-origin\"\n        -Server\n    }\n\n    log {\n        output file \u002Fvar\u002Flog\u002Fcaddy\u002Fmyapp.log {\n            roll_size 10mb\n            roll_keep 5\n        }\n    }\n}\n```\nFor rate limiting, the `caddy-ratelimit` module is installed via `xcaddy build` and used with the `rate_limit` directive. The official Docker image does not include it — build your own image or use an upstream application firewall if the need is critical.",{"title":77,"body":78},"Enable and verify the systemd service (APT)","After installation via APT, the service is enabled automatically. Check its status and logs:\n```bash\nsystemctl status caddy\njournalctl -u caddy -f\n```\nTo ensure Caddy starts at reboot: `systemctl enable caddy` (already done by the package). Test that the Let's Encrypt certificate was successfully issued:\n```bash\ncurl -sv https:\u002F\u002Fmyapp.com 2>&1 | grep -E 'subject|issuer|expire'\n```",{"type":38,"title":80,"body":81},"How Caddy's automatic HTTPS works","Caddy implements the ACME (Automated Certificate Management Environment) protocol natively. As soon as a `Caddyfile` block contains a qualified domain name, Caddy automatically triggers the **ACME HTTP-01 challenge**: Let's Encrypt places a verification token at `http:\u002F\u002Fyourdomain.com\u002F.well-known\u002Facme-challenge\u002F`, Caddy responds to this request and proves it controls the server. Let's Encrypt then issues a certificate valid for 90 days.\n\nCaddy renews this certificate in advance (starting 30 days before expiry) and reloads the configuration hot, without service interruption. Certificates and ACME data are stored locally — in `~\u002F.local\u002Fshare\u002Fcaddy\u002F` for an APT installation, in the `caddy_data` volume for Docker. **Do not delete this volume**: Caddy also stores ACME state there, and too many requests to Let's Encrypt trigger rate limits that can block new certificate issuance for several hours.\n\nFor **wildcard certificates** (`*.yourdomain.com`), ACME HTTP-01 does not work: the **DNS-01 challenge** is required, which needs access to your DNS provider's API. Caddy natively supports several providers via modules (`caddy-dns\u002Fcloudflare`, `caddy-dns\u002Fovh`…) compiled with `xcaddy`.",{"type":83,"title":84,"headers":85,"rows":89},"comparison","Caddy vs Nginx: when to choose which",[86,87,88],"Criterion","Caddy","Nginx",[90,94,98,102,106,110,114],[91,92,93],"TLS configuration","Automatic, zero manual configuration","Manual (Certbot or acme.sh required)",[95,96,97],"Learning curve","Low — readable syntax, few directives","Moderate — verbose syntax, many contexts",[99,100,101],"Raw performance (req\u002Fs)","Excellent for most workloads","Slightly higher under very high load",[103,104,105],"Modules and ecosystem","Growing, xcaddy to compile modules","Very large, numerous mature third-party modules",[107,108,109],"Reload without interruption","Native (`caddy reload`)","Native (`nginx -s reload`), similar",[111,112,113],"Ideal use case","Personal VPS, team projects, Docker microservices","Large platforms, CDN frontend, advanced cases (GeoIP, Lua…)",[115,116,117],"HTTP\u002F3 (QUIC) support","Enabled by default since Caddy 2.6","Experimental, requires compilation with quiche or ngx_http_v3",{"type":38,"title":119,"body":120},"Troubleshooting: common errors","**Port 80 already in use.** Caddy needs port 80 for ACME HTTP-01. If Apache or Nginx is already running, stop it before starting Caddy: `systemctl stop apache2` or `systemctl stop nginx`. Then verify with `ss -tlnp | grep :80`.\n\n**ACME failure \u002F certificate not issued.** Let's Encrypt cannot reach your server. Check: (1) your DNS `A` record points to the VPS IP — `dig +short your-domain.com` must return your IP; (2) port 80 is accessible from the outside — VPS firewalls (iptables, ufw) sometimes block this port even when Caddy is listening. Check Caddy logs with `journalctl -u caddy` to read the precise ACME error message.\n\n**`permission denied` on ports 80\u002F443.** Ports below 1024 are reserved under Linux. For an APT installation, the package automatically configures the `CAP_NET_BIND_SERVICE` capability on the Caddy binary. If you compiled Caddy manually, apply it: `setcap cap_net_bind_service=+ep $(which caddy)`.\n\n**DNS not resolved \u002F `no such host`.** Caddy resolves the names of backends declared in `reverse_proxy`. If your application is called `app` in Docker Compose, make sure Caddy and the application share the same Docker network. Verify with: `docker compose exec caddy nslookup app`.\n\n**`caddy_data` volume accidentally deleted.** Caddy must renegotiate all certificates from scratch. Let's Encrypt enforces a limit of 5 certificates per domain over 7 days. If you hit this limit, use the ACME staging environment (`acme_ca https:\u002F\u002Facme-staging-v02.api.letsencrypt.org\u002Fdirectory` in the `Caddyfile`) to test, then switch back to production once the window has passed.",{"type":122,"title":123,"body":124},"tip","For hosting multiple applications on the same VPS","Create a shared Docker network (`docker network create proxy`) and connect each service to that network. The `Caddyfile` then references services by their container name rather than `localhost:PORT` — the configuration does not change when you add or remove applications. Example: `reverse_proxy my-service:3000` instead of `reverse_proxy localhost:3000`.",{"type":122,"title":126,"body":127},"Official documentation","The complete reference for directives, modules and the JSON API is available at `\u003Ca href=\"https:\u002F\u002Fcaddyserver.com\u002Fdocs\u002F\">caddyserver.com\u002Fdocs\u003C\u002Fa>`. The community forum (`\u003Ca href=\"https:\u002F\u002Fcaddy.community\">caddy.community\u003C\u002Fa>`) is the go-to community reference for advanced questions — the maintainers reply directly.","Your VPS, ready for Caddy","Deploy Caddy on a ServOrbit VPS and get a Debian 12 environment, ports 80 and 443 open, and immediate SSH access.","View VPS plans","\u002Fvps-cloud",[133,149,169],{"id":134,"slug":135,"slugs":136,"title":140,"excerpt":141,"readTime":142,"views":23,"isPinned":19,"noindex":19,"publishedAt":143,"updatedAt":144,"category":145,"categories":146,"featuredImage":29,"bgImage":30,"posterImage":148,"relatedSolution":29},38,"deploy-your-applications-with-traefik-on-a-vps",{"fr":137,"en":135,"ar":138,"es":139},"deployer-avec-traefik","انشر-تطبيقاتك-باستخدام-traefik-على-خادم-vps","desplegar-con-traefik","Deploy your applications with Traefik on a VPS","Deploy Traefik as a reverse proxy on your VPS: automatic routing of Docker containers, Let's Encrypt SSL certificates and load balancing.",11,"2026-05-13T00:00:00+00:00","2026-11-08T01:13:13+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[147],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fdeployer-avec-traefik-poster.svg",{"id":150,"slug":151,"slugs":152,"title":156,"excerpt":157,"readTime":17,"views":158,"isPinned":19,"noindex":19,"publishedAt":159,"updatedAt":160,"category":161,"categories":166,"featuredImage":29,"bgImage":30,"posterImage":168,"relatedSolution":29},116,"free-ssl-certificates-with-lets-encrypt-on-a-vps",{"fr":153,"en":151,"ar":154,"es":155},"certificats-ssl-lets-encrypt-vps","شهادات-ssl-مجانية-باستخدام-lets-encrypt-على-خادم-vps","certificados-ssl-gratis-con-lets-encrypt-en-un-vps","Free SSL Certificates with Let's Encrypt on a VPS","Complete Let's Encrypt guide for VPS: certbot nginx, DNS-01 wildcard, systemd renewal, TLS hardening, rate-limit troubleshooting and certbot vs acme.sh vs Caddy.",0,"2026-02-24T00:00:00+00:00","2026-09-30T11:20:34+00:00",{"id":17,"name":162,"slug":163,"color":164,"icon":165},"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[167],{"id":17,"name":162,"slug":163,"color":164,"icon":165},"\u002Fblog\u002Fcovers\u002Fcertificats-ssl-lets-encrypt-vps-poster.svg",{"id":170,"slug":171,"slugs":172,"title":176,"excerpt":177,"readTime":178,"views":179,"isPinned":19,"noindex":19,"publishedAt":180,"updatedAt":181,"category":182,"categories":183,"featuredImage":29,"bgImage":30,"posterImage":185,"relatedSolution":29},229,"docker-compose-in-production-10-point-checklist",{"fr":173,"en":171,"ar":174,"es":175},"docker-compose-production-checklist","docker-compose-في-الإنتاج-قائمة-التحقق-من-10-نقاط","checklist-docker-compose-en-produccion","Docker Compose in Production: 10-Point Checklist","Docker Compose in production: 10 settings, health checks, secrets, rollback, troubleshooting and moving from docker-compose v1 to docker compose on Ubuntu 26.04.",12,1,"2026-08-06T00:00:00+00:00","2026-10-23T13:27:09+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[184],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fdocker-compose-production-checklist-poster.svg",true,1794270387375]