diff --git a/Dockerfile b/Dockerfile index f5ca275..071d494 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,24 @@ -FROM debian +FROM debian8_python3 MAINTAINER Joachim Lusiardi RUN apt-get update; \ - apt-get install -y haproxy; + apt-get install -y \ + git \ + haproxy; \ + git clone https://github.com/letsencrypt/letsencrypt ;\ + cd /letsencrypt ;\ + ./letsencrypt-auto --help +ADD haproxy_ssl.conf /haproxy_ssl.conf ADD haproxy.conf /haproxy.conf +ADD letencrypt.conf /letencrypt.conf -ADD start.sh /start.sh -RUN chmod +x /start.sh +ADD start.py /start.py +RUN chmod +x /start.py VOLUME ["/data"] +EXPOSE 80 EXPOSE 443 -ENTRYPOINT /start.sh +ENTRYPOINT /start.py diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..6bf4598 --- /dev/null +++ b/NOTES @@ -0,0 +1,12 @@ + +# Nach start von haproxy ohne ssl: +/letsencrypt/letsencrypt-auto --config letencrypt.conf certonly -d lusiardi.de +cat /data/config/live/lusiardi.de/fullchain.pem /data/config/live/lusiardi.de/privkey.pem > /data/haproxy/cert.pem + + +# Nach start von haproxy mit ssl: +/letsencrypt/letsencrypt-auto --config letencrypt.conf certonly --standalone-supported-challenges http-01 --http-01-port 54321 --expand -d lusiardi.de -d ps.lusiardi.de +cat /data/config/live/lusiardi.de/fullchain.pem /data/config/live/lusiardi.de/privkey.pem > /data/haproxy/cert.pem + +# aufräumen +rm -rf /data/* diff --git a/haproxy.conf b/haproxy.conf index c54033d..079f2de 100644 --- a/haproxy.conf +++ b/haproxy.conf @@ -21,10 +21,15 @@ defaults timeout client 50000 timeout server 50000 -frontend https - bind *:443 ssl crt /data/cert.pem - reqadd X-Forwarded-Proto:\ https +frontend http + bind *:80 + reqadd X-Forwarded-Proto:\ http + acl letsencrypt-acl path_beg /.well-known/acme-challenge/ + use_backend letsencrypt-backend if letsencrypt-acl default_backend www-backend backend www-backend server one target:80 + +backend letsencrypt-backend + server letsencrypt 127.0.0.1:54321 diff --git a/haproxy_ssl.conf b/haproxy_ssl.conf new file mode 100644 index 0000000..18862fa --- /dev/null +++ b/haproxy_ssl.conf @@ -0,0 +1,42 @@ +global + chroot /var/lib/haproxy + stats socket /admin.sock mode 660 level admin + stats timeout 30s + user haproxy + group haproxy + daemon + + ca-base /etc/ssl/certs + crt-base /crypt + + ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL + ssl-default-bind-options no-sslv3 + +defaults + #log global + mode http + #option httplog + #option dontlognull + timeout connect 5000 + timeout client 50000 + timeout server 50000 + +frontend http + bind *:80 + reqadd X-Forwarded-Proto:\ http + acl letsencrypt-acl path_beg /.well-known/acme-challenge/ + use_backend letsencrypt-backend if letsencrypt-acl + default_backend www-backend + +frontend https + bind *:443 ssl crt /data/haproxy/cert.pem + reqadd X-Forwarded-Proto:\ https + acl letsencrypt-acl path_beg /.well-known/acme-challenge/ + use_backend letsencrypt-backend if letsencrypt-acl + default_backend www-backend + +backend www-backend + server one target:80 + +backend letsencrypt-backend + server letsencrypt 127.0.0.1:54321 diff --git a/letencrypt.conf b/letencrypt.conf new file mode 100644 index 0000000..00cb3ca --- /dev/null +++ b/letencrypt.conf @@ -0,0 +1,8 @@ +non-interactive=TRUE +standalone +staging +logs-dir=/data/logs +work-dir=/data/work +config-dir=/data/config +email=letsencrypt@lusiardi.de +agree-tos=TRUE diff --git a/start.py b/start.py new file mode 100644 index 0000000..413c47b --- /dev/null +++ b/start.py @@ -0,0 +1,113 @@ +#!/usr/bin/python3.4 + +import os +import signal +import logging +import time +import hashlib + +cert_path='/data/haproxy' +cert_file='/data/haproxy/cert.pem' +pid_file='/haproxy.pid' + + +def hash_cert_file(): + if not os.path.isfile(cert_file): + return '' + aFile = open(cert_file, 'rb') + hasher = hashlib.sha256() + buf = aFile.read(65536) + while len(buf) > 0: + hasher.update(buf) + buf = aFile.read(65536) + return hasher.digest() + +def setup_logging(): + """Sets up logging with a nice format""" + logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO) + +def get_pid(): + """This function reads the process id from the given file and returns as int.""" + with open(pid_file, 'r') as file: + return int(file.read()) + +def kill_haproxy(): + """Stops the currently running instance of haproxy by issueing a kill signal to its pid.""" + logging.info('killing haproxy') + try: + os.kill(get_pid(), signal.SIGKILL) + except OSError: + pass + +def start_haproxy_ssl(): + logging.info('starting haproxy SSL') + os.system('/usr/sbin/haproxy -f /haproxy_ssl.conf -p /haproxy.pid') + +def start_haproxy(): + logging.info('starting haproxy NON SSL') + os.system('/usr/sbin/haproxy -f /haproxy.conf -p /haproxy.pid') + +def is_haproxy_running(): + try: + os.kill(get_pid(), 0) + return True + except OSError: + return False + +def ssl_possible(): + """Check if a certificate is available.""" + if not os.path.exists(cert_path): + logging.info('creating cert_path path: %s', cert_path) + os.mkdir(cert_path) + + if not os.path.isfile(cert_file): + return False + else: + return True + +if __name__ == '__main__': + setup_logging() + + logging.info('starting') + + cert_file_hash = '' + + if ssl_possible(): + logging.info('try in SSL mode') + start_haproxy_ssl() + cert_file_hash = hash_cert_file() + if is_haproxy_running(): + SSL_RUNNING=True + else: + logging.info('SSL mode failed') + if not is_haproxy_running() or not ssl_possible(): + logging.info('try in NON SSL mode') + start_haproxy() + SSL_RUNNING=False + + while True: + time.sleep(10) + if ssl_possible() and not SSL_RUNNING: + kill_haproxy() + start_haproxy_ssl() + if is_haproxy_running(): + cert_file_hash = hash_cert_file() + logging.info('NON SSL -> SSL') + SSL_RUNNING=True + else: + start_haproxy() + SSL_RUNNING=False + if SSL_RUNNING and cert_file_hash != hash_cert_file(): + logging.info('cert has changed') + kill_haproxy() + start_haproxy_ssl() + if is_haproxy_running(): + cert_file_hash = hash_cert_file() + logging.info('SSL -> SSL') + SSL_RUNNING=True + else: + start_haproxy() + logging.info('SSL -> NON SSL') + SSL_RUNNING=False +# logging.info('haproxy is running: %s', str(is_haproxy_running())) +# logging.info('haproxy is running with SSL: %s', str(SSL_RUNNING)) diff --git a/start.sh b/start.sh index c3f3e75..949f4ea 100644 --- a/start.sh +++ b/start.sh @@ -1,3 +1,10 @@ #!/bin/bash -/usr/sbin/haproxy -f /haproxy.conf -p /haproxy.pid -db + +if [ -s /data/haproxy/cert.pem ] +then + # ssl cert seems to exist, so start with + /usr/sbin/haproxy -f /haproxy_ssl.conf -p /haproxy.pid -db +else + bash +fi