Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save joshxyzhimself/cc3edfc8f08f11e6ee576f004c528a4e to your computer and use it in GitHub Desktop.
Save joshxyzhimself/cc3edfc8f08f11e6ee576f004c528a4e to your computer and use it in GitHub Desktop.

Revisions

  1. @lmmendes lmmendes revised this gist Jun 28, 2016. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions haproxy_letsencrypt.md
    Original file line number Diff line number Diff line change
    @@ -175,8 +175,6 @@ LETSENCRYPT_BIN=/opt/letsencrypt/letsencrypt-auto
    LETSENCRYPT_CERT_OUTPUT=/etc/letsencrypt/live

    # Create or renew certificate for the domain(s) supplied for this tool
    # $LETSENCRYPT_BIN certonly --domains letsencrypt.passworks.io --authenticator standalone --renew-by-default --standalone-supported-challenges http-01 --text --http-01-port 63443 --agree-tos --email [email protected]

    $LETSENCRYPT_BIN certonly \
    --authenticator standalone \
    --keep-until-expiring \
  2. @lmmendes lmmendes created this gist Jun 28, 2016.
    206 changes: 206 additions & 0 deletions haproxy_letsencrypt.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,206 @@

    # HAProxy and Let's Encrypt


    [HAProxy](https://www.haproxy.org) is a open-source TCP/HTTP load-balancing proxy server supporting native SSL, keep-alive, compression CLI, and other modern features.

    [Let’s Encrypt](https://letsencrypt.org/) is a free, automated, and open certificate authority (CA), run for the public’s benefit. Let’s Encrypt is a service provided by the Internet Security Research Group (ISRG).


    ## Concept

    Let's Encrypt offers many options and plugins to create and validate certificate via its client.


    If you’re running a local webserver for which you have the ability to modify the content being served, and you’d prefer not to stop the webserver during the certificate issuance process, you can use the webroot plugin to obtain a cert by including certonly and `--webroot` on the command line. In addition, you’ll need to specify `--webroot-path` or `-w` with the top-level directory (“web root”) containing the files served by your webserver. For example, `--webroot-path /var/www/html` or `--webroot-path /usr/share/nginx/html` are two common webroot paths.
    Read more about this option here https://certbot.eff.org/docs/using.html#webroot


    In our production environment we have the following setup, HAProxy will handle all HTTP and HTTPS connections (it will terminate the HTTPS connections) and forward all incomming connections to the backend servers in HTTP.

    Meanwhile let's encrypt client will be running in the background auto renewing the certificates when they are about to expire.

    > Let’s Encrypt CA issues short-lived certificates (90 days). Make sure you renew the certificates at least once in 3 months.
    >
    > See [https://certbot.eff.org/docs/using.html#renewal](https://certbot.eff.org/docs/using.html#renewal) for more information.

    ![HAProxy & Let's Encrypt](https://assets.digitalocean.com/articles/letsencrypt/haproxy-letsencrypt.png)

    But there is a catch in our design, Let's Encrypt client using the [`--standalone`](https://certbot.eff.org/docs/using.html#standalone) plugin will try to launch a webserver that will bind it self to port 80 or 443 (depending the configuration) in order to perform the domain validation.

    This happens because Let's Encrypt server will try to make request to the Let's Encrypt client web server using only the port 80 or 443.

    So the problem is that you can't stop HAProxy to allow that the Let's Encript client binds to the port 80 or 433 because that means downtime.

    So here is a good exercise to use HAProxy proxy capabilities, our plan will to be we will have HAProxy running and binding to the 80 and 443 ports, handling incoming HTTP and HTTPS connections to our backends but when a request comes from the Let's Encrypt server trying to validate the domain, HAProxy will proxy the request to the Let's Encrypt client's web server running on a different port in this case we will be using the 63443 port.


    ## Assumptions and prerequisites


    This tutorial was created using Ubuntu 14.04 and HAProxy 1.5. The version of the `letencrypt` at the time was 0.8.1.

    I assume that you how a domain eg: letsencrypt.passworks.io


    ## 1.Update the base system


    Update your server's package manager:

    ```
    $ sudo apt-get update
    ```

    Ensure th

    ```
    $ sudo apt-get upgrade
    ```

    ## 2. Install Let's encrypt client

    Install the git and bc packages with apt-get:

    ```
    $ sudo apt-get -y install git bc
    ```

    We can now clone the Let’s Encrypt repository in /opt with this command:

    ```
    sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
    ```

    ## 3. Install HAProxy

    Before installing HAProxy we need to install install

    ```
    sudo apt-get install --yes software-properties-common
    ```

    Install HAProxy

    ```
    sudo apt-add-repository ppa:vbernat/haproxy-1.5
    sudo apt-get update
    sudo apt-get install --yes haproxy
    ```

    ## 4. Configure HAProxy


    ```
    frontend fe_http
    log global
    mode http
    option httplog
    bind PUBLIC_HAPROXY_IP:80
    acl app_letsencrypt path_beg /.well-known/acme-challenge/
    use_backend be_letsencrypt if app_letsencrypt
    frontend fe_https
    log global
    mode http
    option httplog
    bind 0.0.0.0:443 ssl crt /etc/haproxy/ssl/
    tcp-request inspect-delay 5s
    tcp-request content accept if { req.ssl_hello_type 1 }
    ```

    HAProxy backend rule for HTTP (80) traffic:

    ```
    backend be_letsencrypt
    log global
    mode http
    option httplog
    server srv_letsencrypt 127.0.0.1:63443
    ```


    # 5. Generate certificates using Let's Encrypt

    Let's try to generate our certificates for `passworks.io` and for the subdomain `www.passworks.io` (don't forget to replace the domain `passworks.io` and `www.passworks.io` with or desired domain and replace `[email protected]` with our own e-mail address.

    To generate the certifica type:

    ```
    /opt/letsencrypt/letsencrypt-auto certonly \
    --authenticator standalone \
    --keep-until-expiring \
    --standalone-supported-challenges http-01 \
    --http-01-port 63443 \
    --text \
    --expand \
    --agree-tos \
    --email [email protected] \
    -d passworks.io \
    -d www.passworks.io \
    ```

    If everything goes right you will have your new certificates in `/etc/letsencrypt/live`

    Now we will need to copy the new certificates to a folder where HAProxy can see them so let's start to create the folder inside the HAProxy installation folder:

    ```
    mkdir -p /etc/haproxy/ssl/
    ```

    Let's concat the private certificate with the full public certificate chain and make it available to HAProxy:

    ```
    cat /etc/letsencrypt/live/passworks.io/{fullchain.pem,privkey.pem} > /etc/haproxy/ssl/passworks.io.pem
    ```

    Now restart your hproxy and open your browser and start testing your new certificates:

    ```
    sudo service haproxy reload
    ```

    ## 6. Automation


    ```bash
    #!/bin/bash

    # Path to the letsencrypt-auto tool
    LETSENCRYPT_BIN=/opt/letsencrypt/letsencrypt-auto

    # Directory where the acme client puts the generated certs
    LETSENCRYPT_CERT_OUTPUT=/etc/letsencrypt/live

    # Create or renew certificate for the domain(s) supplied for this tool
    # $LETSENCRYPT_BIN certonly --domains letsencrypt.passworks.io --authenticator standalone --renew-by-default --standalone-supported-challenges http-01 --text --http-01-port 63443 --agree-tos --email [email protected]

    $LETSENCRYPT_BIN certonly \
    --authenticator standalone \
    --keep-until-expiring \
    --standalone-supported-challenges http-01 \
    --http-01-port 63443 \
    --text \
    --expand \
    --agree-tos \
    --email [email protected] \
    -d passworks.io \
    -d www.passworks.io \
    -d brodo.passworks.io \
    -d manage.passworks.io \
    -d api.passworks.io

    # Cat the certificate chain and the private key together for haproxy
    for path in $(find $LETSENCRYPT_CERT_OUTPUT/* -type d -exec basename {} \;); do
    cat $LETSENCRYPT_CERT_OUTPUT/$path/{fullchain.pem,privkey.pem} > /etc/haproxy/ssl/${path}.pem
    done

    ```

    Edit your crontab using `sudo crontab -e`

    ```
    2 1,13 * * * sudo /home/ubuntu/letsencrypt/letsencrypt-passworks.sh
    ```