<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Khanh Duong</title>
    <description>The latest articles on DEV Community by Khanh Duong (@khanh_duong_5ff12607afcec).</description>
    <link>https://dev.to/khanh_duong_5ff12607afcec</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3940807%2F34447932-3447-44c4-a550-7139171eddb0.png</url>
      <title>DEV Community: Khanh Duong</title>
      <link>https://dev.to/khanh_duong_5ff12607afcec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khanh_duong_5ff12607afcec"/>
    <language>en</language>
    <item>
      <title>I got tired of setting up SSL for every side project, so I made a 60-second Docker deploy kit</title>
      <dc:creator>Khanh Duong</dc:creator>
      <pubDate>Tue, 19 May 2026 17:22:26 +0000</pubDate>
      <link>https://dev.to/khanh_duong_5ff12607afcec/i-got-tired-of-setting-up-ssl-for-every-side-project-so-i-made-a-60-second-docker-deploy-kit-35da</link>
      <guid>https://dev.to/khanh_duong_5ff12607afcec/i-got-tired-of-setting-up-ssl-for-every-side-project-so-i-made-a-60-second-docker-deploy-kit-35da</guid>
      <description>&lt;p&gt;You know the drill.&lt;/p&gt;

&lt;p&gt;Your app runs perfectly on &lt;code&gt;localhost:3000&lt;/code&gt;. Time to deploy it. So you rent a cheap VPS, SSH in, and then the fun begins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure Nginx as a reverse proxy&lt;/li&gt;
&lt;li&gt;Install Certbot&lt;/li&gt;
&lt;li&gt;Request a Let's Encrypt certificate&lt;/li&gt;
&lt;li&gt;Set up a cron job for renewals&lt;/li&gt;
&lt;li&gt;Debug why the certificate didn't apply&lt;/li&gt;
&lt;li&gt;Google "nginx ssl redirect loop" at 11pm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Two hours later, you still don't have HTTPS working.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've done this dance at least a dozen times. Last week I finally got fed up and packaged the whole thing into a reusable kit that takes 60 seconds instead of 2 hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: replace Nginx + Certbot with Caddy
&lt;/h2&gt;

&lt;p&gt;The secret is &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;. Unlike Nginx, Caddy handles SSL automatically — it requests certificates from Let's Encrypt and renews them without any configuration. The entire reverse proxy config is 3 lines:&lt;/p&gt;

&lt;p&gt;yourdomain.com {&lt;br&gt;
    reverse_proxy app:3000&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;ssl_certificate&lt;/code&gt; paths. No &lt;code&gt;certbot renew&lt;/code&gt;. No cron jobs. It just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I wrapped this into a small Docker Compose setup that anyone can use:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt; — runs Caddy as a reverse proxy alongside your app container&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caddyfile&lt;/strong&gt; — 3 lines, automatic SSL&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.env&lt;/strong&gt; — the only file you edit:&lt;/p&gt;

&lt;p&gt;DOMAIN=myapp.com&lt;br&gt;
APP_IMAGE=my-dockerhub-user/my-app:latest&lt;br&gt;
APP_PORT=3000&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;setup.sh&lt;/strong&gt; — a one-command script that installs Docker on a fresh Ubuntu VPS and launches everything&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;README&lt;/strong&gt; — step-by-step instructions with examples for Node.js, Python, Go, and static sites&lt;/p&gt;

&lt;h2&gt;
  
  
  The buyer experience
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Rent a cheap VPS ($4-6/month on Hetzner, DigitalOcean, etc.)&lt;/li&gt;
&lt;li&gt;Point your domain's A record to the server IP&lt;/li&gt;
&lt;li&gt;Upload the files and run &lt;code&gt;bash setup.sh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Edit 3 lines in &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker compose up -d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visit &lt;code&gt;https://yourdomain.com&lt;/code&gt; — it's live with a real SSL certificate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No Nginx. No Certbot. No DevOps experience needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm selling it instead of open-sourcing it
&lt;/h2&gt;

&lt;p&gt;I wanted to experiment with selling a small digital product. The kit is $10 — cheap enough to be an impulse buy, expensive enough to be worth packaging properly with good documentation and examples.&lt;/p&gt;

&lt;p&gt;The configs themselves aren't rocket science. What you're paying for is the tested, documented, ready-to-go package that saves you an afternoon of Googling and debugging.&lt;/p&gt;

&lt;p&gt;If you're interested: &lt;a href="https://khanhdev3.gumroad.com/l/docker-deploy-kit" rel="noopener noreferrer"&gt;Docker Deploy Kit on Gumroad&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned building my first digital product
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope matters.&lt;/strong&gt; A product this small (5 files) can be built and shipped in one afternoon. Don't overthink it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test it for real.&lt;/strong&gt; I spun up a Hetzner VPS and ran through the entire buyer experience. Found a bug (environment variables weren't being passed to the Caddy container) and fixed it before anyone paid for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The README is the product.&lt;/strong&gt; The config files are simple. The value is in clear, step-by-step documentation that makes the buyer feel confident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free DNS services are unreliable.&lt;/strong&gt; DuckDNS didn't work with Let's Encrypt during testing. Proper domain registrars (Namecheap, Porkbun, Cloudflare) are worth the few dollars.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you have any questions about Caddy, Docker deployment, or selling digital products, happy to answer in the comments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
