acme-client
Tools
PHP
acme-client (Deprecated)
a small PHP script to get and renew TLS certs from Let’s Encrypt (Deprecated)
-
ACME v1 is deprecated,
Please Use https://github.com/kaienkira/acme-v2-client instead -
Please Read The Lastest Terms of Service Of Let’s Encrypt Before You Use this Script.
https://acme-v01.api.letsencrypt.org/terms - Please Audit The Code Before You Use It
- Never Let The Script Run By Root
- Never Let The Script Read Your Domain Private Key
-
use ssl server test to check your website’s security
https://www.ssllabs.com/ssltest/
What you need to use this script to setup a https website
-
account private key
- used to register and communicate with acme server
- the script need the read access of the account key
-
domain private key
- used as your website ssl private key
- it must be different from your account private key for security
- keep it in safe place, don’t let the script read it
-
csr file (Certificate Signing Request)
- used to request the cert from CA
- can be generated from your domain private key
- the script need the read access of the csr file
-
http challenge dir (which can be access by your domain)
-
used to prove the domain is in your control, acme server will
access your domain like
http://yourdomain.com/.well-known/acme-challenge/ - the script need the write access of the http challenge dir
- the script will put the challenge file in this dir
-
used to prove the domain is in your control, acme server will
-
a new user
- used to run this script
- for security, never run this script by root
-
the user can not login from ssh
(set your /etc/passwd to disable login for the new user) - the user can not read the domain private key
- the user can read the account private key, csr file only
- the user can write to the http challenge dir
-
set the renew cert crontab task for this user
(Let’s Encrypt cert will exprired about 90 days)
-
custom dh paramters (optional)
- fix the weak Diffie-Hellman and the logjam attack issue
Script Usage
usage: acme-client.php
-a <account_key_file>
-r <csr_file>
-d <domain_list(domain1;domain2...;domainN)>
-c <http_challenge_dir>
-o <output_cert_file>
[-t <terms_of_service>]
if -t command line option is set and it does not equal to the latest tos url,
you will get a error like:
terms of service has changed: please modify your -t command option
new tos: <new_tos>
Detail Guide
dependency
# install php-cli first
sudo apt-get install php-cli php-curl
generate account private key
openssl genrsa -out account.key 4096
generate domain private key
openssl genrsa -out domain.key 2048
generate custom dh paramters
openssl dhparam -out dhparams.pem 2048
generate csr from domain private key
# single domain
openssl req -new -sha256 -key domain.key -out domain.csr -subj "/CN=domain.com"
# multiple domain
cp /etc/ssl/openssl.cnf domain.conf
printf "[SAN]nsubjectAltName=DNS:domain.com,DNS:www.domain.com" >> domain.conf
openssl req -new -sha256 -key domain.key -out domain.csr -subj "/"
-reqexts SAN -config domain.conf
add a sslcert user, put the key in place
useradd -M sslcert
mkdir /opt/sslcert
mkdir /opt/sslcert/bin
mkdir /opt/sslcert/keys
mkdir /opt/sslcert/certs
mkdir /opt/sslcert/acme-challenge
cp acme-client.php /opt/sslcert/bin
mv account.key /opt/sslcert/keys
mv domain.csr /opt/sslcert/keys
mv domain.key /etc/ssl/private
mv dhparams.pem /etc/ssl/private
chown -R sslcert:sslcert /opt/sslcert/keys
chown -R sslcert:sslcert /opt/sslcert/certs
chown -R sslcert:sslcert /opt/sslcert/acme-challenge
chmod 700 /opt/sslcert/keys
chmod 600 /opt/sslcert/keys/account.key
chmod 600 /opt/sslcert/keys/domain.csr
chmod 600 /etc/ssl/private/domain.key
chmod 600 /etc/ssl/private/dhparams.pem
change nginx config to add http challenge dir
server {
listen 80 default_server;
server_name domain.com www.domain.com;
root /opt/www/html;
index index.html;
try_files $uri $uri/ =404;
location /.well-known/acme-challenge/ {
default_type text/plain;
alias /opt/sslcert/acme-challenge/;
}
}
service nginx reload
create a wrap script
vi /opt/sslcert/bin/getcert.sh
chmod +x /opt/sslcert/bin/getcert.sh
#!/bin/bash
php /opt/sslcert/bin/acme-client.php
-a /opt/sslcert/keys/account.key
-r /opt/sslcert/keys/domain.csr
-d "domain.com;www.domain.com"
-c /opt/sslcert/acme-challenge
-o /opt/sslcert/certs/domain.crt.new
if [ $? -ne 0 ]
then
exit 1
fi
cp /opt/sslcert/certs/domain.crt.new
/opt/sslcert/certs/domain.crt
rm -f -- /opt/sslcert/acme-challenge/*
get cert
su -s /bin/bash -c '/opt/sslcert/bin/getcert.sh' sslcert
final nginx ssl conf
server {
listen 80 default_server;
server_name domain.com www.domain.com;
root /opt/www/html;
index index.html;
try_files $uri $uri/ =404;
location /.well-known/acme-challenge/ {
default_type text/plain;
alias /opt/sslcert/acme-challenge/;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name domain.com www.domain.com;
root /opt/www/html;
index index.html;
try_files $uri $uri/ =404;
ssl on;
ssl_certificate /opt/sslcert/certs/domain.crt;
ssl_certificate_key /etc/ssl/private/domain.key;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/private/dhparams.pem;
}
service nginx reload
set crontab task to renew cert (run every week)
crontab -u sslcert -e
0 0 * * 1 /bin/bash /opt/sslcert/bin/getcert.sh
Thanks
tialaramex@reddit