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.

Check if TCP forwarding in sshd_config is enabled (Server)

One thing that a reader reported in, was that without AllowTCPForwarding enabled in the sshd_config file, the connection will not establish. You may also enable AllowAgentForwarding as well, if it still is not working.

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 serveruser@localhost -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):

fox@floof:~$ 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!

🦊

10 Replies to “Nextcloud + reverse proxy with autossh”

  1. Thanks was really great and helpful, in the article do not mention but for somebody else could save hours as tip check first if ssh_ AllowAgentForwarding and AllowTcpForwarding yes, the ssh server has mark it No by default.

    1. Hi Rodrigo!

      I appreciate your feedback, I value that a lot!

      I will make sure to update my guide to reflect this, you are 100% correct. I, myself, did not notice this going through this when I wrote this article, but that may be due to my setup was not entirely fresh 🙂

      I hope everything worked out for you.
      den

  2. I am able to ssh to my VPS and then from VPS back to server using the reverse proxy. However, when I try to ssh into my VPS from my laptop on the desired port, I am getting a connection refused error. I made sure to adjust the config to allow Tcp forwarding and agent but still no success… I also allowed the desired port I’m using on my VPS providers security center.

    1. Do I need to adjust the ssh config on both the vps and server?
    2. Do I need to open the port I am using on my server? I figured this is a no since it’s tunneling to port 22 which is already open for ssh

    Thanks for any advice!

    1. Hi Adam!

      Thanks for your comment!
      Looking at what you wrote, I will do a few assumptions in my reply, perhaps worth checking.

      I understand the following;
      1. You are able to connect to the VPS, creating an initial tunnel.
      2. You are able to connect back to the origin server, through the tunnel you have created.
      3. Then, if you are using your laptop to do the same, you are getting a connection refused error.

      In regards to this, my first assumption would be that you are not connecting to the right port/IP, or that your laptop is on a network/IP that is not allowed by the service you are connecting to (So, it basically closes connection). I would strongly recommend you to check your firewall settings on the VPS. Also test without creating the initial SSH tunnel, does it work from laptop then? Please note, you can not occupy a port with the reverse proxy and then use the same port again later. Only one port per tunnel 🙂

      If you are able, show some commands you are trying, and tell a little step by step what you are doing in order to receive the issue.

      Question 1: Maybe – you need to adjust the settings as you mentioned; make sure TCP forwarding is enabled. Then restart the SSH service in order for it to take effect (on the Server). The VPS only needs to be accessible on a port with SSH. You should also check if GatewayPorts is enabled;
      You can enable this using the GatewayPorts directive in your SSHD main configuration file /etc/ssh/sshd_config on the remote host (VPS).

      Open the file for editing
      sudo nano /etc/ssh/sshd_config

      Look for the required directive, uncomment it, and set its value to yes:

      GatewayPorts yes

      Question 2:
      In order to make tunnels, you need to open new ports for every tunnel you make (aka, use one new port for every new service). I touch upon this in the end of the article 🙂

      I hope that helps. If not, revert back and I am happy to assist.

      1. SUCCESS!

        Thank you so much for the speedy reply! It seems the problem boiled down to the GatewayPorts yes not being enabled. Maybe add that to the list up top incase other viewers have the same issue. Now I’ll do some testing disabling and enabling the other configs on both the VPS and Server to see where it needs to be enabled and where it can be left to its defaults. Now I can continue on with the rest of the article!

        I successfully implemented a NextCloud instance on my home server before and used ngrok to tunnel the ports. However, I found your article and realized paying for my own VPS is a better value than paying for ngrok (if you want custom domain). Not to mention it’s a lot more fun!

        P.S., my setup is behind a CGNAT which is why I need this for porting into my home server running on a VM.

        Thanks Again. I might be back with more questions…

        1. Fantastic news, thanks for updating on the progress!
          I will add that as a thing to enable in the guide so others do not have the same problem as you.

  3. Thanks a lot for this solution.
    It works with a LetsEncrypt certificate. I combined these manuals:
    https://floof.cc/2020/01/05/nextcloud-reverse-proxy-with-autossh/
    https://bayton.org/docs/nextcloud/installing-nextcloud-on-ubuntu-16-04-lts-with-redis-apcu-ssl-apache/
    https://websiteforstudents.com/setup-lets-encrypt-wildcard-on-ubuntu-20-04-18-04
    – apt install libmagickcore-6.q16-6-extra (solves the imagick error)

    My problem is, Caldav isn’t working.
    Added the redirects to the 000-default.conf

    Redirect 301 /.well-known/carddav https://MYSERVER/remote.php/dav
    Redirect 301 /.well-known/caldav https://MYSERVER/remote.php/dav
    Redirect 301 /.well-known/webfinger https://MYSERVER/index.php/.w&gt;
    Redirect 301 /.well-known/nodeinfo https://MYSERVER/index.php/.we&gt;

    and the errors in nextcloud are gone but MacOS gives an error: Unable to verify account name or password.
    I think it’s the ssl connection. Any Idea?

    1. Hello there!

      I am not sure what could be the reason behind this. I cant remember messing around with the redirects to get caldav working, so that could potentially be the requests that come in are redirected with the correct payload (auth).
      have you tried manually hitting those and see if you get any weird behaviour?

      1. On the iphone CalDav works.
        Restarted the mac and now everything works.
        Thanks for your good explanation. Now I have a full nextcloud server with LetsEncrypt behind a reversed proxy.

  4. Does this also work for you when downloading large files? I have the problem that the download stops relatively often when it goes through the SSH tunnel. If I do the same download without the tunnel, the problem does not occur.

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.