From ebfeffb7a3fe182bc3020c84e3572ee27773b6af Mon Sep 17 00:00:00 2001 From: Loic Date: Tue, 11 Jan 2022 17:52:12 +0100 Subject: [PATCH] Add With Certbot Nginx example (#73) --- examples/with-certbot/.env | 7 ++ examples/with-certbot/Dockerfile | 7 ++ examples/with-certbot/docker-compose.yml | 57 +++++++++++++ .../with-certbot/dolibarr-with-certbot.md | 31 +++++++ examples/with-certbot/https.png | Bin 0 -> 25338 bytes examples/with-certbot/init-letsencrypt.sh | 80 ++++++++++++++++++ examples/with-certbot/nginx/nginx.conf | 29 +++++++ 7 files changed, 211 insertions(+) create mode 100644 examples/with-certbot/.env create mode 100644 examples/with-certbot/Dockerfile create mode 100644 examples/with-certbot/docker-compose.yml create mode 100644 examples/with-certbot/dolibarr-with-certbot.md create mode 100644 examples/with-certbot/https.png create mode 100644 examples/with-certbot/init-letsencrypt.sh create mode 100644 examples/with-certbot/nginx/nginx.conf diff --git a/examples/with-certbot/.env b/examples/with-certbot/.env new file mode 100644 index 0000000..0aa41da --- /dev/null +++ b/examples/with-certbot/.env @@ -0,0 +1,7 @@ +SITE_URL=https://www.exemple.com/ +DB_HOST=doli_mysql +DB_PORT=3306 +DB_USER=doli +DB_PASS=!ChangeMe! +DB_ROOT_PASS=ChangeMeToo! +DB_NAME=dolibarr diff --git a/examples/with-certbot/Dockerfile b/examples/with-certbot/Dockerfile new file mode 100644 index 0000000..384ec37 --- /dev/null +++ b/examples/with-certbot/Dockerfile @@ -0,0 +1,7 @@ +FROM nginx:alpine + +WORKDIR /etc/nginx +COPY ./nginx/nginx.conf ./conf.d/default.conf +EXPOSE 8080 +ENTRYPOINT [ "nginx" ] +CMD [ "-g", "daemon off;" ] diff --git a/examples/with-certbot/docker-compose.yml b/examples/with-certbot/docker-compose.yml new file mode 100644 index 0000000..3749e6c --- /dev/null +++ b/examples/with-certbot/docker-compose.yml @@ -0,0 +1,57 @@ +version: "3.4" + +services: + db: + image: mysql:8.0.20 + container_name: doli_mysql + command: mysqld --default-authentication-plugin=mysql_native_password --max_allowed_packet=32505856 + restart: always + env_file: + - ./.env + environment: + - MYSQL_DATABASE=${DB_NAME} + - MYSQL_USER=${DB_USER} + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASS} + - MYSQL_PASSWORD=${DB_PASS} + volumes: + - ./docker/db/data:/var/lib/mysql + + web: + image: tuxgasy/dolibarr + container_name: doli_web + env_file: + - ./.env + environment: + DOLI_DB_HOST: ${DB_HOST} + DOLI_DB_USER: ${DB_USER} + DOLI_DB_PASSWORD: ${DB_PASS} + DOLI_DB_HOST_PORT: ${DB_PORT} + DOLI_DB_NAME: ${DB_NAME} + DOLI_URL_ROOT: ${SITE_URL} + PHP_INI_DATE_TIMEZONE: 'Europe/Paris' + ports: + - "8181:80" + links: + - db + volumes: + - ./docker/doli/documents:/var/www/documents + + nginx: + container_name: doli_nginx + image: nginx:latest + ports: + - 80:80 + - 443:443 + restart: always + volumes: + - ./docker/nginx:/etc/nginx/conf.d/:ro + - ./docker/certbot/www:/var/www/certbot/:ro + - ./docker/certbot/conf:/etc/letsencrypt + + certbot: + image: certbot/certbot + container_name: skreept_certbot + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" + volumes: + - ./docker/certbot/conf:/etc/letsencrypt + - ./docker/certbot/www:/var/www/certbot diff --git a/examples/with-certbot/dolibarr-with-certbot.md b/examples/with-certbot/dolibarr-with-certbot.md new file mode 100644 index 0000000..b0bd5c4 --- /dev/null +++ b/examples/with-certbot/dolibarr-with-certbot.md @@ -0,0 +1,31 @@ +#Dolibarr with Nginx https as proxy pass using certbot +The purpose is to add an nginx container and a certbot container to auto generate SSL certificates + +###containers + +- 1 container for Dolibarr original image running on apache 2 port 8181 +- 1 container for DB (mysql8 here) +- 1 container for Certbot +- 1 container for Nginx proxy pass and certificates regeneration, forwad port 443 using certificate to 8181 dolibarr + +Bonus, in this example docker will auto check and regenerate certificates (entrypoint command in certbot) + + +![https.png](https.png) + +###Steps + +1. Edit `.env` file +2. Edit `.init-letsencrypt.sh` file line 8 and 11 replace example.com. +3. Edit `nginx/nginx.conf` and replace example.com +4. Exec `docker-compose up --build` +5. Exec `sudo ./init-letsencrypt` +6. Enjoy + +###Troubleshoot + +If the certbot certificate fail the challenge, comment line 17 to 29 in `nginx.conf` then redo operation 3 and 4. Then restore `nginx.conf` and restart docker `docker-compose down && docker-compose up -d` + +###Credits + +Based on medium article by Philipp https://pentacent.medium.com/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71 diff --git a/examples/with-certbot/https.png b/examples/with-certbot/https.png new file mode 100644 index 0000000000000000000000000000000000000000..4f843ced79c2bccf2cacc7b159be48a77a8348ac GIT binary patch literal 25338 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

W&N! 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 literal 0 HcmV?d00001 diff --git a/examples/with-certbot/init-letsencrypt.sh b/examples/with-certbot/init-letsencrypt.sh new file mode 100644 index 0000000..2d1718d --- /dev/null +++ b/examples/with-certbot/init-letsencrypt.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +if ! [ -x "$(command -v docker-compose)" ]; then + echo 'Error: docker-compose is not installed.' >&2 + exit 1 +fi + +domains=(example.com) +rsa_key_size=4096 +data_path="./docker/certbot" +email="contact@example.com" # Adding a valid address is strongly recommended +staging=1 # Set to 1 if you're testing your setup to avoid hitting request limits + +if [ -d "$data_path" ]; then + read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision + if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then + exit + fi +fi + + +if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then + echo "### Downloading recommended TLS parameters ..." + mkdir -p "$data_path/conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf" + curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem" + echo +fi + +echo "### Creating dummy certificate for $domains ..." +path="/etc/letsencrypt/live/$domains" +mkdir -p "$data_path/conf/live/$domains" +docker-compose run --rm --entrypoint "\ + openssl req -x509 -nodes -newkey rsa:1024 -days 1\ + -keyout '$path/privkey.pem' \ + -out '$path/fullchain.pem' \ + -subj '/CN=localhost'" certbot +echo + + +echo "### Starting nginx ..." +docker-compose up --force-recreate -d nginx +echo + +echo "### Deleting dummy certificate for $domains ..." +docker-compose run --rm --entrypoint "\ + rm -Rf /etc/letsencrypt/live/$domains && \ + rm -Rf /etc/letsencrypt/archive/$domains && \ + rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot +echo + + +echo "### Requesting Let's Encrypt certificate for $domains ..." +#Join $domains to -d args +domain_args="" +for domain in "${domains[@]}"; do + domain_args="$domain_args -d $domain" +done + +# Select appropriate email arg +case "$email" in + "") email_arg="--register-unsafely-without-email" ;; + *) email_arg="--email $email" ;; +esac + +# Enable staging mode if needed +if [ $staging != "0" ]; then staging_arg="--staging"; fi + +docker-compose run --rm --entrypoint "\ + certbot certonly --webroot -w /var/www/certbot \ + $staging_arg \ + $email_arg \ + $domain_args \ + --rsa-key-size $rsa_key_size \ + --agree-tos \ + --force-renewal" certbot +echo + +echo "### Reloading nginx ..." +docker-compose exec nginx nginx -s reload diff --git a/examples/with-certbot/nginx/nginx.conf b/examples/with-certbot/nginx/nginx.conf new file mode 100644 index 0000000..1bfd959 --- /dev/null +++ b/examples/with-certbot/nginx/nginx.conf @@ -0,0 +1,29 @@ +server { + listen 80; + listen [::]:80; + + server_name example.com www.example.com; + server_tokens off; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://example.com$request_uri; + } +} + +server { + root /srv/api/public; + + listen 443 ssl http2; + server_name www.example.com; + + ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + + location / { + proxy_pass http://example.com:8181; + } +}