{"id":833,"date":"2026-08-08T23:25:47","date_gmt":"2026-08-08T23:25:47","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=833"},"modified":"2026-08-08T23:25:47","modified_gmt":"2026-08-08T23:25:47","slug":"caddy-reverse-proxy-setup-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/","title":{"rendered":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">If you self-host more than one service on a single VPS \u2014 a web app, an API, Grafana, a chat server \u2014 you need a reverse proxy in front of them. It terminates TLS, routes requests by hostname or path, and gives you one public entry point instead of a pile of ports. Caddy is the easiest option on Linux: a single static binary, a small declarative config file, and HTTPS certificates that issue and renew themselves. You can go from a bare VPS to a working HTTPS reverse proxy in about ten minutes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial assumes you already picked a host \u2014 if not, <a href=\"https:\/\/virtualserversvps.com\/#providers\">see the full specs in our VPS comparison table<\/a> first. Any plan with 1&nbsp;GB of RAM and a public IPv4 address is enough for the proxy itself.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>A VPS running Ubuntu 22.04 or 24.04 LTS (Debian 12 works too).<\/li><li>A domain name with an <strong>A record pointing at your VPS IP<\/strong> \u2014 this is required for automatic HTTPS.<\/li><li>Ports 80 and 443 reachable: <code>ufw allow 80\/tcp &amp;&amp; ufw allow 443\/tcp<\/code> if you use UFW.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1 \u2014 Install Caddy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Install from the official Caddy repository so you get automatic updates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl\ncurl -1sLf 'https:\/\/dl.cloudsmith.io\/public\/caddy\/stable\/gpg.key' | sudo gpg --dearmor -o \/usr\/share\/keyrings\/caddy-stable-archive-keyring.gpg\ncurl -1sLf 'https:\/\/dl.cloudsmith.io\/public\/caddy\/stable\/debian.deb.txt' | sudo tee \/etc\/apt\/sources.list.d\/caddy-stable.list\nsudo apt update\nsudo apt install caddy<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the service is running: <code>systemctl status caddy<\/code> should show <code>active (running)<\/code>, and <code>caddy version<\/code> prints the installed build.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2 \u2014 Understand the Caddyfile<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Caddy&#8217;s config lives in <code>\/etc\/caddy\/Caddyfile<\/code>. The core directive is <code>reverse_proxy<\/code>, which forwards requests to a backend. The first line of a site block is the site address \u2014 Caddy automatically obtains and renews a Let&#8217;s Encrypt or ZeroSSL certificate for any hostname you put there, which is the feature that makes Caddy worth switching to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app.example.com {\n    reverse_proxy 127.0.0.1:8080\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That is the whole config for a single app. After editing, apply with <code>sudo caddy reload --config \/etc\/caddy\/Caddyfile<\/code> \u2014 no restart, no downtime.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3 \u2014 Real config examples<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Multiple services on one domain, routed by path<\/strong> \u2014 an API on <code>:3000<\/code> and a frontend on <code>:8080<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>example.com {\n    handle \/api\/* {\n        reverse_proxy 127.0.0.1:3000\n    }\n    handle {\n        reverse_proxy 127.0.0.1:8080\n    }\n    encode zstd gzip\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>WebSocket support<\/strong> \u2014 Caddy detects the <code>Upgrade<\/code> header and tunnels WebSocket connections automatically, so a Node.js socket server needs no special flags:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ws.example.com {\n    reverse_proxy 127.0.0.1:3001\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Security headers<\/strong> \u2014 add a <code>header<\/code> block for HSTS and clickjacking protection:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>app.example.com {\n    reverse_proxy 127.0.0.1:8080\n    header {\n        Strict-Transport-Security \"max-age=31536000\"\n        X-Content-Type-Options \"nosniff\"\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4 \u2014 Automatic HTTPS, explained<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When Caddy starts (or reloads) with a new hostname, it asks Let&#8217;s Encrypt for a certificate using the HTTP-01 challenge: it briefly serves a token on port 80, the CA verifies it, and the certificate is issued \u2014 usually in under five seconds. Certificates are stored in <code>\/var\/lib\/caddy\/.local\/share\/caddy<\/code>, and Caddy renews them automatically at 30 days before expiry. You never touch certbot or crontab. Confirm it worked: <code>curl -I https:\/\/app.example.com<\/code> should return <code>HTTP\/2 200<\/code> with a valid <code>certificate<\/code> chain.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common pitfalls<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Port 80 blocked:<\/strong> the HTTP-01 challenge fails with &#8220;certificate obtained&#8221; errors \u2014 open 80 and 443 in UFW and at the provider&#8217;s firewall panel.<\/li><li><strong>Domain not pointing at the VPS:<\/strong> Caddy refuses to issue a cert for a hostname whose DNS does not resolve to your IP. Fix the A record, wait for propagation, reload.<\/li><li><strong>Port conflicts:<\/strong> if Nginx or Apache is already bound to 80\/443, stop it (<code>systemctl stop nginx<\/code>) \u2014 Caddy must own ports 80 and 443.<\/li><li><strong>Slow backend timeouts:<\/strong> for long requests add <code>reverse_proxy 127.0.0.1:8080 { dial_timeout 5s read_header_timeout 30s }<\/code>.<\/li><li><strong>CORS errors:<\/strong> Caddy does not add CORS headers by default \u2014 add them with a <code>header<\/code> directive or handle CORS in your app.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Verify under load<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before declaring victory, run a quick smoke test: <code>ab -n 1000 -c 50 https:\/\/app.example.com\/<\/code>. Caddy handles thousands of requests per second on a single vCPU; what you are really checking is that your backend and the proxy agree on timeouts, headers, and WebSocket upgrades.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once the proxy is up, every new service is just one more site block and one reload \u2014 no new ports exposed, no cert management, no config languages to learn. For the deeper Nginx-versus-Caddy tradeoffs, our <a href=\"https:\/\/virtualserversvps.com\/#providers\">VPS provider comparison<\/a> also covers which hosts give you the headroom these proxies need. Start with Caddy on a small plan, and you can run a dozen services behind one IP without breaking a sweat.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>If you self-host more than one service on a single VPS \u2014 a web app, an API, Grafana, a chat server \u2014 you need a reverse proxy in front of&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-833","post","type-post","status-publish","format-standard","hentry","category-vps-guides-tutorials"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes\" \/>\n<meta property=\"og:description\" content=\"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-08T23:25:47+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/\",\"name\":\"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-08T23:25:47+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/","og_locale":"en_US","og_type":"article","og_title":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes","og_description":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes","og_url":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-08T23:25:47+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/","name":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-08T23:25:47+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/caddy-reverse-proxy-setup-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Set Up a Reverse Proxy with Caddy on a VPS: Automatic HTTPS in 10 Minutes"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/833","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=833"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/833\/revisions"}],"predecessor-version":[{"id":836,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/833\/revisions\/836"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=833"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=833"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=833"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}