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:
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 switch Cloudflare to full proxying and just restart nginx:
sudo docker exec -ti your-docker-host sh -c "nginx -s reload"