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:
-
Change the port
80
to8080
and the port443
to8443
at/etc/apache2/ports.conf
:cd /etc/apache2/
ls
nano ports.conf -
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 -
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
-
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/
-
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
. -
Reload
apache2
config and test again:apachectl -t
systemctl reload apache2curl -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
). -
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.
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
.
-
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_ -
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/ -
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 -
Make sure that
/etc/hosts
has these two lines:127.0.0.1 wp1.user1.fs.al
127.0.0.1 wp2.user1.fs.alping 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
.
-
Split a
tmux
window horizontally (withC-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 -
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:
-
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 instructionproxy_pass
), we will notice this line:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
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 headerX-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.