HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
acmesh-official
acme.sh
Shell2016–2026
acmesh-official / acme.sh

acme.sh

A pure Unix shell script ACME client for SSL / TLS certificate automation

66Distinct people
94Mentions
2Explicit recommenders
48KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

A pure Unix shell script ACME client for SSL / TLS certificate automation

GitHub

Where it is used

  • OpenWrt — OpenWrt uses acme.sh to provide ACME-based certificate issuance and renewal via its packaged acme-acmesh integration. The distro ships acme.sh so users can obtain HTTPS certificates on OpenWrt systems. Source

What people are saying

It’s “only” 7.1K LoC, but my favorite is the “acme.sh” script which is used to issue and renew certs from Lets Encrypt.…

xyst used a recommendation phrase. 2 indexed comments match. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 5:04:57 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year94 dated mentions

Observed mentions: 2016-04-14 15:49:23 UTC to 2026-10-16 10:19:09 UTC.

0510152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 4 mentions; 1 submissions, 3 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 10 mentions; 1 submissions, 9 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 6 mentions; 1 submissions, 5 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 16 mentions; 2 submissions, 14 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 12 mentions; 1 submissions, 11 comments20212022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 10 mentions; 0 submissions, 10 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 7 mentions; 1 submissions, 6 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 12 mentions; 2 submissions, 10 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 9 mentions; 0 submissions, 9 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC110
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC413
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC1019
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC615
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC16214
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC12111
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC10010
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC716
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC12210
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC707
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC909

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
🔐 acme.sh An ACME Protocol Client Written Purely in Shell ✨ Features 🐚 An ACME protocol client written purely in Shell (Unix shell) language 📜 Full ACME protocol implementation 🔑 Support ECDSA certificates 🌐 Support SAN and wildcard certificates ⚡ Simple, powerful and very easy to use — only 3 minutes to learn! 🔧 Compatible with Bash, dash and sh 🚫 No dependencies on Python 🔄 One script to issue, renew and install your certificates automatically 👤 DOES NOT require root/sudoer access 🐳 Docker ready 🌍 IPv6 ready 📧 Cron job notifications for renewal or error 💡 It's probably the easiest & smartest shell script to automatically issue & renew free certificates. 📚 Wiki • 🐳 Docker Guide • 🐦 Twitter 🌏 中文说明 🏆 Who Uses acme.sh? FreeBSD.org ruby-china.org Proxmox pfsense Loadbalancer.org discourse.org Centminmod splynx opnsense.org CentOS Web Panel lnmp.org more... 🖥️ Tested OS NO Status Platform 1 Mac OSX 2 Windows (cygwin with curl, openssl and crontab included) 3 FreeBSD 4 Solaris 5 Ubuntu 6 NA pfsense 7 OpenBSD 8 NetBSD 9 DragonFlyBSD 10 MidnightBSD 11 Omnios 12 OpenIndiana 13 Debian 14 openSUSE 15 Alpine Linux (with curl) 16 Archlinux 17 fedora 18 Kali Linux 19 Oracle Linux 20 Mageia 21 Gentoo Linux 22 ----- Cloud Linux #111 23 ----- OpenWRT: Tested and working. See wiki page 24 Proxmox: See Proxmox VE Wiki. Version 4.x, 5.0, 5.1, version 5.2 and up 25 Haiku OS 26 Tribblix 27 GhostBSD 28 GNU Hurd 29 openEuler 30 HardenedBSD 31 OPNsense 🧪 Check our testing project 🖥️ The testing VMs are supported by vmactions.org 🏛️ Supported CA CA Status ZeroSSL.com CA ⭐ Default Letsencrypt.org CA ✅ Supported SSL.com CA ✅ Supported Google.com Public CA ✅ Supported Actalis.com CA ✅ Supported Pebble strict Mode ✅ Supported Any RFC8555-compliant CA ✅ Supported ⚙️ Supported Modes Mode Description 📁 Webroot mode Use existing webroot directory 🖥️ Standalone mode Built-in webserver on port 80 🔐 Standalone tls-alpn mode Built-in webserver on port 443 🪶 Apache mode Use Apache for verification ⚡ Nginx mode Use Nginx for verification 🌐 DNS mode Use DNS TXT records 🔗 DNS alias mode Use DNS alias for verification 📡 Stateless mode Stateless verification 📌 DNS persist mode Persistent DNS TXT record (draft-ietf-acme-dns-persist-01) 📖 Usage Guide 1️⃣ How to Install 📥 Install Online Check this project: https://github.com/acmesh-official/get.acme.sh curl https://get.acme.sh | sh -s email=my@example.com Or: wget -O - https://get.acme.sh | sh -s email=my@example.com 📦 Install from Git Clone this project and launch installation: git clone https://github.com/acmesh-official/acme.sh.git cd ./acme.sh ./acme.sh --install -m my@example.com 💡 You don't have to be root then, although it is recommended. 📚 Advanced Installation: https://github.com/acmesh-official/acme.sh/wiki/How-to-install The installer will perform 3 actions: Create and copy acme.sh to your home dir ($HOME): ~/.acme.sh/. All certs will be placed in this folder too. Create alias for: acme.sh=~/.acme.sh/acme.sh. Create daily cron job to check and renew the certs if needed. Cron entry example: 0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null ⚠️ After the installation, you must close the current terminal and reopen it to make the alias take effect. ✅ You are ready to issue certs now! Show help message: acme.sh -h 🔏 Verify a Release Release tags from 3.1.6 on are signed with the maintainer's SSH key. The signing happens on the maintainer's machine, so the private key is never available to CI. The public half is allowed_signers in this repository. From a clone: git config gpg.ssh.allowedSignersFile allowed_signers git verify-tag 3.1.6 The signature covers the tag object, which pins the commit and therefore the whole tree, so a good signature verifies every file at that release and no separate tarball checksum is needed. Build a tarball from the verified tag: git archive --format=tar.gz --prefix=acme.sh-3.1.6/ 3.1.6 > acme.sh-3.1.6.tar.gz ⚠️ Tags up to 3.1.5 are unsigned. 2️⃣ Issue a Certificate Example 1: Single domain. acme.sh --issue -d example.com -w /home/wwwroot/example.com or: acme.sh --issue -d example.com -w /home/username/public_html or: acme.sh --issue -d example.com -w /var/www/html Example 2: Multiple domains in the same cert. acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com The parameter /home/wwwroot/example.com or /home/username/public_html or /var/www/html is the web root folder where you host your website files. You MUST have write access to this folder. Second argument "example.com" is the main domain you want to issue the cert for. You must have at least one domain there. You must point and bind all the domains to the same webroot dir: /home/wwwroot/example.com. The certs will be placed in ~/.acme.sh/example.com/ 🔄 The certs will be renewed automatically every 30 days. 🔐 The certs will default to ECC certificates. 📚 More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert 3️⃣ Install the Certificate to Apache/Nginx After the cert is generated, you probably want to install/copy the cert to your Apache/Nginx or other servers. ⚠️ IMPORTANT: You MUST use this command to copy the certs to the target files. DO NOT use the certs files in ~/.acme.sh/ folder — they are for internal use only, the folder structure may change in the future. 🪶 Apache Example: acme.sh --install-cert -d example.com \ --cert-file /path/to/certfile/in/apache/cert.pem \ --key-file /path/to/keyfile/in/apache/key.pem \ --fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ --reloadcmd "service apache2 force-reload" ⚡ Nginx Example: acme.sh --install-cert -d example.com \ --key-file /pa
Read the full README on GitHub

What Hacker News says

94 sources
You don't need to do it manually - the DNS challenge works automatically as long as the machine doing the renewing can call out to something to update the DNS entry, and you can use the dns-alias option¹ if your main DNS provider isn't easy to automate this way (this also limits the opportunities for something going wrong with the automatic DNS updates for certs breaking your main DNS at the same time). I'm interested in the new DNS-persist method² which will make this even easier, though with some obvious trade-offs, but despite the announcements in Feb/May suggesting it would be rolled out in Q2, I've heard nothing recently and we are now in Q4. There are various ways to separate managing certs via regular ACME renews and the hosts that actually use the certificates, meaning that hosts which can never see or be touched by the outside ne
Read the rest
twork (except via whatever VPN you may use when away yourself) can have ACME certs instead of you setting up your own CA arrangement to serve them. One option if you don't mind all your services having one private key, is to get a wildcard cert on one host (a small server just answering the top level domain.tld for HTTPS based validation, or again one of the DNS options) and have your other services regularly refresh the certificate they use by reading it from there. ---- [1] Docs for acme.sh: https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mo... (other tools work just as well with it) [2] https://letsencrypt.org/2026/02/18/dns-persist-01
In What I self-host
> I use the acme dns-1 challenge on my public domain. See also perhaps DNS aliasing in case you are not able to dynamically update your 'primary' domain, but can update a secondary or sub-domain: * https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mo... So if "example.com" is control by Corporate IT, and they don't want 'random' folks fiddling with it, then you can create a "dnsauth.example.com" and point the dns-1 challenge record from "…foo.example.com" to "foo.dnsauth.example.com" (or a completely different domain, like "…example.net"). There are DNS servers written strictly focused on this use case: * https://github.com/acme-dns/acme-dns Also code that handles a bunch of DNS provider APIs so you don't have to roll your own for ACME client hooks: * https://github.com/dns-lexicon/dns-lexicon
In TLS certificates for internal services done right
> I've been hesitant to set that up because I'm concerned about the potential compromise of a token that has permissions to edit my DNS zone. Depending on your DNS provider, it may be possible to narrow the permissions to allow only updates of a particular record. Route53 as an example: { "Effect": "Allow", "Action": "route53:ChangeResourceRecordSets", "Resource": "arn:aws:route53:::hostedzone/<ZONE-ID>", "Condition": { "ForAllValues:StringEquals": { "route53:ChangeResourceRecordSetsNormalizedRecordNames": "_acme-challenge.<SUB>.<DOMAIN>.<TLD>" } } } * https://github.com/acmesh-official/acme.sh/wiki/How-to-use-A... BIND 9 example: * https://dan.langille.org/2020/12/19/creating-a-very-specific... You can also point the hostname that you wish to
Read the rest
issues certs for to another (sub-)domain completely via a CNAME, and allow updates only for that other (sub-)domain: * https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mo... * https://www.eff.org/deeplinks/2018/02/technical-deep-dive-se...
In Installing a Let's Encrypt TLS certificate on a Brother printer with Certbot
I remember being annoyed because the docs don't actually say you can't do it: https://certbot-dns-rfc2136.readthedocs.io/en/stable/ ...but they also don't say how to specify the zone to be updated like acme.sh does: https://github.com/acmesh-official/acme.sh/blob/master/dnsap... So say you want a cert for *.foo.com, and you have: _acme-challenge.foo.com CNAME _acme-challenge.foo.bar.com ...I can make certbot talk to the foo.bar.com DNS server, but it tries to add the TXT record for _acme-challenge.foo.com, which that DNS server obviously rejects (and even if it accepted it, that obviously wouldn't work). I'd be happy to hear there's a way to do it that I missed. Also I'm specifically talking about the rfc2136 support, maybe some of the proprietary certbot backends do support this. EDIT: Here are more references: https://github.com/ce
Read the rest
In You can run a DNS server (2025)
Works on my machine: git clone https://github.com/acmesh-official/acme.sh Cloning into 'acme.sh'... remote: Enumerating objects: 21361, done. remote: Counting objects: 100% (351/351), done. remote: Compressing objects: 100% (101/101), done. remote: Total 21361 (delta 282), reused 253 (delta 250), pack-reused 21010 (from 3) Receiving objects: 100% (21361/21361), 7.25 MiB | 9.65 MiB/s, done. Resolving deltas: 100% (13612/13612), done. Anonymous access clone that is. Are you accessing a private repo? I do not have a way to test that as I nuked my accounts long ago.
In Ask HN: Is GitHub Down?
CNAMEs. I do this for everything. Example: 1. Your main domain is important.example.com with provider A. No DNS API token for security. 2. Your throwaway domain in a dedicated account with DNS API is example.net with provider B and a DNS API token in your ACME client 3. You create _acme-challenge.important.example.com not as TXT via API but permanent as CNAME to _acme-challenge.example.net or _acme-challenge.important.example.com.example.net 4. Your ACME client writes the challenge responses for important.example.com into a TXT at the unimportant _acme-challenge.example.net and has only API access to provider B. If this gets hacked and example.net lost you change the CNAMES and use a new domain whatever.tld as CNAME target. acme.sh supports this (see https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mo...; this also works for wild
Read the rest
cards as described there), most ACME clients do. I also wrote an acme.sh Ansible role supporting this: https://github.com/foundata/ansible-collection-acmesh/tree/m.... Example values: [...] # certificate: "foo.example.com" with an additional "bar.example.com" SAN - domains: - name: "foo.example.com" challenge: # parameters depend on type type: "dns" dns_provider: "dns_hetzner" # CNAME _acme-challenge.foo.example.com => _acme-challenge.foo.example.com.example.net challenge_alias: "foo.example.com.example.net" - name: "bar.example.com" challenge: type: "dns" dns_provider: "dns_inwx" # CNAME _acme-challenge.bar.example.com => _acme-challenge.example.net challenge_alias: "example.net" [...]
In Nginx introduces native support for ACME protocol
I was amazed by them having so much distrust of the various clients. Certbot is typically in the repositories for things like Debian/Ubuntu. My favourite client is probably https://github.com/acmesh-official/acme.sh If you use a DNS service provider that supports it, you can use the DNS-01 challenge to get a certificate - that means that you can have the acme.sh running on a completely different server which should help if you're twitchy about running a complex script on it. It's also got the advantage of allowing you to get certificates for internal/non-routable addresses.
In Why I no longer have an old-school cert on my HTTPS site

Showing the 15 most recent of 94 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.