docker-library / wordpress

Docker Official Image packaging for WordPress
https://wordpress.org/
GNU General Public License v2.0
1.77k stars 1.07k forks source link

Loopback request and REST API fail in Site Health Status when using a reverse proxy or different port #493

Closed ghost closed 4 years ago

ghost commented 4 years ago

I use WordPress (fpm-alpine) together with Nginx in the backend with HTTP on port 80. In front of that I have the caddy reverse proxy running, although this applies to any other reverse proxy.

                             +------------------+         +------------------+
                             |      caddy       |         |       nginx      |
https://example.org +-------->                  +-------->+                  |
                             |  172.18.0.2:443  |         |   172.18.0.3:80  |
                             +------------------+         +------------------+

The installation of WordPress and plugins works fine, but the Site Health Status (/wp-admin/site-health.php) shows that the Loopback request and REST API fail with following error: Error: cURL error 28: Failed to connect to example.org port 443: Operation timed out (http_request_failed)

This can be partially fixed by redirecting the domain of the site (example.org) to the IP of the reverse proxy (172.18.0.2) using extra_hosts to docker-compose.yml:

    extra_hosts:
      - "example.org:172.18.0.2"
      - "example.org:fd00::2"

Then cURL tries to connect to the correct domain but still fails: Error: cURL error 28: Operation timed out after 10001 milliseconds with 0 bytes received (http_request_failed)

There is a tedious workaround which you can try to prevent these errors to occur. By changing the Nginx backend port to the same which port is used by the visitors domains (example.org), which in this case is the default HTTPS port 443. To do that I had to create a self-signed certificate and change some settings related to SSL in the backend Nginx server. After doing there were no errors. But as I've said, this is a workaround and not a fix. The error itself is not related to SSL, but rather to the port that is used.

docker-compose.yml:

version: '3.8'

services:
  caddy:
    image: caddy/caddy:alpine
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./caddy/data:/data

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx:/etc/nginx
      - ./www:/var/www/html

  wordpress:
    image: wordpress:fpm-alpine
    env_file: .env
    volumes:
      - ./www:/var/www/html
    extra_hosts:
      - "example.org:172.18.0.2"
      - "example.org:fd00::2"

  mariadb:
    image: mariadb:latest
    env_file: .env
    volumes:
      - ./mariadb:/var/lib/mysql

nginx.conf:

user nginx;
worker_processes auto;
pid /var/run/nginx.pid;

events {
  worker_connections 1024;
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  charset UTF-8;
  sendfile on;

  set_real_ip_from caddy;
  real_ip_header X-Forwarded-For;

  server {
    listen 80;
    listen [::]:80;
    server_name _;
    root /var/www/html;
    index index.php;

    location / {
      try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
      include fastcgi.conf;
      fastcgi_pass wordpress:9000;
    }
  }
}

I have also tested this using plain HTTP locally without a reverse proxy. When using Docker port 80 and Nginx port 80 everything works. But when binding any port with Docker that Nginx doesn't use, the same error happens. Here is a docker-compose.yml configuration which causes the same error to occur:

docker-compose.yml:

...
  nginx:
    image: nginx:alpine
    ports:
      - 127.0.0.1:8080:80
...
tianon commented 4 years ago

This seems like a very complicated way to deploy -- is there a particular reason you're using two separate reverse proxies instead of just one? (Either of Caddy or NGINX should be able to do what you need without the other.)

I'd also suggest trying the Docker Community Forums, the Docker Community Slack, or Stack Overflow -- the issues here aren't intended to be a dedicated support forum, and I really don't see what we could change in the WordPress image to alleviate the issue you're seeing (I think it's likely related to the complexity of your container networking topology).

ghost commented 4 years ago

I use multiple reverse proxies because it makes it easier to deploy multiple services. I think my issue is still relevant as it not only applies to reverse proxies with different backend ports, but also when simply running a webserver such as Nginx with a different port number (see the last section of my issue). It should be possible to run WordPress on a different port with Nginx or other webservers.

yosifkit commented 4 years ago

I think this is outside the scope of the wordpress image. These issues are meant to cover bugs with the Docker image and not a generic support forum.

This issue is about configuring WordPress to work correctly behind multiple proxies. So I think you'd probably need the equivalent of some of these? Or try asking on the WordPress Support pages (or links @tianon gave above)?


As for the port changing 127.0.0.1:8080:80 that is very similar to running WordPress behind an ssl terminating reverse proxy, so I would guess that WordPress needs to be informed what the site url is including port (and X-Forwarded-Proto when changing from ssl to non-ssl);

ghost commented 4 years ago

I take back what I said, my problems were caused by a faulty plugin I had installed. Thanks for the help nevertheless.

adkondr commented 3 years ago

Tell me, what solution is working now?

scyto commented 2 years ago

This is great solution even in a single proxy solution and for other issues!

I run split brain DNS so mydomain.com inside my network and mydomain.com outside my network resolve to different IPs For the loop back to work (and to enable me to finish my site upgrade) adding mydomain.com and external IP using this method was simple, quick and easy. Thanks

warioishere commented 1 year ago

im having the same problem here, unable to solve it @scyto would u like to share what u did exactly? Runing my own dns server inside my network, should i set the IP to my external IP on my domain? or what exactly did u do?

wajdijurry commented 1 year ago

I have the same problem. Any one was able to resolve it ?

warioishere commented 1 year ago

I have the same problem. Any one was able to resolve it ?

Are you running your worpress behind a Reverse proxy and your firewall is port fowarding to your Proxy? What firewall do you use? On my pfsense i had to enable NAT Reflection so Servers can make internal loop requests.

See https://docs.netgate.com/pfsense/en/latest/recipes/port-forwards-from-local-networks.html

It made it work. If it doesnt work, create a New 443vhost on your webhost with a certificate and let it point to your wordpress domain.

Tell me if u had success.

Cheers

visionm45 commented 1 year ago

not sure if this could help in this specific situation but I have had the a similar issue and I was not able to continue until I found a solution. My issue was caused by mapping the container's port to 8080. What I did was edit the apache server config files to match the port that was set for the container.

In /etc/apache2/sites-enabled/000-default.conf I added :8080 to the first line <VirtualHost :80 *:8080>

then in /etc/apache2/ports.conf just below Listen 80

I added the line Listen 8080

then after running apachectl restart

everything now works as expected

pal03377 commented 1 month ago

Just adding this in case someone will have a similar problem:

In my case the problem was that I gave my Docker container a hostname with the same name as the domain. So I had a domain example.com and in my Docker compose file, I had this setting:

services:
  wordpress:
    hostname: example.com
    ...

Of course, this does not work because then the Docker container will resolve example.com to itself directly (because it's its own hostname after all), which will break if you use another port or if you're using a reverse proxy for an https-connection.

My solution was simply to remove the hostname configuration, as I did not need it.