Docker compose: nginx and wordpress behind Cloudflare — HTTPS to HTTP proxying problem
Faced an unusual issue — docker wordpress image fails to work with Cloudflare out of the box.
The problem is that I originally had Flexible proxying configured instead of Full (strict) on Cloudflare. In this case, the request goes to Cloudflare via HTTPS, but from Cloudflare to server via HTTP.
As a result, I decided not to change docker-compose-yml with additional custom image assemblies and just to connect certbot without installing it onto the docker host.
So the solution is to create two folders on the host machine /data/certbot/letsencrypt for certificates and /data/certbot/www to store acme challenges from letsencrypt. Then I’ve just mounted them on the Nginx host. Here is my nginx host config as is:
nginx:
image: nginx:1.21-alpine
restart: unless-stopped
volumes:
- /data/log/nginx:/var/log/nginx
- ./sites-enabled:/etc/nginx/sites-enabled
- ./nginx.conf:/etc/nginx/nginx.conf
- /data/certbot/letsencrypt:/etc/letsencrypt
- /data/certbot/www:/var/www/certbot
- ./127.ru:/var/www/127.ru # here goes wordpress
ports:
- 80:80
- 443:443
depends_on:
- mysql
- wordpress
In the nginx config at sites-enabled/127.ru
server {
listen 80;
server_name 127.ru;
index index.php;
root /var/www/127.ru;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
try_files $uri $uri/ /index.php;
}
location ~ ^/.+.php(/|$) {
try_files $uri =404;
include /etc/nginx/fastcgi.conf;
fastcgi_pass wp127ru:9000;
}
#listen 443 ssl;
#ssl_certificate /etc/letsencrypt/live/127.ru/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/127.ru/privkey.pem;
}
Turn off port 80 later - it is useless. The important line here is /.well-known/acme-challenge/ - at this path certbot will check the acme-challenge when generating an SSL certificate.
Then, from the host machine with Docker, we obtain the certificate to the mounted folders:
docker run --rm --name temp_certbot \
-v /data/certbot/letsencrypt:/etc/letsencrypt \
-v /data/certbot/www:/tmp/letsencrypt \
certbot/certbot \
certonly --webroot --agree-tos --renew-by-default \
--preferred-challenges http-01 --server https://acme-v02.api.letsencrypt.org/directory \
--text --email my@email.com \
-w /tmp/letsencrypt -d 127.ru
Now just remove port 80 in the nginx config (line «listen 80;») and uncomment the lines off SSL certs in the same place:
#listen 443 ssl;
#ssl_certificate /etc/letsencrypt/live/127.ru/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/127.ru/privkey.pem;
Next s witch Cloudflare to full proxying.
Now just restart nginx:
sudo docker exec -ti your-docker-host sh -c "nginx -s reload"