-
-
Save Greelan/28a46a33140b65c9a045573ca460f044 to your computer and use it in GitHub Desktop.
Set up Let’s Encrypt certificate using acme.sh as non-root user
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# How to use acme.sh to set up Let's Encrypt, with the script being run | |
# mostly without root permissions | |
# See https://github.com/Neilpang/acme.sh for more | |
# These instructions use the domain "EXAMPLE.COM" as an example | |
# These instructions: | |
# - work on Ubuntu 18.04 and 20.04 with nginx | |
# - use CloudFlare DNS validation | |
# - set up a wildcard certificate for the "EXAMPLE.COM" domain | |
# - use a systemd service, rather than cron job, to renew the certificate | |
# When this is done, there will be an "acme" user that handles issuing, | |
# updating, and installing certificates. This user will have the following | |
# (fairly minimal) permissions: | |
# - Copy certificates and key to /etc/letsencrypt/EXAMPLE.COM | |
# - Reload your nginx server | |
# First things first - create a system user account and group for acme | |
sudo useradd -m -d /var/lib/acme -s /usr/sbin/nologin -r -U acme | |
sudo chmod 700 /var/lib/acme | |
# Create a directory for the acme account to save certs in | |
MYDOMAIN="EXAMPLE.COM" | |
sudo mkdir -m 710 /etc/letsencrypt/"$MYDOMAIN" | |
sudo chown acme.www-data /etc/letsencrypt/"$MYDOMAIN" | |
# Edit your sudoers file to allow the acme user to reload (not restart) nginx | |
sudo visudo | |
# Add the following line at the end: | |
acme ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx.service | |
# Now change to the "acme" user - you'll do most of the rest of this guide as them | |
sudo MYDOMAIN="$MYDOMAIN" -s -u acme bash | |
export HOME=/var/lib/acme | |
cd ~ | |
# Install acme.sh | |
git clone https://github.com/Neilpang/acme.sh.git | |
cd acme.sh | |
./acme.sh --install | |
# Export your CloudFlare API token and account ID so that acme.sh can use them | |
# See https://github.com/Neilpang/acme.sh/wiki/dnsapi for more about API tokens | |
# You can find your account ID in the URL of any page within the Cloudflare Dashboard | |
# after selecting the appropriate account | |
export CF_Token="[insert]" | |
export CF_Account_ID="[insert]" | |
# Create your certificate | |
# Note that the "force" flag is needed for the below commands as otherwise | |
# the acme.sh script complains about being run as sudo | |
cd ~ | |
.acme.sh/acme.sh --issue -d "$MYDOMAIN" -d *."$MYDOMAIN" --dns dns_cf --force | |
# If everything went well, install your certificate | |
.acme.sh/acme.sh --install-cert --domain "$MYDOMAIN" \ | |
--ca-file /etc/letsencrypt/"$MYDOMAIN"/chain.pem \ | |
--key-file /etc/letsencrypt/"$MYDOMAIN"/key.pem \ | |
--fullchain-file /etc/letsencrypt/"$MYDOMAIN"/fullchain.pem \ | |
--reloadcmd "sudo systemctl reload nginx.service" --force | |
# Disable default cron job as a systemd service will be created instead for renewal | |
.acme.sh/acme.sh --uninstall-cronjob --force | |
# Drop back to your own user | |
exit | |
# Now modify your nginx config to work with the new certs | |
sudo nano /etc/nginx/sites-enabled/"$MYDOMAIN" | |
# Example SSL config section | |
#server { | |
# ... | |
# ssl_certificate /etc/letsencrypt/EXAMPLE.COM/fullchain.pem; | |
# ssl_certificate_key /etc/letsencrypt/EXAMPLE.COM/key.pem; | |
# ssl_trusted_certificate /etc/letsencrypt/EXAMPLE.COM/chain.pem; | |
# include /etc/nginx/ssl/ssl_params; # Change to whatever SSL settings you use - see further below | |
# ... | |
#} | |
# acme.sh does not create its own suggested SSL settings for you to use with nginx, | |
# so you will need to create your own (if you haven't already) | |
# The following commands set up SSL parameters of a reasonable level of security - | |
# relax or harden as you see fit (eg to include OCSP stapling), or skip if you | |
# already have your own. See https://ssl-config.mozilla.org/ for suggestions | |
sudo mkdir /etc/nginx/ssl | |
sudo tee /etc/nginx/ssl/ssl_params >/dev/null <<EOF | |
ssl_session_cache shared:SSL:10m; | |
ssl_session_timeout 1d; | |
ssl_protocols TLSv1.2 TLSv1.3; | |
ssl_prefer_server_ciphers off; | |
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ | |
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ | |
ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ | |
DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; | |
ssl_ecdh_curve X25519:secp384r1; | |
ssl_session_tickets off; | |
ssl_dhparam /etc/nginx/ssl/dhparam.pem; | |
EOF | |
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 | |
# Now test nginx to see if everything is working | |
sudo nginx -t | |
# And reload if it worked | |
sudo systemctl reload nginx.service | |
# Create a systemd service and timer to renew the certificate and reload nginx | |
sudo tee /etc/systemd/system/acme_letsencrypt.service >/dev/null <<EOF | |
[Unit] | |
Description=Renew Let's Encrypt certificates using acme.sh | |
After=network-online.target | |
[Service] | |
Type=oneshot | |
User=acme | |
Group=acme | |
Environment="HOME=/var/lib/acme" | |
ExecStart=/var/lib/acme/.acme.sh/acme.sh --cron | |
SuccessExitStatus=0 2 | |
EOF | |
sudo tee /etc/systemd/system/acme_letsencrypt.timer >/dev/null <<EOF | |
[Unit] | |
Description=Daily renewal of Let's Encrypt's certificates | |
[Timer] | |
OnCalendar=daily | |
RandomizedDelaySec=1h | |
Persistent=true | |
[Install] | |
WantedBy=timers.target | |
EOF | |
# Now start and enable | |
sudo systemctl start acme_letsencrypt.timer | |
sudo systemctl enable acme_letsencrypt.timer | |
# Congrats, you have a Let's Encrypt wildcard certificate set up on your box | |
# and it is configured to automatically renew, all by running the acme.sh script mostly | |
# without root permissions (other than to reload nginx on renewal). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Back after over 2 years because of a fresh install that I have done.
I see that things have changed because of the underlying changes that have happened in acme.sh
Couple of extra steps that I had to do as a result.
acme.sh now using ZeroSSL by default (rather than LetsEncrypt) ... so a step is needed to set-up the ZeroSSL environment.
The approach taken depends on whether or not the user has a ZeroSSL account.
See https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
Also - now using CloudFlare but probably worth mentioning that if using something else (I use Dynu) then the opening steps are different and user should follow the appropriate sequence from https://github.com/acmesh-official/acme.sh/wiki/dnsapi
remembering to also change the "--issue" command to use the correct "--dns" setting.