{"componentChunkName":"component---src-templates-blog-post-jsx","path":"/blog/one-wildcard-ssl-certificate-to-secure-all-subdomains-via-certbot/","result":{"data":{"site":{"siteMetadata":{"name":"Huzaifa Rasheed","title":"Huzaifa Rasheed","description":"Software Engineer","about":"\n      Hey, I'm Huzaifa.\n      <br/><br/>\n      Engineer by trade, builder by instinct - I believe in owning my stack, shipping fast, and occasionally running on chai (tea) and stubbornness. I work best in that sweet spot between deep focus and fast feedback - solo or in sync with a good team.\n      <br/><br/>\n      This site's my little corner of the internet - part portfolio, part lab - where I document what I build, break, or learn.\n      <br/><br/>\n      Outside work, I'm into long walks, pixel-perfect headshots in FPS games (eventually... maybe), plants I probably overwater, and the occasional \"classified\" hobby to stay curious.\n      <br/><br/>\n      Reach out anytime - my digital door's always open. 👋\n    ","twitter":"https://twitter.com/huzRasheed","github":"https://github.com/huzaifa-99","linkedin":"https://www.linkedin.com/in/huzaifa-rasheed/","devto":"https://dev.to/huzaifa99","stackoverflow":"https://stackoverflow.com/users/12579290/huzaifa","leetcode":"https://leetcode.com/rhuzaifa","discord":"https://discordapp.com/users/rhuzaifa","email":"dev@rhuzaifa.com","projects":[{"name":"FFMpeg Web","description":"An experimental browser-based terminal that runs FFmpeg using WebAssembly, enabling media processing directly in the browser.","link":"https://ffmpeg-web.rhuzaifa.com/","github":"https://github.com/huzaifa-99/ffmpeg-web"},{"name":"Feed base 2","description":"A mini browser game where players manipulate 4-bit binary blocks to match target BCD values - part puzzle, part binary logic trainer.","link":"https://feedbase2.rhuzaifa.com/","github":"https://github.com/huzaifa-99/feed-base-2"},{"name":"Fabric browser extension","description":"A Chrome extension that injects engineered Fabric prompts directly into the ChatGPT interface for enhanced workflow automation.","link":"https://github.com/huzaifa-99/fabric-browser-extension","github":"https://github.com/huzaifa-99/fabric-browser-extension"},{"name":"Pure Cinema","description":"An experimental, tongue-in-cheek text-to-video generator that stitches together footage, synthesized voiceovers, and background music with a Node.js + ffmpeg pipeline. Not quite Hollywood, but it renders.","link":"https://cinema.rhuzaifa.com","github":null},{"name":"Aria2c Packload","description":"A Bash script for bulk downloading magnet links or torrents using aria2c - optimized for series or list-based transfers.","link":"https://github.com/huzaifa-99/aria2c-packload","github":"https://github.com/huzaifa-99/aria2c-packload"},{"name":"RSS Watchdog","description":"A lightweight Bash script that watches RSS/Atom feeds and compiles a Markdown-based reading checklist for Unix systems.","link":"https://github.com/huzaifa-99/rss-watchdog","github":"https://github.com/huzaifa-99/rss-watchdog"},{"name":"QuoteGen","description":"A quote graphic generator that produces stylized quote images with random selection and a built-in editor for customization.","link":"https://quotegen.rhuzaifa.com/","github":null},{"name":"WebRTC Video Chat","description":"A basic WebRTC-powered app enabling peer-to-peer video and audio calls between two users.","link":"https://webrtc-video-chat.rhuzaifa.com/","github":null}],"experience":null,"skills":[{"name":"Languages & Frameworks","description":"JavaScript, TypeScript, Python, Bash - Frameworks include Node.js, React, Next.js, Vue, React Native, FastAPI."},{"name":"Databases & Storage","description":"PostgreSQL, MySQL, MongoDB - Experience with schema design, indexing, query optimization, and migrations."},{"name":"Cloud & Infrastructure","description":"AWS (EC2, RDS, S3, Lambda), Vercel, Netlify, Heroku - Comfortable with serverless, autoscaling, and cost optimization."},{"name":"DevOps & Tooling","description":"Docker, Git, CI/CD pipelines (GitHub Actions, GitLab CI) - Experience with observability, containerization, and release workflows."},{"name":"Testing & QA Automation","description":"Jest, Playwright, Puppeteer, Selenium - Focus on E2E testing, mocking APIs, and maintaining test coverage."}]}},"markdownRemark":{"id":"fcb0423f-61ba-5260-947f-bc0d14924ed3","excerpt":"SSL certificates for dozens of subdomains quickly becomes a headache.  Recently, I needed to secure all the usual suspects - stuff like , ,  - and I decided to…","html":"<p>SSL certificates for dozens of subdomains quickly becomes a headache. </p>\n<p>Recently, I needed to secure all the usual suspects - stuff like <code class=\"language-text\">api.</code>, <code class=\"language-text\">mail.</code>, <code class=\"language-text\">vault.</code> - and I decided to just get <strong>one wildcard SSL certificate</strong> that covers them all. </p>\n<p><strong>Spoiler:</strong> It made life way easier.</p>\n<hr>\n<h2>Why bother with a wildcard cert?</h2>\n<p>Managing individual certs for every subdomain is a pain - renewals everywhere, multiple cron jobs, config spaghetti. </p>\n<p>A wildcard cert (<code class=\"language-text\">*.example.com</code>) just covers all subdomains in one go.</p>\n<p>This is a solid shortcut to less headache and fewer surprises in a multi service, self hosted infra setup on different subdomains.</p>\n<hr>\n<h2>Why DNS validation?</h2>\n<p>Let’s Encrypt offers a few ways to prove you own a domain. </p>\n<p>The <strong>DNS-01 challenge</strong> is basically the only way to get wildcard certs. It means you prove ownership by adding a TXT record to your DNS.</p>\n<p>It’s also handy because:</p>\n<ul>\n<li>You don’t have to expose a webserver or open firewall ports</li>\n<li>You can pre-create certs before your service is even live</li>\n<li>It’s less error-prone than messing with HTTP challenges</li>\n</ul>\n<p>If your DNS provider has an API and Certbot supports it, you can automate the whole thing. Otherwise, manual TXT records work fine too - just a little more hands-on.</p>\n<p>For extra integrity, enable DNSSEC - it helps prevent spoofing of TXT records used in validation.</p>\n<hr>\n<h2>Certbot? Isn’t there something else?</h2>\n<p>Sure, there are other ACME clients like <code class=\"language-text\">acme.sh</code> and <code class=\"language-text\">lego</code>. </p>\n<p>Those are great if you want minimal dependencies or full scripting control. But for my use case, Certbot’s DNS plugins and docs made things straightforward and reliable.</p>\n<hr>\n<h2>Here’s the quick rundown:</h2>\n<h3>1. Install Certbot</h3>\n<p>On Debian/Ubuntu, this is easy:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">apt</span> update\n<span class=\"token function\">sudo</span> <span class=\"token function\">apt</span> <span class=\"token function\">install</span> certbot</code></pre></div>\n<h3>2. Grab the DNS plugin (optional)</h3>\n<p>If you want Certbot to handle DNS TXT record updates automatically (Cloudflare example):</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># replace 'cloudflare' with your DNS provider (ex: python3-certbot-dns-digitalocean)</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">apt</span> <span class=\"token function\">install</span> python3-certbot-dns-cloudflare</code></pre></div>\n<h3>3. Request the wildcard cert</h3>\n<p>Manual way:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> certbot certonly --manual --preferred-challenges dns -d <span class=\"token string\">\"*.example.com\"</span></code></pre></div>\n<p>Certbot will spit out a TXT record to add:</p>\n<div class=\"gatsby-highlight\" data-language=\"arduino\"><pre class=\"language-arduino\"><code class=\"language-arduino\">_acme<span class=\"token operator\">-</span>challenge<span class=\"token punctuation\">.</span>example<span class=\"token punctuation\">.</span>com IN TXT <span class=\"token string\">\"some_long_token\"</span></code></pre></div>\n<p>Add it, wait a bit, then hit Enter for verification.</p>\n<p>Automated way (Cloudflare example):</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> certbot certonly --dns-cloudflare -d <span class=\"token string\">\"*.example.com\"</span></code></pre></div>\n<p>This handles the DNS records for you.</p>\n<p>Wildcards don’t cover the root domain (example.com), so request both if you need it.</p>\n<h3>4. Use the cert</h3>\n<p>After success, your cert will be in:</p>\n<div class=\"gatsby-highlight\" data-language=\"swift\"><pre class=\"language-swift\"><code class=\"language-swift\"><span class=\"token operator\">/</span>etc<span class=\"token operator\">/</span>letsencrypt<span class=\"token operator\">/</span>live<span class=\"token operator\">/</span>example<span class=\"token punctuation\">.</span>com<span class=\"token operator\">/</span>fullchain<span class=\"token punctuation\">.</span>pem\n<span class=\"token operator\">/</span>etc<span class=\"token operator\">/</span>letsencrypt<span class=\"token operator\">/</span>live<span class=\"token operator\">/</span>example<span class=\"token punctuation\">.</span>com<span class=\"token operator\">/</span>privkey<span class=\"token punctuation\">.</span>pem</code></pre></div>\n<p>Plug those into NGINX, Postfix, whatever.</p>\n<h3>Don’t forget renewal</h3>\n<p>Let’s Encrypt certs expire every 90 days. To stay ahead of expiration issues, they recommend renewing every 60 days.</p>\n<p>If you’re doing manual DNS, you’ll have to repeat the TXT record dance when they expire.</p>\n<p>If automated, just run:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> certbot renew --quiet</code></pre></div>\n<p>Or add that to a cron/systemd timer to make it hands-off.</p>\n<p>Add something like a deploy hook for post cert renewal actions (which only runs on successful renewals)</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> certbot renew --quiet --deploy-hook <span class=\"token string\">\"systemctl reload nginx\"</span> <span class=\"token comment\"># or the web server you use</span></code></pre></div>\n<h3>Why this matters in DevOps</h3>\n<p>Good SSL management is a silent backbone of solid infrastructure. Wildcard certs + DNS validation cut down complexity, especially if you:</p>\n<ul>\n<li>Run multiple self-hosted tools on subdomains</li>\n<li>Automate deployments in CI/CD</li>\n<li>Want to avoid firefighting expired certs</li>\n</ul>\n<p>If you’re in that boat, this setup will save you a bunch of hassle.</p>\n<h3>Be careful, tho</h3>\n<p>If someone gains access to your wildcard cert and private key, they can impersonate any subdomain. That’s a much bigger blast radius than a cert for just one subdomain.</p>\n<p>For sensitive setups, consider managing certs and keys with something like <strong>HashiCorp Vault</strong> or <strong>Kubernetes Secrets</strong>. Don’t just leave <code class=\"language-text\">.pem</code> files lying around.</p>\n<hr>\n<p>If you’ve done this differently or have tips, drop them my way (<a href=\"mailto:dev@rhuzaifa.com\">dev@rhuzaifa.com</a>). Always good to swap war stories.</p>","frontmatter":{"title":"One Wildcard SSL Certificate to Secure All Subdomains via Certbot","date":"July 18, 2024","description":"Wildcard + Certbot + DNS = one cert to rule them all."}}},"pageContext":{"slug":"/blog/one-wildcard-ssl-certificate-to-secure-all-subdomains-via-certbot/","previous":{"fields":{"slug":"/blog/aggregating-rss-feeds-locally-with-a-simple-bash-script/"},"frontmatter":{"title":"Aggregating RSS Feeds Locally with a Simple Bash Script"}},"next":{"fields":{"slug":"/blog/docker-is-great-just-not-for-local-dev/"},"frontmatter":{"title":"Docker Is Great, Just Not for Local Dev"}}}},"staticQueryHashes":["2276319502"]}