Passa al contenuto principale

Reverse Proxy

1. Run both nginx and apache2

Is it possible to run both of them?

1.1 Try to start apache2

systemctl status nginx
systemctl status apache2

systemctl unmask apache2
systemctl start apache2
journalctl -xeu apache2.service
systemctl status apache2
systemctl status apache2 --no-pager -l -o cat

This error message shows that the port 80 is already used by some other process:

(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80
lsof -i 4 -a -i :80

This confirms that the port 80 is being used by nginx.

So, apache2 and nginx cannot run at the same time, if they try to listen on the same ports (80 and 443).

1.2 Change the ports

Let's change the ports of apache2 and try to start it again:

  1. Change the port 80 to 8080 and the port 443 to 8443 at /etc/apache2/ports.conf:

    cd /etc/apache2/
    ls
    nano ports.conf
  2. Change the ports on virtual definitions too:

    cd sites-available/
    grep 80 -R .
    grep 443 -R .

    nano 000-default.conf
    nano default-ssl.conf
    nano wp1.conf
    nano wp2.conf
  3. Try to start again apache2

    systemctl start apache2
    systemctl status apache2
    systemctl enable apache2

1.3 Open the new ports on the firewall

firewall-cmd --list-all
firewall-cmd --permanent --zone=public --add-port=8080/tcp
firewall-cmd --permanent --zone=public --add-port=8443/tcp
firewall-cmd --reload
firewall-cmd --list-all

1.4 Test redirection

  1. Test it with curl -v like this:

    curl -v http://wp1.user1.fs.al:8080/

    This output line shows that we also need to fix the redirection target url:

    < Location: https://wp1.user1.fs.al/
  2. Edit sites-available/wp1.conf and append the port :8443 on the redirect line:

    Redirect / https://wp1.user1.fs.al:8443/

    Do the same for sites-available/wp2.conf.

  3. Reload apache2 config and test again:

    apachectl -t
    systemctl reload apache2
    curl -v http://wp1.user1.fs.al:8080/
    curl -v https://wp1.user1.fs.al:8443/

    Now we notice another problem:

    < X-Redirect-By: WordPress
    < Location: https://wp1.user1.fs.al/

    Due to its configuration, WordPress also is making a redirection, but to the wrong url https://wp1.user1.fs.al/ (without :8443).

  4. Fix WP configuration and try again:

    cd /var/www/wp1/
    wp option get siteurl
    wp option set siteurl https://wp1.user1.fs.al:8443
    wp option get siteurl
    wp option get home
    wp option set home https://wp1.user1.fs.al:8443
    wp option get home
    curl -v https://wp1.user1.fs.al:8443/

    Try in browser https://wp1.user1.fs.al:8443/

    Do the same thing for wp2.user1.fs.al:

    cd ../wp2/
    wp option set siteurl https://wp2.user1.fs.al:8443
    wp option set home https://wp2.user1.fs.al:8443
    wp option get siteurl
    wp option get home

2. Reverse Proxy

A url like https://wp1.user1.fs.al:8443 does not look nice and is less practical. We can setup nginx to accept requests for the virtual domain wp1.user1.fs.al (on the ports 80 and 443) and to forward those requests to apache2 (on the ports 8080 and 8443).

From the point of view of the client (browser) it is nginx that is responding, however the truth is that it is getting the response from apache2. It is standing between the client and the real webserver as a mediator. In this case it is acting as a Reverse Proxy.

note

Apache2 can also act as a reverse proxy, serving websites on behalf of other apache2 or nginx servers that are behind it. However we will try here only the case where nginx acts as a reverse proxy for some apache2 websites that are behind it.

2.1 Add virtual hosts to nginx

Let's add virtual host configurations to nginx for the domains wp1.user1.fs.al and wp2.user1.fs.al.

  1. Create the file /etc/nginx/sites-available/wp1 like this:

    cat <<'_EOF_' > /etc/nginx/sites-available/wp1
    server {
    listen 80;
    server_name wp1.user1.fs.al www.wp1.user1.fs.al;

    include snippets/letsencrypt.conf;
    location ^~ / {
    return 301 https://$host$request_uri;
    }
    }
    server {
    listen 443 ssl;
    server_name wp1.user1.fs.al www.wp1.user1.fs.al;

    ssl_certificate /etc/letsencrypt/live/wp1.user1.fs.al/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/wp1.user1.fs.al/privkey.pem;

    access_log /var/log/nginx/wp1-access.log;
    error_log /var/log/nginx/wp1-error.log error;

    location / {
    include proxy_params;
    proxy_pass https://wp1.user1.fs.al:8443;
    }
    }
    _EOF_
  2. Create the file /etc/nginx/sites-available/wp2 like this:

    cp /etc/nginx/sites-available/{wp1,wp2}
    sed -i /etc/nginx/sites-available/wp2 \
    -e 's/wp1/wp2/g'
    nano /etc/nginx/sites-available/wp2
    ls /etc/nginx/sites-available/
  3. Enable these two sites and reload nginx:

    ln -s ../sites-available/wp1 /etc/nginx/sites-enabled/wp1
    ln -s ../sites-available/wp2 /etc/nginx/sites-enabled/wp2
    ls -l sites-enabled/

    nginx -t
    systemctl reload nginx
  4. Make sure that /etc/hosts has these two lines:

    127.0.0.1  wp1.user1.fs.al
    127.0.0.1 wp2.user1.fs.al
    ping wp1.user1.fs.al
    ping wp2.user1.fs.al

2.2 Fix WP settings

If we try to open in browser https://wp1.user1.fs.al we will get the error message:

wp1.user1.fs.al redirected you too many times.

The problem is that the options siteurl and home of the WP site are not correct. Let's change them back to https://wp1.user1.fs.al:

wp option get siteurl
wp option get home

wp option set siteurl https://wp1.user1.fs.al
wp option set home https://wp1.user1.fs.al

wp option get siteurl
wp option get home

Do the same for the site https://wp2.user1.fs.al and try again to open them in browser. Now they should work.

2.3 Close the ports 8080 and 8443 on firewall

We don't need the ports 8080 and 8443 anymore. Let's close them:

firewall-cmd --list-all
firewall-cmd --permanent --zone=public --remove-port=8080/tcp
firewall-cmd --permanent --zone=public --remove-port=8443/tcp
firewall-cmd --reload
firewall-cmd --list-all

2.4 Set the real IP

Let's have a look at the logs of nginx and apache2.

  1. Split a tmux window horizontally (with C-b ") and show their logs in each of the panes:

    tail /var/log/nginx/wp1-access.log -f
    tail /var/log/apache2/wp1-access.log -f
  2. Open https://wp1.user1.fs.al in browser (or reload it).

Notice that the logs on nginx (which is the reverse proxy) report the real IP of the client, while the logs of apache2 (which is behind the proxy) report 127.0.0.1, that is the IP of the localhost.

This makes sense, because the request to apache2 is comming from the everse proxy (nginx).

Some applications don't care about the real IP of the client, but some of them may use it somehow. It is better to fix it, so that the webserver gets the real IP of the client, although it is behind the reverse proxy. It can be done like this:

  1. First, the reverse proxy should be configured to send to the backend server the real IP of the client on a special header, named for example X-Forwarded-For.

    Actually, our nginx proxy is already configured to do this. If we check the config file /etc/nginx/proxy_params (which is included on the virtual domains before the instruction proxy_pass), we will notice this line:

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  2. The backend webserver must be configured to use this header for getting the real IP of the client.

    Webservers don’t do this by default for security reasons (HTTP headers can be spoofed easily). That’s why we also have to tell apache2 the IP of the reverse proxy, so that it can trust the header X-Forwarded-For that comes from it.

    • Create the config file remoteip.conf:

      cat <<EOF > /etc/apache2/conf-available/remoteip.conf
      RemoteIPHeader X-Forwarded-For
      RemoteIPTrustedProxy 127.0.0.1
      EOF
    • Enable it:

      a2enconf remoteip
      ls -l /etc/apache2/conf-enabled/
    • We also need to enable the apache2 module remoteip:

      a2enmod remoteip
      ls -l /etc/apache2/mods-enabled/
    • Restart apache2:

      systemctl restart apache2

Reload the website on the browser and check the logs again. We should see that apache2 is now logging the real IP of the client.