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:

  image: nginx:1.21-alpine
  restart: unless-stopped
    - /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
    - ./ # here goes wordpress
    - 80:80
    - 443:443
    - mysql
    - wordpress

In the nginx config at sites-enabled/
server {
  listen 80;
  index index.php;
  root /var/www/;
  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/;
  #ssl_certificate_key /etc/letsencrypt/live/;

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 \
--text --email \
-w /tmp/letsencrypt -d

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/;
#ssl_certificate_key /etc/letsencrypt/live/;
Next switch Cloudflare to full proxying and just restart nginx:
sudo docker exec -ti your-docker-host sh -c "nginx -s reload"
Back to articles


Explore Aber Vulgue's blog for expert articles on programming, software development, and DevOps. Dive into practical guides on JavaScript, C++, mobile app development, neural networks, and more to enhance your tech skills.


Non penis canina est!