LetsEncrypt cert renewal script not working via docker compose - docker

I have a web site running SSL done using lets encrypt. I have written/used a script following this guide but the cert are not renewed automatically. Every 90 days I need to manually run the lets encrypt renewal command to get new certs for my website.
This is how my docker-compose looks like for nginx and certbot
nginx:
build: nginx-image
image: km-nginx
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- 80:80
- 443:443
depends_on:
- keycloak
- km-app
links:
- keycloak
- km-app
environment:
- PRODUCTION=true
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'"

Related

CERTBOT can't find config file in docker container

Two months ago, I set up a website with SSL thanks to Let's Encrypt. The details of how I did it are now quite blurry.
The site is hosted inside several docker containers (nginx, PHP, MySQL). There is a certbot container which should perform the renewal of the SSL certificate. This container is launched once a week and aborts immediately.
I have checked the logs and found this error. My research were unsuccessful and I have no idea what file certbot is complaining about.
usage:
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
it will attempt to use a webserver both for obtaining and installing the
certificate.
certbot: error: Unable to open config file: certonly -n --webroot --webroot-path=/var/lib/challenge --email contact#**********.com --agree-tos --no-eff-email -d www.**********.com --key-type ecdsa. Error: No such file or directory
Do you have any idea of the problem?
Thanks in advance,
EDIT:
The contents of /etc/letsencrypt are
accounts archive cli.ini csr keys live renewal renewal-hooks
Inside cli.ini, I have :
key-type = ecdsa
elliptic-curve = secp384r1
rsa-key-size = 4096
email = contact#attom.eu
authenticator = webroot
webroot-path = /var/lib/challenge
agree-tos = true
The docker-compose.yml contains :
version: '3'
services:
nginx:
build: ./nginx
container_name: nginx
restart: unless-stopped
depends_on:
- php
networks:
- app-network
volumes:
- {{ mounted_dir_app }}/public:/var/www/html:ro
- certbotdata:/etc/letsencrypt:ro
- challenge:/home/challenge
ports:
- "80:80"
- "443:443"
env_file:
- .env
- ".env.$ENV"
healthcheck:
test: curl -IsLk $$SITE_URL | head -n 1 | grep -q -e ^HTTP -e 200
start_period: 30s
interval: 10s
timeout: 3s
retries: 5
php:
#skip
mysql:
#skip
certbot:
depends_on:
nginx:
condition: service_healthy
build:
context: ./certbot
args:
- "ENV=$ENV"
container_name: certbot
env_file:
- .env
- ".env.$ENV"
volumes:
- certbotdata:/etc/letsencrypt
- challenge:/var/lib/challenge
networks:
app-network:
driver: bridge
volumes:
dbdata:
certbotdata:
challenge:
Edit:
The CERTBOT Dockerfile is
ARG ENV
FROM certbot/certbot as cert-prod
CMD certonly -n --webroot --webroot-path=/var/lib/challenge --email contact#**********.com --agree-tos --no-eff-email -d www.**********.com --key-type ecdsa
FROM alpine as cert-dev
RUN apk update && apk add openssl
CMD mkdir -p /etc/letsencrypt/live/www.**********.com && \
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-subj "/C=**/ST=**********/L=**********" \
-keyout /etc/letsencrypt/live/www.**********.com/privkey.pem -out /etc/letsencrypt/live/www.**********.com/fullchain.pem
FROM cert-${ENV}

map nginx conf within docker to correct location

I've been struggling to make changes to my docker app. After a lot of trial and error it looks what I thought was my nginx conf file might not actually be my nginx conf file.
I have determined this because I tried removing it entirely and my app runs the same with docker.
It looks like changes I make to my nginx service via the app.conf file have been having no impact on the rest of my app.
I am trying to understand if my volume mapping is correct. Here's my docker compose:
version: "3.5"
services:
collabora:
image: collabora/code
container_name: collabora
restart: always
cap_add:
- MKNOD
environment:
- "extra_params=--o:ssl.enable=false --o:ssl.termination=true"
- domain=mydomain\.com
- dictionaries=en_US
ports:
- "9980:9980"
volumes:
- ./appdata/collabora:/config
nginx:
image: nginx:1.15-alpine
restart: unless-stopped
depends_on:
- certbot
- collabora
volumes:
# - ./data/nginx:/etc/nginx/conf.d
- ./data/nginx:/etc/nginx
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- "80:80"
- "443:443"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
My projects directory is:
/my_project
docker-compose.yaml
data
nginx
app.conf
And then my app.conf has various nginx settings
server {
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://$host$request_uri;
}
} ... more settings below
Assuming I'm correct that my app.conf file is not being used, how can I correctly map app.conf on local to the correct place in the nginx container?
nginx conf directory is
/etc/nginx/nginx.conf
This File has an include of all of contento from
/etc/nginx/conf.d/*
You can verify your nginx.conf in use executing a ps -ef | grep nginx on your container.
Verify your default.conf. Anyway, in your compose you must have:
volumes:
- ./data/nginx:/etc/nginx/conf.d
Try with absolute path
Regards

Nginx container doesn’t copy files to my host

I am trying to copy a set of files (etc/nginx/*) from Nginx container to myhost (./nginx) but don't work.
Every time I run my docker-compose, the folder on the host (/ usr / development / nginx) is empty.
How can I do this?
Environment
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
Docker Compose
docker-compose version 1.25.5, build 8a1c60f6
Docker
Docker version 19.03.6, build 369ce74a3c
My docker-compose.yml
version: '3.7'
services:
nginx:
container_name: 'nginx'
hostname: nginx
image: nginx
ports:
- "80:80"
- "443:443"
restart: unless-stopped
command: /bin/sh -c "while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g 'daemon off;'"
volumes:
- ./nginx:/etc/nginx
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
networks:
- docker-network
portainer:
image: portainer/portainer
container_name: portainer
hostname: portainer
ports:
- 9000:9000
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./portainer/data:/data
networks:
- docker-network
certbot:
container_name: 'certbot'
hostname: certbot
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
restart: unless-stopped
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;"
depends_on:
- nginx
networks:
- docker-network
networks:
docker-network:
name: docker-network
driver: bridge

Should Nginx and Flask run in the same container

The ideal is to have one process per container, but there is a strong affinity between Flask+uwsgi and Nginx.
Currently we run them together, but should we refactor ?
Yes, it's a good idea to refactor. Try to make service ephemeral and run only one main process in it. So, in the end, you need to have something like this:
version: '3.4'
services:
web:
build:
dockerfile: Dockerfile
context: .
ports:
- 8000:8000
volumes:
- .:/app/
env_file:
- common.env
nginx:
restart: always
image: nginx:1.18-alpine
ports:
- 80:80
- 443:443
volumes:
- ./deployment/nginx.conf:/etc/nginx/conf.d/default.conf
- ./deployment/config.conf:/etc/nginx/nginx.conf
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\";'"
depends_on:
- web
It's designed to have only one main process in a container, in that case if your application fails the container will be down.

Update. LetsEncrypt certificates in two different docker containers

I have few containers, which supports HTTPS connections:
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
# Update certificates every 12 hours.
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
It mounts LetsEncrypt certificates and updates it every 12 hours.
Also, I have two additional containers:
nginx:
restart: always
build: ./nginx
ports:
- "80:80"
- "443:443"
volumes:
- db-data:/var/lib/postgresql
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/app.conf:/etc/nginx/conf.d/app.conf:ro
- frontend-webroot:/var/www/app.com/public_html/:ro
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- api
- frontend
# Reloads nginx every 6 hours to make it sure everything is OK.
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
Which mounts certificates and reloads nginx one per 6 hours (as it's recommended)
and another container:
api:
container_name: api
restart: always
build: ./web
ports:
- "9002:9002"
volumes:
- /usr/src/app/app/static
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- postgres
This container provided REST API and I'm not sure, it's a great idea to reload this container every X hours to update LetsEncrypt certificates.
What is wrong in this architecture? And how it might be improved to avoid reloading of container with REST API, but to make it possible to work with certificates?
UPDATE
What I expect from my app:
There should be available as home pages, etc. as API calls like:
GET https://localhost:9000/api/endpoint # API call
GET https://localhost:443/home # Home page from another container with React app
etc.

Resources