{"id":1313,"date":"2025-11-04T16:54:41","date_gmt":"2025-11-04T13:54:41","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/the-hands%e2%80%91off-guide-to-lets-encrypt-wildcard-ssl-dns%e2%80%9101-auto%e2%80%91renew-and-real%e2%80%91world-setups-on-cpanel-plesk-and-nginx\/"},"modified":"2025-11-04T16:54:41","modified_gmt":"2025-11-04T13:54:41","slug":"the-hands%e2%80%91off-guide-to-lets-encrypt-wildcard-ssl-dns%e2%80%9101-auto%e2%80%91renew-and-real%e2%80%91world-setups-on-cpanel-plesk-and-nginx","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/the-hands%e2%80%91off-guide-to-lets-encrypt-wildcard-ssl-dns%e2%80%9101-auto%e2%80%91renew-and-real%e2%80%91world-setups-on-cpanel-plesk-and-nginx\/","title":{"rendered":"The Hands\u2011Off Guide to Let\u2019s Encrypt Wildcard SSL: DNS\u201101, Auto\u2011Renew, and Real\u2011World Setups on cPanel, Plesk, and Nginx"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>So there I was, staring at yet another expiring SSL warning for a client who swears they \u201conly launched two subdomains.\u201d By the time we finished listing them, there were nine. Marketing had spun up a few launches. The mobile team had a staging area. Someone added a \u201cbeta.\u201d You know how it goes. That was the day I stopped playing whack\u2011a\u2011mole with single\u2011host certificates and moved every domain with even a hint of subdomain sprawl to a Let\u2019s Encrypt wildcard SSL with DNS\u201101 validation and automation. It felt like unclogging a drain you\u2019ve been ignoring for months\u2014quiet relief and the kind of calm you don\u2019t realize you\u2019ve needed.<\/p>\n<p>If you\u2019ve ever had that moment where a subdomain goes red in the browser at 2 a.m., this one\u2019s for you. In this guide, we\u2019ll walk through the what and why of DNS\u201101, then set up fully automated wildcard SSL in three common environments: cPanel, Plesk, and Nginx on a <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a>. I\u2019ll share what tends to break (and how I fix it fast), where to stash API tokens safely, and how to make renewals boring\u2014which is the dream. By the end, you\u2019ll have a game plan that keeps <strong>*.yourdomain.com<\/strong> locked down without late\u2011night fire drills.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Why_Wildcard_SSL_DNS01_Is_the_Sanity_Saver\"><span class=\"toc_number toc_depth_1\">1<\/span> Why Wildcard SSL + DNS\u201101 Is the Sanity Saver<\/a><\/li><li><a href=\"#DNS01_Without_the_Headache_Whats_Really_Happening\"><span class=\"toc_number toc_depth_1\">2<\/span> DNS\u201101 Without the Headache: What\u2019s Really Happening<\/a><\/li><li><a href=\"#cPanel_From_Please_Renew_Emails_to_Fully_Automated_Wildcards\"><span class=\"toc_number toc_depth_1\">3<\/span> cPanel: From \u201cPlease Renew\u201d Emails to Fully Automated Wildcards<\/a><ul><li><a href=\"#The_highlevel_flow_I_use\"><span class=\"toc_number toc_depth_2\">3.1<\/span> The high\u2011level flow I use<\/a><\/li><li><a href=\"#Option_A_acmesh_with_your_DNS_providers_API\"><span class=\"toc_number toc_depth_2\">3.2<\/span> Option A: acme.sh with your DNS provider\u2019s API<\/a><\/li><li><a href=\"#Option_B_Certbot_with_a_DNS_plugin_then_install_via_cPanel_UAPI\"><span class=\"toc_number toc_depth_2\">3.3<\/span> Option B: Certbot with a DNS plugin, then install via cPanel UAPI<\/a><\/li><\/ul><\/li><li><a href=\"#Plesk_BuiltIn_Wildcard_If_DNS_Is_in_the_Right_Place\"><span class=\"toc_number toc_depth_1\">4<\/span> Plesk: Built\u2011In Wildcard, If DNS Is in the Right Place<\/a><ul><li><a href=\"#When_DNS_lives_in_Plesk\"><span class=\"toc_number toc_depth_2\">4.1<\/span> When DNS lives in Plesk<\/a><\/li><li><a href=\"#When_DNS_lives_elsewhere\"><span class=\"toc_number toc_depth_2\">4.2<\/span> When DNS lives elsewhere<\/a><\/li><li><a href=\"#Renewals_and_the_invisible_factor\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Renewals and the \u201cinvisible\u201d factor<\/a><\/li><\/ul><\/li><li><a href=\"#Nginx_on_a_VPS_Certbot_or_acmesh_and_a_Clean_Reload\"><span class=\"toc_number toc_depth_1\">5<\/span> Nginx on a VPS: Certbot or acme.sh, and a Clean Reload<\/a><ul><li><a href=\"#Certbot_example_with_a_DNS_plugin_Cloudflare\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Certbot example with a DNS plugin (Cloudflare)<\/a><\/li><li><a href=\"#acmesh_example_with_Route_53\"><span class=\"toc_number toc_depth_2\">5.2<\/span> acme.sh example with Route 53<\/a><\/li><\/ul><\/li><li><a href=\"#Little_Things_That_Make_the_Whole_Setup_RockSolid\"><span class=\"toc_number toc_depth_1\">6<\/span> Little Things That Make the Whole Setup Rock\u2011Solid<\/a><ul><li><a href=\"#Use_staging_while_you_wire_it_up\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Use staging while you wire it up<\/a><\/li><li><a href=\"#Mind_your_CAA_records\"><span class=\"toc_number toc_depth_2\">6.2<\/span> Mind your CAA records<\/a><\/li><li><a href=\"#Keep_DNS_API_tokens_tight_and_quiet\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Keep DNS API tokens tight and quiet<\/a><\/li><li><a href=\"#Low_TTLs_help_manual_paths\"><span class=\"toc_number toc_depth_2\">6.4<\/span> Low TTLs help \u201cmanual\u201d paths<\/a><\/li><li><a href=\"#Chain_files_and_reloads\"><span class=\"toc_number toc_depth_2\">6.5<\/span> Chain files and reloads<\/a><\/li><li><a href=\"#Dont_forget_the_rest_of_your_security_posture\"><span class=\"toc_number toc_depth_2\">6.6<\/span> Don\u2019t forget the rest of your security posture<\/a><\/li><\/ul><\/li><li><a href=\"#Common_Why_Is_This_Failing_Moments_And_Quick_Fixes\"><span class=\"toc_number toc_depth_1\">7<\/span> Common \u201cWhy Is This Failing?\u201d Moments (And Quick Fixes)<\/a><ul><li><a href=\"#Validating_the_TXT_record_is_failing\"><span class=\"toc_number toc_depth_2\">7.1<\/span> \u201cValidating the TXT record is failing\u201d<\/a><\/li><li><a href=\"#It_worked_yesterday_now_renewals_are_broken\"><span class=\"toc_number toc_depth_2\">7.2<\/span> \u201cIt worked yesterday, now renewals are broken\u201d<\/a><\/li><li><a href=\"#The_site_still_shows_the_old_certificate\"><span class=\"toc_number toc_depth_2\">7.3<\/span> \u201cThe site still shows the old certificate\u201d<\/a><\/li><li><a href=\"#Wildcard_works_but_the_apex_domain_is_missing\"><span class=\"toc_number toc_depth_2\">7.4<\/span> \u201cWildcard works, but the apex domain is missing\u201d<\/a><\/li><li><a href=\"#We_use_DNSSECdoes_it_matter_for_ACME\"><span class=\"toc_number toc_depth_2\">7.5<\/span> \u201cWe use DNSSEC\u2014does it matter for ACME?\u201d<\/a><\/li><\/ul><\/li><li><a href=\"#Putting_It_All_Together_A_Quick_RealWorld_Blueprint\"><span class=\"toc_number toc_depth_1\">8<\/span> Putting It All Together: A Quick, Real\u2011World Blueprint<\/a><\/li><li><a href=\"#WrapUp_Make_Renewals_Boring_Again\"><span class=\"toc_number toc_depth_1\">9<\/span> Wrap\u2011Up: Make Renewals Boring Again<\/a><\/li><\/ul><\/div>\n<h2 id=\"section-1\"><span id=\"Why_Wildcard_SSL_DNS01_Is_the_Sanity_Saver\">Why Wildcard SSL + DNS\u201101 Is the Sanity Saver<\/span><\/h2>\n<p>Let\u2019s start with the heartbeat of the setup: wildcard certificates. A Let\u2019s Encrypt wildcard like <strong>*.example.com<\/strong> covers all first\u2011level subdomains\u2014think <em>www<\/em>, <em>app<\/em>, <em>staging<\/em>, <em>beta<\/em>. If your world changes a lot (and whose doesn\u2019t?), you skip the endless add\u2011remove cycle of hostnames. The catch is that Let\u2019s Encrypt only lets you get wildcards via <strong>DNS\u201101<\/strong>, not the usual HTTP\u201101. That\u2019s their way of saying \u201cprove you control the domain at the DNS layer,\u201d which is more authoritative than dropping a file on a web server.<\/p>\n<p>Here\u2019s the thing: once you automate DNS\u201101, renewals become gloriously boring. No manual TXT pasting, no calendar reminders. Your DNS provider\u2019s API adds and removes the validation TXT records on schedule, Let\u2019s Encrypt issues or renews, and your server installs the new cert. That\u2019s it. I\u2019ve run these pipelines for years across different stacks, and when they\u2019re set right, they become invisible.<\/p>\n<p>If you\u2019re newer to SSL in general and want a refresher, I\u2019ve written a friendly explainer about <a href=\"https:\/\/www.dchost.com\/blog\/en\/ssl-sertifikasi-nedir-web-sitenizi-guvence-altina-almanin-yollari\/\">what an SSL certificate actually does and how it secures your site<\/a>. It pairs nicely with this guide.<\/p>\n<h2 id=\"section-2\"><span id=\"DNS01_Without_the_Headache_Whats_Really_Happening\">DNS\u201101 Without the Headache: What\u2019s Really Happening<\/span><\/h2>\n<p>Let\u2019s demystify DNS\u201101 in normal language. When you request a certificate, the CA (Let\u2019s Encrypt) asks you to create a special TXT record at <strong>_acme-challenge.example.com<\/strong>. That TXT value is a unique token. If they can look up that record and it matches, they know you control the domain. For a wildcard, the validation still lives at <strong>_acme-challenge.example.com<\/strong>, even though you\u2019re requesting <strong>*.example.com<\/strong>.<\/p>\n<p>The smart path is to use automation so your server (or a CLI tool) talks to your DNS provider\u2019s API and drops that TXT record just\u2011in\u2011time. After validation, it removes the record or leaves it be\u2014depends on the tool. That\u2019s where utilities like Certbot\u2019s DNS plugins and acme.sh shine. They speak to popular DNS services and take care of the fussy parts for you.<\/p>\n<p>If TXT records, CNAMEs, and AAAA glue your brain into knots, I put together <a href=\"https:\/\/www.dchost.com\/blog\/en\/dns-kayitlari-adan-zye-a-aaaa-cname-mx-txt-srv-caa-ve-sizi-yakan-o-kucuk-hatalar\/\">my friendly guide to DNS records and the little gotchas<\/a>. It will absolutely make the next section feel clearer.<\/p>\n<h2 id=\"section-3\"><span id=\"cPanel_From_Please_Renew_Emails_to_Fully_Automated_Wildcards\">cPanel: From \u201cPlease Renew\u201d Emails to Fully Automated Wildcards<\/span><\/h2>\n<p>I\u2019ll be honest: cPanel out of the box does a beautiful job with standard HTTP\u201101 \u201cAutoSSL,\u201d but wildcard via Let\u2019s Encrypt needs DNS\u201101, and not every hosting provider wires that up for you. The reliable workaround I use is to pair a DNS\u2011aware ACME client with cPanel\u2019s API for installation. Once this is dialed in, it hums along elegantly.<\/p>\n<h3><span id=\"The_highlevel_flow_I_use\">The high\u2011level flow I use<\/span><\/h3>\n<p>First, I pick a DNS automation tool. I use <em>acme.sh<\/em> when I want a tiny, dependency\u2011light script with dozens of DNS providers supported; I use Certbot when I want a more standard, distro\u2011friendly approach. Then I wire the tool to my DNS provider via API tokens. The tool requests a wildcard from Let\u2019s Encrypt, creates the TXT record via API, Let\u2019s Encrypt validates, and the certificate gets issued. Finally, I deploy the cert directly into cPanel using its UAPI or a deploy\u2011hook. The whole loop becomes automatic with a cron job.<\/p>\n<h3><span id=\"Option_A_acmesh_with_your_DNS_providers_API\">Option A: acme.sh with your DNS provider\u2019s API<\/span><\/h3>\n<p>acme.sh is tiny, fast, and knows a shocking number of DNS APIs. I\u2019ve used it with Cloudflare, Route 53, DigitalOcean, GoDaddy\u2014you name it. Here\u2019s a sketch of what it looks like with Cloudflare. The dance is similar for other providers; you just change the environment variables.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># install acme.sh (as the cPanel user or root; I prefer per-user)\ncurl https:\/\/get.acme.sh | sh -s email=you@example.com\n\n# export your DNS provider credentials (use least-privileged tokens!)\nexport CF_Token=&quot;&lt;cloudflare_api_token_with_dns_edit&gt;&quot;\nexport CF_Account_ID=&quot;&lt;your_account_id&gt;&quot;\n\n# issue the wildcard + apex\n~\/.acme.sh\/acme.sh --issue \n  --dns dns_cf \n  -d example.com -d '*.example.com'\n\n# optional: use the Let's Encrypt staging endpoint while testing\n# ~\/.acme.sh\/acme.sh --set-default-ca --server letsencrypt\n# ~\/.acme.sh\/acme.sh --issue --dns dns_cf -d example.com -d '*.example.com' --staging\n<\/code><\/pre>\n<p>Once issued, you can deploy to cPanel via the built\u2011in deploy hook. acme.sh has a <em>cpanel_uapi<\/em> deploy target that talks to cPanel\u2019s API and installs the certificate for the correct domain\/user. You\u2019ll need a cPanel API token and the cPanel username.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># store your cPanel API token securely and set environment variables\nexport DEPLOY_CPanel_USER=&quot;&lt;cpanel_username&gt;&quot;\nexport DEPLOY_CPanel_TOKEN=&quot;&lt;long_api_token&gt;&quot;\nexport DEPLOY_CPanel_SERVER=&quot;https:\/\/&lt;hostname_or_domain&gt;:2083&quot;  # or 2087 for WHM\n\n# deploy the cert into cPanel\n~\/.acme.sh\/acme.sh --deploy \n  -d example.com \n  --deploy-hook cpanel_uapi\n\n# renewals: acme.sh creates a cron entry; verify it exists\n~\/.acme.sh\/acme.sh --cron --home ~\/.acme.sh\n<\/code><\/pre>\n<p>In my experience, this approach is the sweet spot: you don\u2019t have to move DNS, you keep your preferred provider, and the install lands right where cPanel expects it. Renewals run quietly, and your certificate stays fresh without you lifting a finger.<\/p>\n<h3><span id=\"Option_B_Certbot_with_a_DNS_plugin_then_install_via_cPanel_UAPI\">Option B: Certbot with a DNS plugin, then install via cPanel UAPI<\/span><\/h3>\n<p>Certbot can do the same, with the added comfort of being the \u201cofficial\u201d Let\u2019s Encrypt client many distros ship. The trick is using a DNS plugin like Cloudflare, Route 53, or DigitalOcean. After issuance, you call cPanel\u2019s UAPI to install the cert. If you\u2019re comfortable with yum\/apt packages and systemd timers, this feels very native.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># example with Cloudflare on a CentOS\/Alma\/Rocky server\nsudo dnf install certbot python3-certbot-dns-cloudflare -y\n\n# credentials file for Cloudflare\nsudo bash -c 'cat &gt; \/etc\/letsencrypt\/cloudflare.ini &lt;&lt;EOF\ndns_cloudflare_api_token = &lt;token_with_dns_edit&gt;\nEOF'\nsudo chmod 600 \/etc\/letsencrypt\/cloudflare.ini\n\n# request the wildcard and apex\nsudo certbot certonly \n  --dns-cloudflare \n  --dns-cloudflare-credentials \/etc\/letsencrypt\/cloudflare.ini \n  -d example.com -d '*.example.com' \n  -m you@example.com --agree-tos --non-interactive\n\n# install into cPanel via UAPI (adjust --user and domain)\nuapi --user=&lt;cpanel_username&gt; SSL install_ssl \n  cert=&quot;$(sudo cat \/etc\/letsencrypt\/live\/example.com\/cert.pem)&quot; \n  key=&quot;$(sudo cat \/etc\/letsencrypt\/live\/example.com\/privkey.pem)&quot; \n  cabundle=&quot;$(sudo cat \/etc\/letsencrypt\/live\/example.com\/chain.pem)&quot;\n<\/code><\/pre>\n<p>Certbot sets up a systemd timer for renewal automatically. I add a deploy hook that calls UAPI again on renewal so the fresh certs install themselves.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># reload or re-install on renewal\nsudo bash -c 'cat &gt; \/etc\/letsencrypt\/renewal-hooks\/deploy\/10-install-cpanel.sh &lt;&lt;EOF\n#!\/usr\/bin\/env bash\nuapi --user=&lt;cpanel_username&gt; SSL install_ssl \n  cert=&quot;$(cat &quot;$RENEWED_LINEAGE\/cert.pem&quot;)&quot; \n  key=&quot;$(cat &quot;$RENEWED_LINEAGE\/privkey.pem&quot;)&quot; \n  cabundle=&quot;$(cat &quot;$RENEWED_LINEAGE\/chain.pem&quot;)&quot;\nEOF'\nsudo chmod +x \/etc\/letsencrypt\/renewal-hooks\/deploy\/10-install-cpanel.sh\n<\/code><\/pre>\n<p>Either way, test in staging first. I once chased a DNS permission issue for an hour only to realize I was hitting production rate limits because I forgot the staging flag. Don\u2019t be me on a Friday.<\/p>\n<h2 id=\"section-4\"><span id=\"Plesk_BuiltIn_Wildcard_If_DNS_Is_in_the_Right_Place\">Plesk: Built\u2011In Wildcard, If DNS Is in the Right Place<\/span><\/h2>\n<p>Plesk has a nice edge here: its Let\u2019s Encrypt extension understands DNS\u201101 and can handle wildcard certificates directly in the UI. The smoothest ride happens when your DNS is hosted in Plesk (or synced from Plesk to a cloud DNS via an extension). In that case, Plesk adds and cleans up the TXT record for you during both issuance and renewal.<\/p>\n<h3><span id=\"When_DNS_lives_in_Plesk\">When DNS lives in Plesk<\/span><\/h3>\n<p>From the domain\u2019s dashboard, open the Let\u2019s Encrypt extension, check the option to issue a wildcard, include both <strong>example.com<\/strong> and <strong>*.example.com<\/strong>, and proceed. Plesk drops the TXT record into its DNS zone automatically, Let\u2019s Encrypt validates, and you\u2019re done. Renewals will just happen. It\u2019s the kind of \u201cset it and forget it\u201d we all need more of.<\/p>\n<h3><span id=\"When_DNS_lives_elsewhere\">When DNS lives elsewhere<\/span><\/h3>\n<p>If your DNS is on Route 53, Cloudflare, or another provider, you have two good paths. One is to momentarily add the TXT record manually when prompted\u2014fine for one\u2011offs, not great for automation. The other is to use a Plesk DNS extension that syncs zones to your provider. For example, there are extensions for Route 53 and Google Cloud DNS. Once configured, Plesk updates those zones on your behalf, which lets the wildcard flow be fully automated again.<\/p>\n<p>A quick tip: mind your TTLs. If you\u2019re adding TXT records manually or syncing zones, a high TTL can slow validation down. I have a whole playbook on this in my <a href=\"https:\/\/www.dchost.com\/blog\/en\/zero-downtime-tasima-icin-ttl-stratejileri-dns-yayilimini-gercekten-nasil-hizlandirirsin\/\">TTL Playbook for zero\u2011downtime migrations and faster DNS changes<\/a>. It\u2019s the same trick I use to speed up ACME validation in tricky environments.<\/p>\n<h3><span id=\"Renewals_and_the_invisible_factor\">Renewals and the \u201cinvisible\u201d factor<\/span><\/h3>\n<p>What I love about Plesk\u2019s approach is that, once the pipeline is healthy, renewal day looks the same as any other day. No banners, no nagging. The only times I\u2019ve seen hiccups were when DNS got moved without telling Plesk, or when a provider changed API auth. I keep API tokens well\u2011scoped and rotate them on a schedule. It\u2019s a small habit that saves big headaches.<\/p>\n<h2 id=\"section-5\"><span id=\"Nginx_on_a_VPS_Certbot_or_acmesh_and_a_Clean_Reload\">Nginx on a VPS: Certbot or acme.sh, and a Clean Reload<\/span><\/h2>\n<p>For a straight VPS running Nginx, I choose between Certbot and acme.sh based on two things: what the OS packages nicely, and which DNS provider I need to talk to. Both work brilliantly.<\/p>\n<h3><span id=\"Certbot_example_with_a_DNS_plugin_Cloudflare\">Certbot example with a DNS plugin (Cloudflare)<\/span><\/h3>\n<p>Certbot\u2019s DNS plugins are straightforward and well\u2011documented. With Cloudflare, an API token limited to one zone\u2019s DNS edit permission is enough.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt update &amp;&amp; sudo apt install -y certbot python3-certbot-dns-cloudflare\n\n# credentials file (strict permissions)\nsudo bash -c 'cat &gt; \/etc\/letsencrypt\/cloudflare.ini &lt;&lt;EOF\ndns_cloudflare_api_token = &lt;token&gt;\nEOF'\nsudo chmod 600 \/etc\/letsencrypt\/cloudflare.ini\n\nsudo certbot certonly \n  --dns-cloudflare \n  --dns-cloudflare-credentials \/etc\/letsencrypt\/cloudflare.ini \n  -d example.com -d '*.example.com' \n  -m you@example.com --agree-tos --non-interactive\n\n# point Nginx to the certs\nsudo sed -i 's|# ssl_certificate .*|ssl_certificate \/etc\/letsencrypt\/live\/example.com\/fullchain.pem;|' \/etc\/nginx\/sites-available\/example\nsudo sed -i 's|# ssl_certificate_key .*|ssl_certificate_key \/etc\/letsencrypt\/live\/example.com\/privkey.pem;|' \/etc\/nginx\/sites-available\/example\n\n# safer to edit by hand, of course, then test and reload\nsudo nginx -t &amp;&amp; sudo systemctl reload nginx\n<\/code><\/pre>\n<p>For renewals, Certbot\u2019s systemd timer handles the schedule. I add a deploy hook so Nginx reloads only when a cert actually changes. It\u2019s tiny but satisfying.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo bash -c 'cat &gt; \/etc\/letsencrypt\/renewal-hooks\/deploy\/20-reload-nginx.sh &lt;&lt;&quot;EOF&quot;\n#!\/usr\/bin\/env bash\n\/usr\/sbin\/nginx -t &amp;&amp; \/bin\/systemctl reload nginx\nEOF'\nsudo chmod +x \/etc\/letsencrypt\/renewal-hooks\/deploy\/20-reload-nginx.sh\n<\/code><\/pre>\n<h3><span id=\"acmesh_example_with_Route_53\">acme.sh example with Route 53<\/span><\/h3>\n<p>If you live in the Amazon world, acme.sh\u2019s Route 53 integration is a delight. Set your AWS keys with least privilege (only the specific zone) and let acme.sh do the rest.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">curl https:\/\/get.acme.sh | sh -s email=you@example.com\n\nexport AWS_ACCESS_KEY_ID=&quot;&lt;access_key&gt;&quot;\nexport AWS_SECRET_ACCESS_KEY=&quot;&lt;secret_key&gt;&quot;\n\n~\/.acme.sh\/acme.sh --issue \n  --dns dns_aws \n  -d example.com -d '*.example.com'\n\n# install to a path Nginx uses\nsudo mkdir -p \/etc\/nginx\/ssl\/example.com\n~\/.acme.sh\/acme.sh --install-cert -d example.com \n  --fullchain-file \/etc\/nginx\/ssl\/example.com\/fullchain.pem \n  --key-file \/etc\/nginx\/ssl\/example.com\/privkey.pem \n  --reloadcmd &quot;nginx -t &amp;&amp; systemctl reload nginx&quot;\n<\/code><\/pre>\n<p>Now renewals are automatic via acme.sh\u2019s cron job, and Nginx reloads on change. If you ever wonder whether renewals are running, check your logs\u2014Certbot uses systemd journal; acme.sh logs under its home directory. I like to set a calendar reminder to glance at them monthly. Five minutes well spent.<\/p>\n<h2 id=\"section-6\"><span id=\"Little_Things_That_Make_the_Whole_Setup_RockSolid\">Little Things That Make the Whole Setup Rock\u2011Solid<\/span><\/h2>\n<p>These are the small habits that have saved me hours across dozens of deployments.<\/p>\n<h3><span id=\"Use_staging_while_you_wire_it_up\">Use staging while you wire it up<\/span><\/h3>\n<p>Let\u2019s Encrypt has rate limits, and you\u2019ll hit them faster than you think when you\u2019re experimenting. Switch to the staging endpoint until your pipeline works end\u2011to\u2011end. With Certbot, that\u2019s <em>&#8211;dry-run<\/em> or the staging server; with acme.sh, use <em>&#8211;staging<\/em> or set the default CA to staging first.<\/p>\n<h3><span id=\"Mind_your_CAA_records\">Mind your CAA records<\/span><\/h3>\n<p>If you use CAA, make sure your domain allows Let\u2019s Encrypt to issue wildcards. Add an <strong>issue<\/strong> or <strong>issuewild<\/strong> record permitting <em>letsencrypt.org<\/em>. Otherwise, you\u2019ll have a perfect pipeline that fails at the very last step. If you need a refresher on DNS safety basics, I break down <a href=\"https:\/\/www.dchost.com\/blog\/en\/dnssec-nedir-web-sitenizi-nasil-daha-guvenli-hale-getirir\/\">what DNSSEC is and how it protects you<\/a>, plus the pitfalls that can block validation if misconfigured.<\/p>\n<h3><span id=\"Keep_DNS_API_tokens_tight_and_quiet\">Keep DNS API tokens tight and quiet<\/span><\/h3>\n<p>Scope tokens to a single zone with DNS edit only. Store them in root\u2011readable files with 600 permissions. I\u2019ve seen renewals fail because a token was rotated and nobody updated the server. A tiny secrets checklist (where tokens live, when they expire) prevents that \u201cwhy did this break?\u201d mystery later on.<\/p>\n<h3><span id=\"Low_TTLs_help_manual_paths\">Low TTLs help \u201cmanual\u201d paths<\/span><\/h3>\n<p>If you\u2019re temporarily adding TXT records by hand, lower the TTL beforehand so you\u2019re not waiting on slow propagation. When you\u2019re done, set it back. If this is new to you, my <a href=\"https:\/\/www.dchost.com\/blog\/en\/zero-downtime-tasima-icin-ttl-stratejileri-dns-yayilimini-gercekten-nasil-hizlandirirsin\/\">TTL Playbook for zero\u2011downtime migrations<\/a> shows exactly how I approach this without breaking a sweat.<\/p>\n<h3><span id=\"Chain_files_and_reloads\">Chain files and reloads<\/span><\/h3>\n<p>Browsers and some middleware can be picky about intermediate chains. Always point servers at the <strong>fullchain<\/strong> file and not just the leaf certificate. After renewal, reload the service cleanly. With Nginx, I like \u201ctest then reload\u201d because a failed config push should never take down a running site.<\/p>\n<h3><span id=\"Dont_forget_the_rest_of_your_security_posture\">Don\u2019t forget the rest of your security posture<\/span><\/h3>\n<p>SSL is one layer. Once you have it, round out the basics: set HSTS and other headers, keep redirects tight, and avoid mixed content. If you want a plain\u2011English walkthrough, here\u2019s how I <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-guvenlik-basliklari-rehberi-hsts-csp-ve-digerlerini-ne-zaman-nasil-uygulamalisin\/\">set strong HTTP security headers without breaking stuff<\/a>. It\u2019s the natural next step once TLS is in place.<\/p>\n<h2 id=\"section-7\"><span id=\"Common_Why_Is_This_Failing_Moments_And_Quick_Fixes\">Common \u201cWhy Is This Failing?\u201d Moments (And Quick Fixes)<\/span><\/h2>\n<p>I\u2019ve met every error you can imagine. Here\u2019s how I think through them in the moment.<\/p>\n<h3><span id=\"Validating_the_TXT_record_is_failing\">\u201cValidating the TXT record is failing\u201d<\/span><\/h3>\n<p>Nine times out of ten, this is either a propagation lag or the TXT record landing in the wrong zone. Confirm the TXT value and name, double\u2011check you don\u2019t have an extra domain suffix (e.g., <em>_acme-challenge.example.com.example.com<\/em>), and query a public resolver. If you\u2019re using multiple DNS providers or moved zones recently, make sure the NS records point where you think they do.<\/p>\n<h3><span id=\"It_worked_yesterday_now_renewals_are_broken\">\u201cIt worked yesterday, now renewals are broken\u201d<\/span><\/h3>\n<p>Tokens expire, permissions change, or DNS moved. I look at the renewal logs first, then test the DNS API call directly. If that works, I run the ACME client in verbose or debug mode. You\u2019ll often see a clear 401 from your DNS provider\u2014time to rotate and update the credentials file. And if you switched DNS providers, ensure your automation uses the right plugin for the new home.<\/p>\n<h3><span id=\"The_site_still_shows_the_old_certificate\">\u201cThe site still shows the old certificate\u201d<\/span><\/h3>\n<p>This usually means the certificate issued fine but never made it into the web server, or the service didn\u2019t reload. On cPanel, check the UAPI call or the acme.sh deploy hook logs. On Nginx, verify the live paths and perform a manual reload. I also peek at any L4\/L7 proxies in front of the site\u2014CDNs can cache certs too.<\/p>\n<h3><span id=\"Wildcard_works_but_the_apex_domain_is_missing\">\u201cWildcard works, but the apex domain is missing\u201d<\/span><\/h3>\n<p>Remember that wildcard <strong>*.example.com<\/strong> does not cover <strong>example.com<\/strong>. Always include both the apex and the wildcard in your request. It\u2019s a small oversight that happens to everyone once.<\/p>\n<h3><span id=\"We_use_DNSSECdoes_it_matter_for_ACME\">\u201cWe use DNSSEC\u2014does it matter for ACME?\u201d<\/span><\/h3>\n<p>It matters in the best way when configured right. Signed zones help protect the integrity of your TXT validation. Misconfigured DNSSEC, however, can block resolution. If validation mysteriously fails yet your TXT record exists, I immediately test DNSSEC health and check the DS record chain. If you need a refresher, I\u2019ve got a friendly explainer on <a href=\"https:\/\/www.dchost.com\/blog\/en\/dnssec-nedir-web-sitenizi-nasil-daha-guvenli-hale-getirir\/\">how DNSSEC works and why it matters<\/a>.<\/p>\n<h2 id=\"section-8\"><span id=\"Putting_It_All_Together_A_Quick_RealWorld_Blueprint\">Putting It All Together: A Quick, Real\u2011World Blueprint<\/span><\/h2>\n<p>If you only take one recipe from this post, make it this: pick a DNS\u2011aware ACME tool, use least\u2011privilege API tokens, include both apex and wildcard, point your server at the full chain, and add a reload hook. That\u2019s the heart of the whole system, no matter where you host.<\/p>\n<p>Here are the official docs I lean on for the nitty\u2011gritty details and new plugin support. The explanations are clean, and the examples are current:<\/p>\n<p>\u2022 The <a href=\"https:\/\/letsencrypt.org\/docs\/wildcard-certificates\/\" rel=\"nofollow noopener\" target=\"_blank\">Let\u2019s Encrypt documentation on wildcard certificates<\/a> for the DNS\u201101 basics and caveats.<br \/>\u2022 The <a href=\"https:\/\/eff-certbot.readthedocs.io\/en\/stable\/using.html#dns-plugins\" rel=\"nofollow noopener\" target=\"_blank\">Certbot documentation about DNS plugins<\/a> to pick your provider module and credential format.<br \/>\u2022 The <a href=\"https:\/\/github.com\/acmesh-official\/acme.sh\" rel=\"nofollow noopener\" target=\"_blank\">acme.sh project documentation<\/a> for provider variable names and deploy hooks.<\/p>\n<p>That trio covers 95% of what I encounter in the wild.<\/p>\n<h2 id=\"section-9\"><span id=\"WrapUp_Make_Renewals_Boring_Again\">Wrap\u2011Up: Make Renewals Boring Again<\/span><\/h2>\n<p>I still remember the first time a big renewal wave came and went with zero alerts, zero pings, zero anything. I checked logs a little suspiciously and then laughed\u2014it had all just worked. That\u2019s what a good DNS\u201101 wildcard setup gives you: calm. You aren\u2019t chasing new subdomains, you aren\u2019t pasting TXT records, and you aren\u2019t shipping last\u2011minute hotfixes because someone forgot a renewal.<\/p>\n<p>If you\u2019re on cPanel, wire up acme.sh or Certbot with your DNS provider and install via UAPI. On Plesk, lean into the Let\u2019s Encrypt extension and keep DNS where Plesk can manage it (or sync it). On Nginx, choose Certbot or acme.sh, point at fullchain, and reload on change. Add staging while you experiment, keep API tokens tight, and make a habit of peeking at renewal logs once in a while. And when you\u2019re ready to go the extra mile, set up security headers\u2014the finishing touch after TLS is solid. I shared exactly how I do that in my guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-guvenlik-basliklari-rehberi-hsts-csp-ve-digerlerini-ne-zaman-nasil-uygulamalisin\/\">getting HSTS, CSP, and friends right<\/a>.<\/p>\n<p>Hope this was helpful! If there\u2019s a stack you want me to cover next\u2014HAProxy, Traefik, Kubernetes Ingress\u2014I\u2019m game. Until then, may your certificates auto\u2011renew quietly and your dashboards stay gloriously boring.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>So there I was, staring at yet another expiring SSL warning for a client who swears they \u201conly launched two subdomains.\u201d By the time we finished listing them, there were nine. Marketing had spun up a few launches. The mobile team had a staging area. Someone added a \u201cbeta.\u201d You know how it goes. That [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1314,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=1313"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1313\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/1314"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=1313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=1313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=1313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}