Categories
Docker nginx Ubuntu 🏴‍☠️

วิธีการติดตั้ง Free SSL Certificates จาก Let’s Encrypt โดยใช้ Docker และ Nginx

Spread the love

Install Docker on Ubuntu

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

 Update the Ubuntu package database

sudo apt-get update

install Docker

sudo apt-get install -y docker-ce

Install Docker Compose on Ubuntu

sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

A Better Solution: Run Let’s Encypt’s Certbot in a Docker Container

On your server, create a new Directory:

sudo mkdir -p /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site

Then, create a new docker-compose.yml file

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/docker-compose.yml

docker-compose.yml

version: '3.1'

services:

  letsencrypt-nginx-container:
    container_name: 'letsencrypt-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./letsencrypt-site:/usr/share/nginx/html
    networks:
      - docker-network

networks:
  docker-network:
    driver: bridge

 Then, create a configuration file for nginx

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/nginx.conf

nginx.conf

server {
listen 80;
listen [::]:80;
server_name xxx.com www.xxx.com;

location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}

root /usr/share/nginx/html;
index index.html;
}

Next, create an index.html file

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site/index.html

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Let's Encrypt First Time Cert Issue Site</title>
</head>
<body>
    <h1>Hello!</h1>
    <p>
        This is the temporary site that will only be used for the very first time SSL certificates are issued by Let's Encrypt's
        certbot.
    </p>
</body>
</html>

Before running the Certbot command, spin up a Nginx container in Docker to ensure the temporary Nginx site is up and running

cd /docker/letsencrypt-docker-nginx/src/letsencrypt
sudo docker-compose up -d

Then, open up a browser and visit the domain to ensure that the Docker container is up and running and accessible. As stated earlier, it’s not necessary to have a default index.html page for this container, but it makes testing the container a lot easier, so I always create one.

Run the staging command for issuing a new certificate:

sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d xxx.com -d www.xxx.com

After executing the above command, you should get the following output which should indicate everything ran successfully.

You can also get some additional information about certificates for your domain by running the Certbot certificates command:

sudo docker run --rm -it --name certbot \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
certbot/certbot \
--staging \
certificates

If the staging command executed successfully, execute the command to return a live certificate

First, clean up staging artifacts:

sudo rm -rf /docker-volumes/

And then request a production certificate: (note that it’s a good idea to supply your email address so that Let’s Encrypt can send expiry notifications)

sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt \
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsencrypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--email [email protected].com --agree-tos --no-eff-email \
--webroot-path=/data/letsencrypt \
-d xxx.com -d www.xxx.com

If everything ran successfully, run a docker-compose down command to stop the temporary Nginx site

cd /docker/letsencrypt-docker-nginx/src/letsencrypt
sudo docker-compose down

Set up Your Production Site to Run in a Nginx Docker Container

sudo mkdir -p /docker/letsencrypt-docker-nginx/src/production/production-site
sudo mkdir -p /docker/letsencrypt-docker-nginx/src/production/dh-param

docker-compose.yml

version: '3.1'

services:

  production-nginx-container:
    container_name: 'production-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./production.conf:/etc/nginx/conf.d/default.conf
      - ./production-site:/usr/share/nginx/html
      - ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem
      - /docker-volumes/etc/letsencrypt/live/xxx.com/fullchain.pem:/etc/letsencrypt/live/xxx.com/fullchain.pem
      - /docker-volumes/etc/letsencrypt/live/xxx.com/privkey.pem:/etc/letsencrypt/live/xxx.com/privkey.pem
    networks:
      - docker-network

networks:
  docker-network:
    driver: bridge

Next, create the Nginx configuration file for the production site

sudo nano /docker/letsencrypt-docker-nginx/src/production/production.conf

production.conf

server {
    listen      80;
    listen [::]:80;
    server_name xxx.com www.xxx.com;

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }

    #for certbot challenges (renewal process)
    location ~ /.well-known/acme-challenge {
        allow all;
        root /data/letsencrypt;
    }
}
#https://xxx.com
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ohhaithere.com;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/xxx.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/xxx.com/privkey.pem;

    ssl_buffer_size 8k;

    ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;

    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl_ecdh_curve secp384r1;
    ssl_session_tickets off;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;

    return 301 https://www.xxx.com$request_uri;
}
#https://www.xxx.com
server {
    server_name www.xxx.com;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_tokens off;

    ssl on;

    ssl_buffer_size 8k;
    ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl_ecdh_curve secp384r1;
    ssl_session_tickets off;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4;

    ssl_certificate /etc/letsencrypt/live/xxx.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/xxx.com/privkey.pem;

    root /usr/share/nginx/html;
    index index.html;
}

Generate a 2048 bit DH Param file

sudo openssl dhparam -out /docker/letsencrypt-docker-nginx/src/production/dh-param/dhparam-2048.pem 2048

Copy your site content into the mapped directory:

/docker/letsencrypt-docker-nginx/src/production/production-site/

Spin up the production site in a Docker container:

cd /docker/letsencrypt-docker-nginx/src/production
sudo docker-compose up -d

How to Renew Let’s Encrypt SSL Certificates with Certbot and Docker

Earlier, we placed the following section in the production Nginx configuration file:

location ~ /.well-known/acme-challenge {
    allow all;
    root /usr/share/nginx/html;
}

The production site’s docker-compose file then maps a volume into the Nginx container that can be used for challenge requests:

production-nginx-container:
    container_name: 'production-nginx-container'
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      #other mapped volumes...
      #for certbot challenges
      - /docker-volumes/data/letsencrypt:/data/letsencrypt
    networks:
      - docker-network

To add a crontab, run the following commands:

sudo crontab -e

Place the following at the end of the file, then close and save it.

0 23 * * * docker run --rm -it --name certbot -v "/docker-volumes/etc/letsencrypt:/etc/letsencrypt" -v "/docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt" -v "/docker-volumes/data/letsencrypt:/data/letsencrypt" -v "/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" certbot/certbot renew --webroot -w /data/letsencrypt --quiet && docker kill --signal=HUP production-nginx-container

ref: https://www.humankode.com/ssl/how-to-set-up-free-ssl-certificates-from-lets-encrypt-using-docker-and-nginx

Spread the love