We gave up on Pound Proxy and got some help from @fossxplorer to set up Nginx instead, to serve as a reverse proxy to our Apache hosts. We must say we’re impressed of the speed that Nginx provide. Even though there is only a few milliseconds difference in loading, it’s noticeable and it feels much smoother. With Nginx we can mix both port 80 and 443 on the same IP and use several hosts on the same port.
Check this if you want hands on support with setting up your own Proxy based on this guide.
Like we described in this post, we run several hosts on the same public IP, and we could only forward port 80 or 443 to one specific internal IP. So to solve this we needed a reverse proxy that can handle the traffic. This tutorial is based on Ubuntu Server 14.04.3 and will take you through the basic setup to be able to handle the limitations when you’re behind one router and have several hosts on the same port.
Let us help you install Nginx Reverse Proxy, check this out.
-
Install Nginx on a separate VM
We prefer to have it separate from the other VMs we run on our server, but you could just install Nginx on your current system next to your Apache install.
Before you can install Nginx you have to create a VM and install Ubuntu Server. VMware will recommend you to make it 20 GB, but it’s enough if you make it 4 GB as its only purpose is to act as a reverse proxy. Just make a clean install without LAMP. Once you finished the install you can begin with the Nginx installation.
$~: sudo apt-get update && sudo apt-get install nginx
If you want bleeding edge Nginx you should use this PPA and add it by typing
$~: apt-add-repository ppa:nginx/development
Please only add it if you want bleeding edge, not otherwise.
-
Forward ports in your router
Decide what internal IP you want to run Nginx Reverse Proxy on. If you want to run both HTTPS (SSL) and HTTP you have to open port 443 and 80 on the IP were you have your Nginx install. In our example we run the Nginx system on a separete VM with IP 192.168.1.200. In this guide we explain how to open ports.
-
Create your first virtual host (port 80)
$~: cd /etc/nginx/sites-available/
$~: sudo nano your-vhost1.conf
- Put this in the vhost. The bold values are the ones you change to suit your config.
server { # The IP that you forwarded in your router (nginx proxy) listen 192.168.1.200:80 default_server; # Make site accessible from http://localhost/ server_name domain1.se; # The internal IP of the VM that hosts your Apache config set $upstream 192.168.1.160; location / { proxy_pass_header Authorization; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_redirect off; } }
-
Create vhost2
$~: cd /etc/nginx/sites-available/
$~: sudo nano your-vhost2.conf
- Put this in your second vhost:
server { # The IP that you forwarded in your router (nginx proxy) listen 192.168.1.200:80; # this is not the default_server # Make site accessible from http://localhost/ server_name domain2.se; # The internal IP of the VM that host you Apache config set $upstream 192.168.1.150; location / { proxy_pass_header Authorization; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_redirect off; } }
If you want to have even more hosts on port 80, you just copy the vhosts to a new file and change the bold values.
$~: cp /path-to-working-vhost.conf /path-to-new-vhost.conf
-
Activate the vhosts by liknking them to ../sites-enabled/
$~: sudo ln -s /etc/nginx/sites-available/vhost.conf /etc/nginx/sites-enabled/vhost.conf
Now, repeat this step for every vhost you want to activate.
-
Restart Nginx
$~: sudo service nginx restart
Now the config for port 80 is done. Lets move over to the SSL config.
-
Create a vhost with SSL (port 443)
$~: cd /etc/nginx/sites-available/
$~: sudo nano your-vhost3.conf
Put this in your SSL config. The bold values are the ones you change to suit your config.
server { listen 192.168.1.200:443 ssl; # SSL config ssl on; ssl_certificate /etc/nginx/ssl/vhost3.pem; ssl_certificate_key /etc/nginx/ssl/vhost3.key; # Make site accessible from http://localhost/ server_name domain3.com www.domain3.se; set $upstream 192.168.1.170; location / { proxy_pass_header Authorization; proxy_pass https://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_redirect off; proxy_ssl_session_reuse off; } }
-
Put your cert files on the nginx system
$~: mkdir /etc/nginx/ssl
-
Move your SSL certs to that folder
The easiest way is to upload them to your ownCloud (assuming it’s on the same network) and copy them with SCP to your Nginx system. You could also use Webmin to upload them, or WinSCP.
Move the pem and the ssl key to your Nginx system from your ownCloud system:
scp -r /etc/ssl/ssl.pem* user@NGINX-IP:/tmp
scp -r /etc/ssl/ssl.key* user@NGINX-IP:/tmp
Move the files to the correct folder on your Nginx system:
mv /tmp/ssl.key /etc/nginx/ssl/vhost3.key
mv /tmp/ssl.pem /etc/nginx/ssl/vhost3.pem
-
Activate the SSL vhost
$~: sudo ln -s /etc/nginx/sites-available/vhost3.conf /etc/nginx/sites-enabled/vhost3.conf
-
Restart Nginx
Now the SSL setup is done and the only thing left to do is to restart Nginx and see the magic.
$~: sudo service nginx restart
Please contact us if you find any issues in this guide. Thank you.
Redirect traffic from port 80 to 443 (HTTP to HTTPS)
-
put this in your Nginx SSL conf:
server { listen 192.168.1.201:80; server_name example.techandme.se; return 301 https://example.techandme.se$request_uri; }
Change server_name to the domain that you use
-
Restart Nginx
-
Test that it works
root@NGNIX:/etc/nginx/sites-available# curl -I http://example.techandme.se HTTP/1.1 301 Moved Permanently Server: nginx/1.9.14 Date: Wed, 20 Apr 2016 08:28:28 GMT Content-Type: text/html Content-Length: 185 Connection: keep-alive Location: https://example.techandme.se/
Modifications in Apache 2.4
Apache can’t read the remote address unless you tell it to. You must take the following actions to make it work.
-
enable mod_remoteip
$~: a2enmod remoteip
-
Create remoteip.conf
$~: sudo nano /etc/apache2/conf-available/remoteip.conf
-
Add config to remoteip.conf:
RemoteIPHeader X-Forwarded-For RemoteIPTrustedProxy 192.168.1.200
-
Activate the new config
$~: a2enconf remoteip
$~: service apache2 restart
-
A modification is required in apache2.conf:
While the remote IP address is injected into PHP just fine, Apache2 continues to log 192.168.1.200 as the remote IP address in access.log. You have to change this:
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
To this:
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
%h has to be replaced with %a. We’re not sure if this is a bug or not but Apache2 will log the real remote IP address from now on.
If you use ownCloud
Add this to your config.php settings:
'trusted_proxies' => array(['192.168.1.200']), 'forwarded_for_headers' => array('HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR'),
In case someone tries to brute-force you and you want to see some more details in the output log entry, add this to /var/www/owncloud/remote.php where 162.158.94.254 is the IP that you want to check:
try { require_once 'lib/base.php'; // Debug failed login attempts: if(\OC::$server->getRequest()->getRemoteAddress() == "162.158.94.254") { \OC::$server->getLogger()->alert(json_encode(array($_REQUEST, $_SERVER, $_FILES, $_COOKIE)), ['app' => 'core']); } if (\OCP\Util::needUpgrade()) { // since the behavior of apps or remotes are unpredictable during // an upgrade, return a 503 directly throw new RemoteException('Service unavailable', OC_Response::STATUS_SERVICE_UNAVAILABLE); }