Nextcloud + reverse proxy with autossh

About 2 years ago, I moved to a new apartment. I decided I wanted to self-host my own cloud, my own website and some other websites. The only problem was, I couldn’t control the router/NAT I was behind. I could not access my server from the outside world. So I almost gave up, until I learned otherwise.


Disclaimer:

Before you continue:
I take no responsibility for wrongly configured services, exposed personal data or incorrect setup causing data-loss. I wrote this long document as a good deed, to help whoever who needed help to use reverse proxies for nextcloud. This is probably one of many ways of doing it, and this is how I use it myself.

I strongly recommend you go through the commands, the configuration and audit that there are no dangerous mistakes or changes happening. I have gone through this document twice already to ensure it is as good and correct as possible, testing and setting it up on two virtual machines.

Please help me fix mistakes and errors by reporting them to me in the comments below.
I am not a part of nextcloud staff and I do not have any relation to nextcloud, other than being a user of it myself.
I hope it helps! You may proceed.


Port forwarding using reverse ssh tunneling

Brief intro

For new users, this may scare you away. But, it is not too advanced, and can be understood if explained correctly. I will try my very best to explain how I understand it, and beware of mistakes and wrong terminology.
When you do port forwarding on your router, you basically tell the router to forward the incoming connection from 1: the router, to 2: the machine you want.

When this is not possible, you cannot connect to your server.
That is when SSH reverse tunneling will help you. This requires a VPS or a computer that is publicly accessible from the internet. NB: it needs a static IP!

Here is an easy example: 2: your server initiates a connection to a different computer 1: f.ex VPS. With this connection, it opens up a tunnel for you, with the port you define on both sides. With this you can connect to the server via the VPS with the ports you define and set up.

When this has been sat up, a user can connect to the VPS, and only see the VPS, while in the background there are proxies and operatios done towards your home server.

Reason this works, is because the connection is created from the server, and it doesn’t really matter if the server is on a phone network, behind 5 NATs or uses a satellite connection. It just needs internet. It will just use the connection it made to the VPS to send data back to the server. That is probably why it is called a reverse tunnel.
I have written the following guide with Linux in mind. If you use windows, or any other different operating system, the process or syntax might be different.

Test ssh reverse tunnelling

You can skip straight to setup if you don’t want to test. This section will greatly help you understand what you are doing, and make it easier to set up new connections later on in this guide.
Please note that I will use “server” as the home server you host nextcloud on, and “VPS” as the publicly accessible server we will proxy through.

Requirements on server:

  1. Make sure ssh client and ssh server is installed. We will need SSH.
  2. Ssh server is set up on standard port 22 (or any other port you want) *

Requirements on VPS:

  • It should be publicly accessible. In the document we will use IP: 150.1.1.1 – Please replace it with your IP/Domain…
  • make sure ssh-server is installed on it, so that we can log in with SSH remotely.
  • Ssh server is set up on standard port 22 (or any other port you want)

*we will use port 22 for ease in this setup.

On our server – Forward the ssh port

We will now try to forward port 22 from the server, to the VPS. This means, we should be able to access SSH on our server, via the VPS.

We will forward it to port 1300 on the VPS, since both servers use port 22.
The command we use then, is:

 ssh -R *:1300:localhost:22 [email protected] -p 22 

Explanation: Forward localhost port 22 to any network device on port 1300 on destination (which is [email protected]) The rest are standard SSH parameters.

Syntax: (use “man ssh” in terminal to get documentation)
ssh -R *:[port on VPS]:localhost:[port on server] [email protected] -p [ssh-port]

Please note that you can not forward to a port on the VPS, that the VPS already uses. Then you will have issues making it work. It will complain saying something like “Cannot bind to … – address already in use”.

We chose port 1300 because that is very unlikely to be used. For multiple webpages, you need to forward to different ports.

Looking at the VPS – Test the forwarded connection

Please let the ssh shell run from the previous section. It needs to run to keep the tunnel active.
Now, unless you got errors, you should be able to connect to your local server ssh from the VPS!
Test from your VPS:

ssh [email protected] -p 1300

it should log you in to your local server. If it works… Congratulations!

Now – get a laptop and try externally from a different network or from a phone, and you’ll see that this will work as well. Port 1300 on the vps is the same as port 22 on your server now. It just forwards it.
ssh [email protected] -p 1300

You may close the connections when you are done. The test is over.

Summary of the test

You did your first port forwarding over reverse ssh tunneling. You can with this access the server SSH from wherever you are in the world, as long as the tunnel is active.
Please be aware that exposing things publicly opens up for security concerns.
You can do this for all sorts of TCP connections. Minecraft servers, websites, ++. UDP is not supported by autossh.

This is a good read for later: https://medium.com/@jasonrigden/hardening-ssh-1bcb99cd4cef
I recommend to change the ssh ports and that you enforce ssh-keys instead of using passwords. Keep your data safe, and do measures against people trying to get access. After all, you are in control of your own data.


Setting up Nextcloud with reverse ssh tunnel

So I am writing this guide to help you set up Nextcloud to run behind a reverse proxy. Ask me in case something is unclear. I am running Linux myself, and I will base it of 18.04 which is identical to my local server version. It shouldn’t be too different on other versions after ubuntu 16.10.
Requirements:
1. Installed and sat up Nextcloud, and it is accessible over local network
2. SSH client and SSH server installed + configured.

Contents of this section:

  1. Install autossh on your server
  2. Create autossh user on server and VPS
  3. Make the autossh user a ssh key and use this when connecting to the VPS for password-less authentication.
  4. Test Autossh
  5. Configure Nextcloud to support reverse tunneling
    1. Trusted proxies
    2. HTTP header for origin IP
    3. Autossh as a system service
  6. Configure webserver ( apache2 ) on VPS to redirect to the tunnel

1. Install autossh

Autossh will let you run reverse tunnels, and it will make sure they stay online. Without it, a reverse tunnel may not be consistent at all. Autossh will restart the tunnel whenever it disconnects or loses connection.
On server:

sudo apt-get install autossh -y

2. Create autossh users on both sides

You should make a user on each side (VPS and server) that is responsible only for the connections in between them.
On server and vps, enter the following cmd and follow instructions:

sudo adduser autossh

Please set up secure passwords for them both. Except for once in this guide, you will likely never need the passwords again, as we will use SSH-keys to identify between the machines.
I recommend 12 characters or greater length. Write them down for now.

3. Generate keys and white-list

On server , use sudo -u and invoke the autossh user to generate new ssh keys:

sudo -u autossh ssh-keygen

Press enter until it has been generated. It should be created in

/home/autossh/.ssh/

Now that we have a ssh-key for the autossh user, we can go ahead and identify with this to the VPS, and whitelist the key for passwordless login. This is important for the automatic service we will set up later.
On server, connect to the vps SSH with “ssh-copy-id”

sudo -u autossh ssh-copy-id [email protected] -p 22

The command launches as “autossh” on the server (that is what “sudo -u” does btw),
and then it copies the ssh-public key to the VPS autossh user.
This will ask you for the autossh password on the VPS. When hit enter, it will connect, add the public key to the list, and then it will tell you to test the connection.

Now, you can test the connection and see if it requires a password or not. If it does not require a password, you are done – it should log you straight in. Remember to log in using autossh to autossh on the VPS:

sudo -u autossh ssh [email protected] -p 22

If this didn’t work out for you, you can check more info here: https://www.ssh.com/ssh/copy-id

4. Testing autossh for the first time

When you have installed autossh, you can quickly check if you have it installed correctly by running the following in your terminal:

autossh

It should give you a print of all the available functions of it (help page):

[email protected]:~$ autossh
usage: autossh [-V] [-M monitor_port[:echo_port]] [-f] [SSH_OPTIONS]

    -M specifies monitor port. Overrides the environment
       variable AUTOSSH_PORT. 0 turns monitoring loop off.
       Alternatively, a port for an echo service on the remote
       machine may be specified. (Normally port 7.)
    -f run in background (autossh handles this, and does not
       pass it to ssh.)
    -V print autossh version and exit.

Environment variables are:
    AUTOSSH_GATETIME    - how long must an ssh session be established
                          before we decide it really was established
                          (in seconds). Default is 30 seconds; use of -f
                          flag sets this to 0.
    AUTOSSH_LOGFILE     - file to log to (default is to use the syslog
                          facility)
    AUTOSSH_LOGLEVEL    - level of log verbosity
    AUTOSSH_MAXLIFETIME - set the maximum time to live (seconds)
    AUTOSSH_MAXSTART    - max times to restart (default is no limit)
    AUTOSSH_MESSAGE     - message to append to echo string (max 64 bytes)
    AUTOSSH_PATH        - path to ssh if not default
    AUTOSSH_PIDFILE     - write pid to this file
    AUTOSSH_POLL        - how often to check the connection (seconds)
    AUTOSSH_FIRST_POLL  - time before first connection check (seconds)
    AUTOSSH_PORT        - port to use for monitor connection
    AUTOSSH_DEBUG       - turn logging to maximum verbosity and log to
                          stderr

PS: I hope you did the test with reverse tunneling under “How to test it” on page 2 – it will make this test quite simple. Also make sure you close down the old connections, so that we don’t run into problems with conflicting ports here.

The syntax is almost the same, but it includes a few more options we should define. The following should work.
Please note, this has to be run as the autossh user, as autossh was set up with ssh-keys earlier.
On server:

sudo -u autossh  autossh -R *:1300:127.0.0.1:22 -N -o "ExitOnForwardFailure=yes" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" [email protected] -p 22 -v

Do you see the similarity with the test with only ssh?
Basically, syntax is like:
autossh -R [what ports to forward to what] [some settings] [ssh login information]

If it asks for a password, make sure you sat up the ssh-keys correctly. This is mandatory to have working. Leave a comment below if you need help.

I have added a “-v” on the end of the command above, and this is to be able to debug (“verbose”) and see that everything connects. This you don’t have to add normally, so only use it for now.

In your terminal, look for:

debug1: Authentication succeeded (publickey)
Authenticated to 150.1.1.1:22

That will give an indication that the SSH login with ssh-keys worked. Then, on the very bottom you should see:

debug1: All remote forwarding requests processed

Meaning the reverse proxy is operating normally!

While it is running, go ahead and try the same as last test. Connect to the server ssh via the VPS, which we just forwarded:

ssh [email protected] -p 1300

If that works, you know that the autossh you sat up is functioning, and we can move over to set up Nextcloud next.

5. Configuring Nextcloud for reverse proxy Prerequisites:

You can read the relevant reverse proxy documentation here: https://docs.nextcloud.com/server/17/admin_manual/configuration_server/reverse_proxy_configuration.html
I will go through the settings for the relevant case here and make sure you understand briefly what they do.

5.1. Define trusted proxies

A trusted proxy is a relay that Nextcloud can trust 100%. Relays that are not trusted, will cause limitations and issues. We want to define that the VPS we use as a relay, is a trusted origin for incoming connections.
Go into your nextcloud config file. Mine is at /var/www/nextcloud/config/config.php

Add the following to your config.php file:
'trusted_proxies'   => ['150.1.1.1'],
And add a trusted domain. Here, your domain name goes:

'trusted_domains' =>  
  array ( 
    0 => 'localhost', 
    1 => 'nextcloud.example.com', //replace with your domain 
),

Make sure you don’t define the same config in two places.
Now, save the file and exit.

If you use cloudflare, you will need to add these in addition (0 until 21)

'trusted_proxies' =>  
  array ( 
    0 => '10.42.0.0/16',  //start cloudflare IP’s
    1 => '103.21.244.0/22', 
    2 => '103.22.200.0/22', 
    3 => '103.31.4.0/22', 
    4 => '104.16.0.0/12', 
    5 => '108.162.192.0/18', 
    6 => '131.0.72.0/22', 
    7 => '141.101.64.0/18', 
    8 => '162.158.0.0/15', 
    9 => '172.64.0.0/13', 
    10 => '173.245.48.0/20', 
    11 => '188.114.96.0/20', 
    12 => '190.93.240.0/20', 
    13 => '197.234.240.0/22', 
    14 => '198.41.128.0/17', 
    15 => '2400:cb00::/32', 
    16 => '2606:4700::/32', 
    17 => '2803:f800::/32', 
    18 => '2405:b500::/32', 
    19 => '2405:8100::/32', 
    20 => '2c0f:f248::/32', 
    21 => '2a06:98c0::/29',   //end cloudflare IP’s
    22 => ‘150.1.1.1’,         //Your proxy here
 ),

Source: https://www.cloudflare.com/ips/

5.2. Define forwarded HTTP IP headers

This is probably a bit “uh why do we need this?” but it is in fact super important to avoid issues with logins and failed login attempts.
When you relay all your traffic from your VPS to your server – all the IP addresses that will appear only to be from the VPS. Because, in fact, all connections origin from there – right?
So then we need to tell Nextcloud how to read the origin IP from the client correctly. We can use a HTTP header for that. Add this to your config.php:
'forwarded_for_headers' => array('HTTP_X_FORWARDED_FOR'),

PS: If you use Cloudflare, you should use these instead:

In the end, it should look something like this (without cloudflare):

<?php 
$CONFIG = array ( 
 'instanceid' => 'removed', 
 'passwordsalt' => 'secret', 
 'secret' => 'removed', 
 'trusted_domains' =>  
 array ( 
   0 => 'localhost',
   1 =>  'nextcloud.example.com', //please use your domain if you have one
 ), 
 'trusted_proxies'   => ['150.1.1.1'], 
 'forwarded_for_headers' => array('HTTP_X_FORWARDED_FOR'), 
 'datadirectory' => '/var/www/nextcloud/data', 
 'dbtype' => 'mysql', 
 'version' => '17.0.2.1', 
 'overwrite.cli.url' => 'http://nextcloud.example.com',  //change to your domain
 'dbname' => 'temporary', 
 'dbhost' => '172.19.0.2', 
 'dbport' => '', 
 'dbtableprefix' => 'oc_', 
 'mysql.utf8mb4' => true, 
 'dbuser' => 'temporary', 
 'dbpassword' => 'temporary', 
 'installed' => true, 
);

5.3. Set up autossh in systemd for nextcloud

Let us set up autossh to forward nextcloud to our VPS. We will use systemd to make this load on every boot, and make sure it keeps running/restarts if it crashes.
Assumptions:
• Nextcloud is running on port 80 on local server.
• You run ubuntu 16.10

Head over to /etc/systemd/system/ on your server

Then do

sudo nano nextcloud-forward.service

this will create a new file and open it up in your nano editor.

Paste this in your terminal. Make sure that the ports, usernames and IP’s are correct. Let us use port 2600 on the VPS for this tutorial.

 [Unit]  
 Description=Keep a tunnel to vps open  
 After=network-online.target

[Service]  
 Type=simple 
 User=autossh 
 Restart=always 
 RestartSec=60 
 ExecStart=/usr/bin/autossh -R *:2600:127.0.0.1:80 -N -o "ExitOnForwardFailure=yes" -o "ServerAliveInterval 60" -o "ServerAliveCount Max 3" [email protected] -p 22

[Install]  
 WantedBy=multi-user.target

Press CTRL + O to save the file, hit enter. Press CTRL+X to exit the editor.
Register the service by typing:

 sudo systemctl daemon-reload

Then start the service, and enable it so it starts on boot:

sudo service nextcloud-forward start
sudo systemctl enable nextcloud-forward

You may want to check if it is “active (running)” by checking:

sudo service nextcloud-forward status
● autossh.service - Keep a tunnel to vps open 
  Loaded: loaded (/etc/systemd/system/nextcloud-forward.service; enabled; vendor preset: enabled) 
  Active: active (running) since Fri 2020-01-03 23:49:25 CET; 1 day 19h ago 
Main PID: 8285 (autossh) 
   Tasks: 2 (limit: 4915) 
  CGroup: /system.slice/nextcloud-forward.service 
          ├─8285 /usr/lib/autossh/autossh -R *:2600:127.0.0.1:80 -N -o ExitOnForwardFailure=yes -o ServerAliveInterval 60 -o Serve 
          └─8304 /usr/bin/ssh -L 563011:127.0.0.1:563012 -R 563012:127.0.0.1:563013 -R *:2600:127.0.0.1:80 -N -o ExitOnForwardFailure= 

Jan 03 23:49:25 big-cookie systemd[1]: Started Keep a tunnel to vps open. 
Jan 03 23:49:25 big-cookie autossh[8285]: starting ssh (count 1) 
Jan 03 23:49:25 big-cookie autossh[8285]: ssh child pid is 8304

If everything looks normal, you can now quickly test and see if you can access your nextcloud by going to your browser. In the address bar, this example would be http://150.1.1.1:2600 (or use your domain attached to the IP with port 2600).

You should now be seeing your login page. The nextcloud-forward service file you sat up is working, and will always be running with the system now.
But… I bet you don’t want to write :2600 every time you want to access nextcloud?
Let’s have a look at the VPS apache setup next.

6. Configure webserver ( apache2 ) on VPS to redirect to the tunnel

On the VPS we can now access nextcloud on port 2600, yay!

We are getting close to finishing the setup. What remains is to let users connect over the conventional port 80 (or port 443 if you run https).
So, you connect to port 80 (ex. http://nextcloud.example.com). We need to check if the user is connecting to nextcloud.example.com (your domain), and then forward this user to the correct place, which is our reverse tunnel to the server.
All this should be configured on the VPS, on the webserver, and not on the server where nextcloud is.

Following part is on the VPS:

Using apache2, I have sat up the following configuration.

<VirtualHost *:80> 
   ServerAdmin [email protected] 
   ServerName nextcloud.example.com
   ErrorLog "/var/log/apache2/nextcloud-error.log" 
   LogLevel warn 
   CustomLog ${APACHE_LOG_DIR}/nc-access.log combined 
   ProxyRequests Off 
   <Location /> 
        ProxyPreserveHost On 
        ProxyPass http://localhost:2600/ retry=1 acquire=3000 timeout=600 Keepalive=On 
        ProxyPassReverse http://localhost:2600/ 
   </Location> 
</VirtualHost>

Save this in /etc/apache2/sites-available/nextcloud-forward.conf

Make sure you replace the relevant information in this file.

To make apache use this config, run

sudo apache2 a2ensite nextcloud-forward

Set up an A record DNS that points to your VPS ip ( for eample 150.1.1.1) and name is nextcloud.yourdomain.com. You can now access nextcloud directly, without having to worry about the port.
You may need to enable the necessary proxy modules in order to make the config above work:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests

If you want to set up SSL on the webpage, which is very recommended, you need to set this up from the VPS. Things to note:
You need to set the overwrite URL setting in config.php on nextcloud to use https://…..
The connection between the server and VPS does not need to be https. It is secured properly by the ssh tunnel.
I recommend letsencrypt (certbot) for easy setup.

And that’s it for now!

Foxy

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.