Skip to content

Instantly share code, notes, and snippets.

@lachesis
Last active December 13, 2023 11:02
Show Gist options
  • Save lachesis/943769f3fac740d5848352752ac08741 to your computer and use it in GitHub Desktop.
Save lachesis/943769f3fac740d5848352752ac08741 to your computer and use it in GitHub Desktop.
Set up LetsEncrypt using acme.sh without root
# How to use "acme.sh" to set up Lets Encrypt without root permissions
# See https://github.com/Neilpang/acme.sh for more
# This assumes that your website has a webroot at "/var/www/<domain>"
# I'll use the domain "EXAMPLE.com" as an example
# When this is done, there will be an "acme" user that handles issuing,
# updating, and installing certificates. This account will have the following
# (fairly minimal) permissions:
# - Host files at http://EXAMPLE.com/.well-known/acme-challenge
# - Copy certificates to /etc/nginx/auth-acme
# - Reload your nginx server
# First things first - create a user account for acme
sudo useradd -m -d /var/lib/acme -s /usr/sbin/nologin acme
sudo chmod 700 /var/lib/acme
# Create a directory for the acme account to save certs in
sudo mkdir /etc/nginx/auth-acme
sudo chown acme.www-data /etc/nginx/auth-acme
sudo chmod 710 /etc/nginx/auth-acme
# Create a directory under the webroot for acme to put webroot challenge responses
sudo mkdir -p /var/www/EXAMPLE.com/.well-known/acme-challenge
sudo chown acme.acme /var/www/EXAMPLE.com/.well-known/acme-challenge
sudo chmod 755 /var/www/EXAMPLE.com/.well-known/acme-challenge
# Also make sure the acme user has at least eXecute permissions on all parent
# directories of this directory. This will generally be true by default.
# Edit your nginx config file to publish the well-known directory on your site.
# Lets Encrypt checks on port 80, non-SSL, so you need to at least not redirect
# that location.
sudo vim /etc/nginx/sites-enabled/EXAMPLE.com
## Example config section:
# webroot for acme
server {
listen [::]:80;
server_name EXAMPLE.com;
location ~ /.well-known {
allow all;
root /var/www/EXAMPLE.com;
}
location / {
rewrite ^ https://EXAMPLE.com$request_uri? permanent;
}
}
# Make sure nginx is configured properly
sudo nginx -t
sudo service nginx reload
# Edit your sudoers file to allow the acme user to reload (not restart) nginx
sudo visudo
# Add the following line:
acme ALL=(ALL) NOPASSWD: /usr/sbin/service nginx reload
# Now change to the ACME user - you'll do most of the rest of this guide as them
sudo -s -u acme bash
export HOME=/var/lib/acme
cd /var/lib/acme
# Install acme.sh
git clone https://github.com/Neilpang/acme.sh.git
cd acme.sh
./acme.sh --install
# Create your first certificate (from here on is roughly what you'll repeat)
cd /var/lib/acme
.acme.sh/acme.sh --issue -d EXAMPLE.com -w /var/www/EXAMPLE.com
# If everything went well, install your certificate
.acme.sh/acme.sh --installcert -d EXAMPLE.com \
--keypath /etc/nginx/auth-acme/EXAMPLE.com.key \
--capath /etc/nginx/auth-acme/EXAMPLE.com.ca \
--fullchainpath /etc/nginx/auth-acme/EXAMPLE.com.crt \
--reloadcmd "sudo service nginx reload"
# Drop back to your own user
exit
# Now modify your nginx config to work with the new certs
sudo vim /etc/nginx/sites-enabled/EXAMPLE.com
# Example SSL config section
server {
...
ssl_certificate /etc/nginx/auth-acme/EXAMPLE.com.crt;
ssl_certificate_key /etc/nginx/auth-acme/EXAMPLE.com.key;
ssl_trusted_certificate /etc/nginx/auth-acme/EXAMPLE.com.ca;
include ssl_settings.conf;
...
}
# Test nginx
sudo nginx -t
# And reload if it worked
sudo service nginx reload
# Congrats, you have letsencrypt and nobody ran anything as root on your box.
# Don't forget to back up /var/lib/acme/.acme.sh - it has your letsencrypt account keys!
@Lacoste
Copy link

Lacoste commented May 15, 2018

I suppose you could say that this is setting it up without the literal root password ... but using sudo is running the commands as root, and modifying files that require root access.

@cfiske
Copy link

cfiske commented Jul 28, 2018

@Lacoste unless I'm mistaken, while sudo/root is needed at setup time it will not be needed after that. The installed acme.sh would be able to renew and install certs without root or sudo because the directories permit the acme user to write to them.

@adamczi
Copy link

adamczi commented Sep 12, 2019

Incorrect, the point is in "--reloadcmd "sudo service nginx reload" parameter - user running acme.sh would have to be able to run that sudo. Sorry for necroing this thread.

@Greelan
Copy link

Greelan commented Dec 12, 2019

Kudos to @lachesis for posting this. I had to adapt it slightly to my use case (specifically DNS validation, plus I substituted systemd services for the default cron job) but it otherwise worked like a charm. So thanks! Slight tweak I found was necessary (perhaps due to changes to acme.sh since the original post) is that the two acme.sh commands (starting lines 75 and 78) needed the --force flag to run, as the script otherwise complained about it being run as sudo and wouldn't execute. See my fork for the steps I used if that would help anyone in a similar scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment