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.

Here is a script that is based on this post. Try it out. :)

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.

  1. 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.

  2. 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.

  3. Create your first virtual host (port 80)
    $~: cd /etc/nginx/sites-available/
    $~: sudo nano your-vhost1.conf
  4. 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;
    
     }
    }
  5. Create vhost2
    $~: cd /etc/nginx/sites-available/
    $~: sudo nano your-vhost2.conf
  6. 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
  7. 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.

  8. Restart Nginx
    $~: sudo service nginx restart

    Now the config for port 80 is done. Lets move over to the SSL config.

  9. 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;
    
     }
    }
  10. Put your cert files on the nginx system
    $~: mkdir /etc/nginx/ssl
  11. 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* [email protected]:/tmp
    scp -r /etc/ssl/ssl.key* [email protected]:/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
  12. Activate the SSL vhost
    $~: sudo ln -s /etc/nginx/sites-available/vhost3.conf /etc/nginx/sites-enabled/vhost3.conf
  13. 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)

  1. 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

  2. Restart Nginx
  3. Test that it works
    [email protected]:/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.

  1. enable mod_remoteip
    $~: a2enmod remoteip
  2. Create remoteip.conf
    $~: sudo nano /etc/apache2/conf-available/remoteip.conf
  3. Add config to remoteip.conf:
    RemoteIPHeader X-Forwarded-For
    RemoteIPTrustedProxy 192.168.1.200
  4. Activate the new config
    $~: a2enconf remoteip
    $~: service apache2 restart
  5. 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);
 }


 Pro tip

Redirect HTTP to HTTPS with a .htaccess file