Created
October 9, 2016 19:25
-
-
Save nikolaik/e6a4f4705f1241c36c865f008ac1d42c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/env python3 | |
# coding: utf-8 | |
import os | |
from subprocess import Popen, PIPE | |
import shutil | |
# SETTINGS | |
CERT_DIR = '/etc/nginx/ssl/' | |
WEBROOT = '/tmp/letsencrypt' | |
LEGO = './lego' | |
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | |
LEGO_CERT_DIR = os.path.join(BASE_DIR, '.lego/certificates/') | |
RENEW_MIN_DAYS = 30 | |
# Load settings from local_settings.py | |
try: | |
from local_settings import * | |
except ImportError: | |
pass | |
def get_env(): | |
env = os.environ.copy() | |
# Set DNS vars in environment | |
for k, v in RFC2136.items(): | |
env['RFC2136_' + k] = v | |
return env | |
def copy_certs(domain): | |
cert_path = os.path.join(LEGO_CERT_DIR, '{}.crt'.format(domain)) | |
key_path = os.path.join(LEGO_CERT_DIR, '{}.key'.format(domain)) | |
dst_dir = os.path.join(CERT_DIR, domain) | |
# copy cert and key | |
shutil.copy(cert_path, dst_dir) | |
shutil.copy(key_path, dst_dir) | |
def lego_cmd(domains): | |
domain_params = [] | |
for d in domains: | |
domain_params.append('-d') | |
domain_params.append(d) | |
global_options = [ | |
'--accept-tos', | |
'--email', ACCOUNT, | |
'--dns', 'rfc2136', | |
'--exclude', 'http-01', | |
'--exclude', 'tls-sni-01', | |
] + domain_params | |
command_options = [ | |
'--days', str(RENEW_MIN_DAYS), | |
'--reuse-key' | |
] | |
cmd = [LEGO] + global_options + ['renew'] + command_options | |
print(' '.join(cmd)) | |
p = Popen(cmd, stdout=PIPE, stderr=PIPE, env=get_env()) | |
out, err = p.communicate() | |
if p.returncode != 0: | |
print(out.decode('utf-8'), err.decode('utf-8')) | |
return p.returncode | |
def renew(domains): | |
if len(domains) == 0: | |
return | |
primary_domain = domains[0] # First in list | |
cert_dir = os.path.join(CERT_DIR, primary_domain) | |
if not os.path.exists(cert_dir): | |
# Create missing cert dir | |
os.mkdir(cert_dir) | |
ret = lego_cmd(domains) | |
# TODO chmod private files | |
if ret == 0: | |
# FIXME: ret is too often 0 | |
copy_certs(primary_domain) | |
return ret | |
def reload_nginx(): | |
cmd = ['nginx', '-s', 'reload'] | |
p = Popen(cmd, stdout=PIPE, stderr=PIPE) | |
out, err = p.communicate() | |
if p.returncode != 0: | |
print(out.decode('utf-8'), err.decode('utf-8')) | |
return False | |
return True | |
def renew_certs(cert_domains): | |
"""Take a list of domain certs and try to renew them""" | |
needs_reload = False | |
for cert in cert_domains: | |
print('{}...'.format(cert[0])) | |
res = renew(cert) | |
if res == 0: | |
print('OK') | |
needs_reload = True | |
elif res == 1: | |
print("ERROR") | |
if needs_reload: | |
print("Reloading Nginx") | |
reload_nginx() | |
if __name__ == '__main__': | |
""" | |
Create/renew letsencrypt certificates with the lego client | |
Ref: https://github.com/xenolf/lego | |
Ref: https://letsencrypt.org | |
Uses DNS verification via RFC2136. | |
Assumes the domain server is setup with correct keys | |
Provides certs that can be included like this: | |
ssl_stapling on; | |
ssl_stapling_verify on; | |
ssl_certificate /etc/nginx/ssl/DOMAIN/DOMAIN.crt; | |
ssl_certificate_key /etc/nginx/ssl/DOMAIN/DOMAIN.key; | |
""" | |
if not os.path.exists(CERT_DIR): | |
print("Creating nginx cert dir {}.".format(CERT_DIR)) | |
os.mkdir(CERT_DIR) | |
if not os.path.exists(WEBROOT): | |
print("Creating webroot dir {}.".format(WEBROOT)) | |
os.mkdir(WEBROOT) | |
if not shutil.which(LEGO): | |
print("ERROR: Missing {} in PATH.".format(LEGO)) | |
exit(1) | |
print("Renewing {} certs with letsencrypt".format(len(CERT_DOMAINS))) | |
renew_certs(CERT_DOMAINS) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment