How to set up and configure your own personal Nextcloud server
January 11, 2025
In this tutorial, I am going to walk you through how to configure your own personal Nextcloud server, starting from installing Ubuntu server all the way through configuring your router's DNS settings to allow for access to your data from any device, anywhere.
Requirements:
- Linux-compatible device (Raspberry Pi, old laptop, etc.)
 - USB Flashdrive with >8GB capacity
 - Active ethernet port
 - Monitor and keyboard for one-time server setup
 - Access to your router (for configuring ports and request routing)
 - Access to a domain name with configurable DNS settings (Cloudflare is an inexpensive but reliable option)
 
Step 1: Server installation and configuration
The first step in getting your own Nextcloud server up and running is to install your server OS of choice on whichever system you are planning to use. I opted to use Ubuntu Server 24.04.1 LTS, as this has several years of guaranteed support from Canonical and using Ubuntu gives us native support for the Nextcloud snap, which greatly simplifies the process of setting up Nextcloud.
Install Ubuntu Server ISO
The ISO file for Ubuntu Server 24.04.1 LTS can be downloaded from Canonical's website. If you are going to run your server on a Raspberry Pi, you will need to make sure you get the ARM-based installer found here. There are many ways to write this ISO to your flashdrive -- I use Fedora Media Writer, but you can also use Rufus, or the Raspberry Pi Imager if you are going to be running your server off of a Pi.
Most of the OS install is fairly straightforward, you just need to pay attention at the stage when you are partitioning your storage drives and remember to expand the LVM group to the full size of the disk. You can read about this on Canonical's Ubuntu Server install page.
            As you are installing the OS, you will also be presented with the option to import ssh keys with GitHub or 
            Launchpad, which allows the OS to be installed with password authentication disabled (which we will want 
            to do as soon as possible, for security reasons). It's recommended that you do this, because if you don't
            cloud-init will override your PasswordAuthentication setting for sshd and you will have to 
            manually correct its override.
        
The final piece of server configuration is to find out what the local IP address is of the server such that we can access it from other devices on the network, as well as assign it a static IP address from the router when we are port forwarding. To find the IP address, you will use
            $ ifconfig
        
        
        
            The output from ifconfig should contain an entry beginning with enp***, indicating the active 
            ethernet connection. In this entry, you should see an IP address labeled inet in the form 
            192.168.*.*, referring to the local IPv4 address of your server. Make note of this IP address 
            for later.
        
            Once you have completed this initial configuration, you will need a system restart with sudo 
            reboot. After you have done this, you can unplug any peripherals from your system as the remainder 
            of the server setup can be done from another machine on your local network (via ssh).
        
Configure access permissions and local firewall
After the initial setup of the server with a username, hostname and password, you should be able to connect to it via ssh from another device on your network. Ideally, you would have imported the ssh keys such that no password is required to connect. If you didn't do this, though, it's alright! We'll tackle that now. Because password authentication is generally less secure than ssh, the very first thing we are going to do is generate an ssh key on your device and copy it to the server.
            If you didn't copy your ssh keys from GitHub or Launchpad, we will need to use ssh-copy-id to 
            do it. If you haven't already generated an ssh key on your system, you can run the following command to do so:
        
            $ ssh-keygen -t rsa -b 4096
        
        This command generates a 4096-bit ssh key with RSA encryption. You can read more about this command from the ssh academy page.
            If you had previously generated an ssh key, you would see it in ~/.ssh/id_rsa.pub
        
            Next, we use ssh-copy-id to send the key to our server. This will require you to connect with 
            the same username and password that you configured as the administrative account on the server.
        
            $ ssh-copy-id user@hostname
        
        
            This will create an authorized_keys file in the ~/.ssh/ directory on the server, 
            making the connection from your system to the server. If your system username matches the one configured 
            as admin on the server, you can omit the user@ portion of the command
        
            Once we have done this, we need to disable password authentication. Head to 
            /etc/ssh/sshd_config in your editor of choice (and sudo) and look for 
            PasswordAuthentication. Change this from yes to no.
        
            It is possible that there are other files which are trying to overwrite your sshd_config file. 
            Specifically, check that /etc/ssh/sshd_config.d/* doesn't have password authentication enabled. 
            If it does, make sure to set this value to no as well. If you didn't pre-populate an ssh key with GitHub or 
            Launchpad, cloud-init tends to add an override here to allow password authentication so you 
            have some way to access the server remotely. Since you've now added an ssh key to this server, you want to 
            remove this password access override.
        
From this point onward, all configuration will be happening on the server (via ssh), *not* on your personal device (unless otherwise specified).
Step 2: Firewall configuration and initial Nextcloud setup
Configuring firewall rules with ufw
            ufw (uncomplicated firewall) is a popular program which allows the user to manage which ports 
            on their machine are accessible to other devices on their network. Because Nextcloud operates over the 
            internet (and utilizes a web interface), it will need access to the http and https ports (80 and 443). 
            Additionally, since we want our server to be accessible from other devices on the local network and enabling
            ufw would protect all unspecified ports, we also need to allow connections via ssh (port 22) 
            such that we don't kick ourselves off of the server unintentionally.
        
            ufw is installed (but inactive) by default on Ubuntu, and you can check your status with:
        
            $ sudo ufw status
        
        
            Once you have verified that ufw is installed, we will add the rules to allow ssh, http and https:
        
            $ sudo ufw allow ssh 
            $ sudo ufw allow http 
            $ sudo ufw allow https
        
        Once we have configured the firewall, we need to enable it and ensure that it is working properly:
            $ sudo ufw enable 
            $ sudo ufw reload 
            $ sudo ufw status
        
        You should then see an output indicating that your firewall is active and ports 22, 80, and 443 are open.
Initializing Nextcloud admin account
We will be installing the Nextcloud snap, as it is well supported on Ubuntu and contains useful features for generating and restoring server backups.
First we install the Nextcloud snap with
            $ sudo snap install nextcloud
        
        
            Next, we need to initialize an admin account for Nextcloud using the IP address of the server that we took 
            note of in step 1 (192.168.*.*). On your non-server system, type the local IP address of the 
            server into your web browser and you should see a Nextcloud login page. This is because Nextcloud is 
            listening on ports 80 and 443 by default, and accessing it over the web (even just over the local network) 
            creates a connection with http (or https, if there are ssl certificates). The username and password that you
            enter here will be the administrator of the server.
        
            We do this now before we port forward for security reasons. If we port forward first, there is the chance 
            that an outside user could create an admin account before us on the server. Additionally, once we configure 
            nginx with a reverse proxy it will only handle client requests properly if accessed via the full web domain 
            (cloud.domainname.com), not from a local IP address. We will talk more about how nginx works in 
            step 3.
        
Modifying Nextcloud server configuration
Once we have created our Nextcloud admin account by accessing the local IP address of the server, we need to change the http and https ports Nextcloud listens on since nginx itself listens on ports 80 and 443.
            $ sudo snap set nextcloud ports.http=81 ports.https=444
        
        
            It is important that you update the list of trusted domains from which you are going to access Nextcloud. 
            Regardless of whether you will host Nextcloud from a custom domain (cloud.domainname.com) or from
            your router's reverse DNS (yourdomain.tplinkdns.net) (see step 4), you will need to specify 
            that address here.
        
            $ sudo snap run nextcloud.occ config:system:set trusted_domains 1 --value=https://cloud.domainname.com
        
        
            Additionally, since we are using nginx to proxy requests to our Nextcloud server, we will need to add 
            localhost (127.0.0.1) to our list of trusted proxies
        
            $ sudo snap run nextcloud.occ config:system:set trusted_proxies 0 --value=127.0.0.1
        
        Step 3: nginx site configuration
After adjusting our Nextcloud ports, we now need to configure nginx to operate as a reverse proxy to appropriately handle client requests and ensure that users are being served the expected content. We will go into the specifics of how and why we are using nginx now.
An introduction to proxies
Forward and reverse proxies are the two primary ways in which device communications over the internet can be monitored and controlled. A forward proxy, commonly referred to simply as a proxy, sits between users on a local network and the outside internet and acts on behalf of the internal clients, forwarding their requests to external servers. The normal workflow of a forward proxy is as follows:
- Internal users make a request to the proxy
 - The proxy forwards the request to external servers
 - External servers see the proxy as the client
 - Proxy returns response back to the internal client
 
A reverse proxy, on the other hand, sits between external clients and an internal server and acts on behalf of the server to process the incoming requests from external clients. A reverse proxy works as follows:
- External user makes request to what they think is the final server
 - Reverse proxy receives the request
 - Proxy forward request to appropriate internal server
 - Internal server processes request and returns response through the proxy back to the client
 
Essentially, the biggest difference between forward and reverse proxies is the direction of their protection: forward proxies protect internal clients from external resources, while reverse proxies protect internal servers from external clients.
nginx as a reverse proxy
For our Nextcloud server, we use nginx as a reverse proxy for many reasons:
- Getting SSL certificates for an nginx reverse proxy is simple, and much easier than integrating https into Nextcloud directly
 - It's an easy way to redirect all traffic to be SSL-encrypted (with https)
 - The reverse proxy allows us to run more than one type of webserver on the same machine, and nginx will redirect the incoming requests to the appropriate backend based on the URL of the content being accessed
 
Installing and configuring nginx
We begin by installing nginx with
            $ sudo apt install nginx
        
        
            Next, we need to create a site in /etc/nginx/sites-available/, which we are going to call 
            cloud. This will allow us to access Nextcloud from the web using cloud.domainname.com
            . Note that creating and modifying this file will require sudo.
        
            server { 
                
                server_name cloud.domainname.com; # modify this to match the domain name of your server!
                
 
                listen 80; 
                
                location / { 
                    
                    proxy_pass http://localhost:81; 
                    proxy_set_header Host $http_host; 
                    proxy_set_header X-Real-IP $remote_addr; 
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
                    proxy_set_header X-Forwarded-Proto $scheme; 
                    proxy_redirect off; 
                    
                } 
                
                fastcgi_request_buffering off; 
                client_max_body_size 2048m; 
                
            }
        
        You must enable your site by creating a link from sites-available to sites-enabled with
            $ sudo ln -s /etc/nginx/sites-available/cloud /etc/nginx/sites-enabled/
        
        and ensure that nginx is running with
            $ sudo systemctl enable nginx 
            $ sudo systemctl restart nginx
        
        Step 4: Port forwarding and DNS configuration
Before we can do certbot, we need to forward our http and https ports on the router so that connections outside of the local network have access to your Nextcloud server. This will require you to log into your router, likely through 192.168.1.1 or something similar. The "default gateway" entry in your device network settings will likely point you to the local IP address of your router.
From your router, go the the WAN settings and find port forwarding. You will want to forward ports 80 and 443 on the local IP address corresponding to the device on which your Nextcloud server is running. If your router asks for a choice on which protocol, TCP is just fine.
            You will also need to set up reverse DNS here, so that you know the IP address of your house. Many routers 
            support this feature with something called Dynamic Domain Name System (DDNS), granting you access to the 
            router with a registered domain name like yourdomain.tplinkdns.net or 
            yourdomain.asuscomm.com. If your router has this feature, set it up. Otherwise, there are 3rd 
            party services which provide a similar reverse DNS functionality.
        
            If you already have a domain name (which you should, since they are quite useful and inexpensive), you can 
            use it here to create a CNAME record for cloud.domainname.com which points to 
            yourdomain.tplinkdns.net or whatever your reverse DNS address is. If you don't have a domain 
            name and don't want to buy one, you can change the hostname in your nginx configuration to be your reverse 
            DNS address. You are limited to hosting only one webserver per reverse DNS address, though, but it will 
            work. Domain names are only ~$12/year, so I would recommend acquiring one. I use Cloudflare for 
            juliancalder.dev, and it works great.
        
Step 5: certbot configuration
We use certbot to easily generate signed SSL certificates for our sites, allowing browsers to authenticate over HTTPS thus encrypting data to and from the site. First, we must ensure we have certbot installed with
            $ sudo snap install certbot --classic
        
        Note that if you aren't on Ubuntu, you have to make sure you have set up the symlink to allow classic snaps to be in your path -- see the snap documentation here.
            Certbot will look for any websites accessible over http and give you a list from which you can choose which 
            ones you want to generate SSL certificates for. You can run the command below and it should automatically 
            detect and generate certificates for your site, after which time your site should be securely accessible 
            at cloud.yourdomain.com
        
            $ sudo certbot --nginx
        
        Step 6 (optional): Importing a Nextcloud backup
The snap version of Nextcloud has a very useful feature enabling you to import a backup of a preexisting server, making it much easier to migrate your server to new hardware (as I did when upgrading from a Raspberry Pi to my new 2700x-powered system). You can import the backup with
            $ sudo nextcloud.import /path/to/your/backup
        
        
            Before you do this, though, it is important that you verify that your backup is somewhere the Nextcloud 
            snap can read it, and that the backup is owned by root. Snaps are fully sandboxed applications, so they are 
            self-contained applications which only have access to the files and resources they need to operate. The 
            Nextcloud snap only has access to the internet and the ability to bind to a port, and importantly does not
            have access to the filesystem outside of its own namespace (including /var/snap/nextcloud/). 
            Therefore, you need to move your backup to somewhere in the filesystem that Nextcloud will be able to
            access it
        
            $ sudo mv /path/to/your/backup /var/snap/nextcloud/common/backup 
            $ sudo chown -R root:root /var/snap/nextcloud/common/backup
        
        It may take a while to restore this backup depending on the size of the file, but once it is finished you should be able to use your devices syncing to the server without any interruptions. Once your backup has been imported, you can safely delete it (unless you want to hold onto it for some reason).
Conclusion
            If you followed the steps above, you should now have an operational Nextcloud server! Depending on your 
            operating system, there are different Nextcloud desktop applications which will allow you to fairly 
            seamlessly integrate this cloud backup functionality into your existing desktop ecosystem. If possible, 
            I would recommend making symlinks from Nextcloud/Documents, Pictures, Music, etc to your 
            home directory to take full advantage of the integration.
        
            Note that it could take some time to sync all of your files the first time your server becomes operational. 
            I've had success syncing all of my files from my primary system, and then using a command like 
            rsync to transfer my files to other systems on my home network to take full advantage of 
            hardware-limited ethernet transfer speeds.
        
References
This post (and this entire website, honestly) would not have been possible without the help of my brother Oliver (calder.dev). The Nextcloud git repo and forums also provided insight into some specific server configuration commands.