NextCloud is very versatile and useful (it can do files, calendars, contacts, and more.) and it feels familiar to users coming from Google Drive, Dropbox, etc, which can make it a good choice to start your journey towards data sovereignty, and even onboard some friends/family.

However it is not trivial to setup NextCloud in a proper, reliable way. This guide will attempt to present a nice and reliable way to setup NextCloud:

Prerequisites

Step 1: Setup Tailscale

First, you need to setup Tailscale on your server. Tailscale is a VPN service that makes it easy to connect your devices and share them with others anywhere in the world.

For this step, I will borrow heavily from this excellent guide.

  1. Add tailscale to the environment.systemPackages in your configuration.nix:
{ config, pkgs, ... }:

{
  # ...Your existing configuration
  environment.systemPackages = with pkgs; [
    # ...Your existing packages
    tailscale   # Add this line
  ];
  # ...Your existing configuration
}
  1. Obtain a one-time Tailscale auth key from the Tailscale admin console. Tailscale auth key step 1 Tailscale auth key step 2

Caution Please do not generate a reusable key for this purpose to make the next step secure.

  1. Create a new file tailscale.nix in the same directory as your configuration.nix:
{ config, pkgs, lib, ... }:
{
    # enable the tailscale service
    services.tailscale.enable = true;

    # Allow our Caddy service to access our Tailscale and automatically fetch/setup our HTTPS certificates
    services.tailscale.permitCertUid = "caddy";
    
    # create a oneshot job to authenticate to Tailscale
    systemd.services.tailscale-autoconnect = {
        description = "Automatic connection to Tailscale";
        
        # make sure tailscale is running before trying to connect to tailscale
        after = [ "network-pre.target" "tailscale.service" ];
        wants = [ "network-pre.target" "tailscale.service" ];
        wantedBy = [ "multi-user.target" ];
        
        # set this service as a oneshot job
        serviceConfig.Type = "oneshot";
        
        # have the job run this shell script
        script = with pkgs; ''
            # wait for tailscaled to settle
            sleep 2
        
            # check if we are already authenticated to tailscale
            status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)"
            if [ $status = "Running" ]; then # if so, then do nothing
            exit 0
            fi
        
            # otherwise authenticate with tailscale
            ${tailscale}/bin/tailscale up -authkey <PASTE_YOUR_AUTH_KEY_HERE>
        '';
    };
}
  1. Paste the one-time auth key you obtained from the Tailscale admin console in the tailscale.nix file, where it says <PASTE_YOUR_AUTH_KEY_HERE>.

Good to know It is generally considered bad practice to store secrets in plain text on a NixOS configuration file, as it can be easily leaked. However, in this case, since we generated a one-time key, it is less of a concern since the key will be invalidated after we make our first connection to Tailscale.

Caution Please make sure to connect to Tailscale before sharing your configuration file with anyone else, and maybe consider deleting the key from the file after you are done. If you need to use a reusable key, you should consider using a more secure method to store the key, such as using a Nix secret manager.

Step 2: Setup NextCloud using the AIO docker image

NixOS offers a way to install NextCloud using the nextcloud module. However, I found it easier to use the All-In-One Docker image. This way, you can avoid dealing with certain details like database setup, apache configuration, etc.

  1. Enable Docker in your configuration.nix:
{ config, pkgs, ... }:

{
  # ...Your existing configuration
  virtualisation.docker.enable = true;
  virtualisation.oci-containers.backend = "docker";
  # ...Your existing configuration
}
  1. Add a new nextcloud.nix file in the same directory as your configuration.nix with the following content:
{ self, config, lib, pkgs, ... }:
{
    # Define the Docker service for the NextCloud All-In-One image
    virtualisation.oci-containers.containers."nextcloud-aio-mastercontainer" = {
        # Use the latest NextCloud All-In-One image
        image = "nextcloud/all-in-one:latest";
        # Options required by the NextCloud All-In-One image
        extraOptions = [
            "--init"
            "--sig-proxy=false"
        ];
        ports = [
            # Forward the Nextcloud admin interface to port 8080
            "8080:8080"
            # Port 11000 is not explicitly forwarded here. NextCloud spawns new containers that forward on that port.
        ];
        volumes = [
            "nextcloud_aio_mastercontainer:/mnt/docker-aio-config"
            # This gives the container access to the Docker socket, which gives it the ability to spawn new containers, which is required for NextCloud AIO to work
            "/var/run/docker.sock:/var/run/docker.sock:ro"
        ];
        environment = {
            # Set the port for the Nextcloud main interface, we will forward port 443 to this port in Caddy
            APACHE_PORT="11000";
            # Bind to all interfaces
            APACHE_IP_BINDING="0.0.0.0";
            # We will use Caddy for reverse proxying and HTTPS, so we can skip domain validation
            SKIP_DOMAIN_VALIDATION="true";
        };
    };
}

This is essentially the equivalent of running the recommended Nextcloud AIO docker command detailed here.

Step 3: Setup Caddy for HTTPS

Nextcloud AIO seems to use HTTP or self-signed HTTPS, which can be cumbersome to deal with. We will use Caddy + Tailscale to automatically obtain and renew HTTPS certificates. Luckily, Tailscale works well with Caddy, so we can make this step easier.

  1. Enable MagicDNS on your Tailscale admin console.
  2. Enable HTTPS certificate support on your Tailscale admin console.
  3. Add a new caddy.nix file in the same directory as your configuration.nix with the following content:
{ config, pkgs, lib, ... }:
{
    services.caddy = {
        enable = true;
        virtualHosts = {
            # This will be the location where we will access Nextcloud
            "<HOSTNAME>.<TAILNET_NAME>.ts.net:443" = {
                # We reverse proxy this to our port 11000 using http
                extraConfig = ''
                    reverse_proxy localhost:11000
                '';
            };
            # This will be the location where we will access Nextcloud's installation and admin panel
            "<HOSTNAME>.<TAILNET_NAME>.ts.net:444" = {
                # We reverse proxy this to our port 8080. The Nextcloud container will try to use some self-signed certificate, but we can safely ignore it
                extraConfig = ''
                    reverse_proxy https://localhost:8080 {
                        transport http {
                            tls_insecure_skip_verify
                        }
                    }
                '';
            };
        };
    };
}

Replace <HOSTNAME> with your computer hostname and <TAILNET_NAME> with your Tailscale network name. You can find your Tailnet name on your admin console. For example, if my computer's hostname is home-server and the tailnet name is sparrow-pineapplefish, then the full domain name we will use is home-server.sparrow-pineapplefish.ts.net

Step 3: Import the new configuration files to your main configuration file

Import the new modules in your existing configuration.nix:

{ config, pkgs, ... }:

{
  imports = [
    # ...Your existing imports

    # Add these files which we created
    ./tailscale.nix
    ./nextcloud.nix
    ./caddy.nix
  ];
  
  # ...Your existing configuration
}

Step 4: Apply the configuration

Run sudo nixos-rebuild switch to apply the new configuration. This will install Tailscale, Nextcloud, and Caddy on your system.

You may need to wait a few minutes for all the services to start up.

If you are having issues, you can check the status of the services using tailscaled.service, systemctl status docker-nextcloud-aio-mastercontainer.service, and systemctl status caddy.service.

Step 5: NextCloud GUI setup

  1. Access your Nextcloud admin panel by going to https://<HOSTNAME>.<TAILNET_NAME>.ts.net:444 in your browser (replace <HOSTNAME> and <TAILNET_NAME> with your values).
  2. The first screen will show you a passphrase for this admin panel. Copy it and save it somewhere safe. AIO passphrase screen
  3. Continue and login to the admin panel.
  4. Next, you will be asked to indicate the domain you will be using to access Nextcloud. Enter <HOSTNAME>.<TAILNET_NAME>.ts.net, replacing <HOSTNAME> and <TAILNET_NAME> with your values. (e.g. home-server.sparrow-pineapplefish.ts.net)
  5. Then, you will be prompted to install the remaining nextcloud components. Follow the instructions on the screen. It might take several minutes for nextcloud to install everything
  6. Once you are done, copy the admin password, which will be shown on the screen. Save it somewhere safe. NextCloud admin password
  7. You can now access your Nextcloud installation by going to https://<HOSTNAME>.<TAILNET_NAME>.ts.net in your browser. Login with admin and the password you copied in the previous step.
  8. (Optional) You can create other users from within Nextcloud.
  9. You are all set! You can now access your Nextcloud installation from anywhere in the world using the Tailscale, with HTTPS enabled NextCloud dashboard

Step 5: (Bonus) Setup backups

  1. Go to the admin panel of your Nextcloud installation at https://<HOSTNAME>.<TAILNET_NAME>.ts.net:444.
  2. Scroll down, there will be a backup section. You can set a path where you want to store your backups. This should generally be an external drive or network location mounted on your NixOS system. Once you input the path, follow the instructions on-screen. NextCloud backup section
  3. Each time you want to backup, you can go to the admin panel and click on the backup button. Please note that all containers will be stopped during the backup process, so it is recommended to do this during off-peak hours.

Learn more Psst! By the way, this Nextcloud setup uses Borg backup for its backups. If you want to deepen your knowledge of this handy backup tool, check out this guide: Making backups with Borg

Q&A

Where is my data stored?

Under this setup, data will be stored in docker volumes. To find out, run this command to see the volumes.

$ sudo docker volume ls
DRIVER    VOLUME NAME
local     nextcloud_aio_apache
local     nextcloud_aio_backup_cache
local     nextcloud_aio_database
local     nextcloud_aio_database_dump
local     nextcloud_aio_elasticsearch
local     nextcloud_aio_mastercontainer
local     nextcloud_aio_nextcloud
local     nextcloud_aio_nextcloud_data
local     nextcloud_aio_redis

Each volume has a separate use in NextCloud. If you want to see where the files uploaded to NextCloud are stored in, you are looking for the nextcloud_aio_nextcloud_data volume.

To be able to see those files from your system, run:

$ sudo docker volume inspect nextcloud_aio_nextcloud_data

This will give you some information about the volume, including where it is mounted in your system. Likely that will be /var/lib/docker/volumes/nextcloud_aio_nextcloud_data/_data

Things went wrong, how do I check the status of things?

Checking the status of Tailscale:

$ systemctl status tailscaled.service

Checking the status of Caddy:

$ systemctl status caddy.service

Checking the status of NextCloud:

$ systemctl status docker-nextcloud-aio-mastercontainer.service

Other questions?

Please feel free to reach out to me! You can find various contact options here: https://danieldaquino.me