Help understanding a Nextcloud module install

Hi all ,

I want to to switch to NixOS for my server setup, which currently runs fedora and nextcloud plus caddy in containers.

currently, I have the nextcloud fpm image with a caddy webserver, a redis container and a mariadb container all in a podman pod, behind a caddy reverse proxy container. A lot of caddy I know! :smile:

First question regarding the database, is postgresql the recommended option ? I know mysql is similar to mariadb but I guess its not compatible in so much as I cant specify it as a database type ? so should I abandon mariadb and then start from fresh with pgsql? ( i.e no database dump ) .

second question in the 23.11 release docs it shows I can use an alternative to the web server in front of Nextcloud by disabling nginx and stating a different option, but it suggests itā€™s a reverse proxy?!

my understanding of my current setup with containers is that the Caddy container I have in front of the Nextcloud fpm container is a web server for the fpm container and that in fact my Caddy container in front of all of that was my reverse proxy, is this correct or is it a reverse proxy in front of a reverse proxy ?

not that it matters too much as I guess in Nix I can just specify a Caddy reverse proxy in front of the Nextcloud install and just leave nginx enabled and managed by the Nix along with the database and redis.

next question, my understanding is that if I specify extra apps in my config the apps will be updated with nixos-rebuild switch and not via the web interface of Nextcloud? is this just the nix way or is it what most users do rather that update and install via Nextcloud?

If I install Caddy as a reverse proxy can I have another instance of Caddy with nix? I currently have a Caddy container as a file server, one as a reverse proxy and as I mentioned one as a web server( if Iā€™m correct in my understanding) in front of Nextcloud

is there a way to specify the data directory on another ssd drive ? as I currently understand all config and data is stored in /var/lib/nextcloud/ could I use datadirectory' => '/media/storage/nextcloud/data in my config options?

if I let nixos manage the database what happens during an major upgrade for example from postgres 15 to 16 say, will this cause a problem ?

so this is a nix config based on my understanding:

{ self, config, lib, pkgs, ... }:

{

  services = {

   caddy = {
   enable = true;
   virtualHosts."example.org".extraConfig = ''
     reverse_proxy http://localhost:5080'';
   };

    nginx.virtualHosts = {
      "localhost" = {
        listen = [ { addr = "127.0.0.1"; port = 5080; } ];
        forceSSL = false;
        enableACME = false;
      };
    };

    nextcloud = {
      enable = true;
      hostName = "localhost";

       # Need to manually increment with every major upgrade.
      package = pkgs.nextcloud27;

      database.createLocally = true;

      configureRedis = true;

      phpOptions = {
        maxUploadSize = "16G";
        https = true;
        enableBrokenCiphersForSSE = false;
      };

      autoUpdateApps.enable = true;
      extraAppsEnable = true;
      extraApps = with config.services.nextcloud.package.packages.apps; {
        inherit calendar contacts notes  tasks;
      };

      config = (
        trusted_proxies = ['127.0.0.1'];
        overwriteProtocol = "https";
        defaultPhoneRegion = "GB";
        dbtype = "pgsql";
        overwrite.cli.url = "https://example.org";
        adminuser = "greylinux";
        adminpassFile = "/etc/nextcloud-admin-pass";
      };
    };
  };
}

will this work ?

do I need the trusted proxies section ? currently I do but thatā€™s because I run in containers

Is the admin pass file where the admin user password is saved ? is this from the first install screen or do I have to specify it in the file before hand ? what about other users?

this is the caddyfile I have for my caddy file server

http://192.168.1.160 {
        root * /media/
        file_server * {
                browse /etc/caddy/simple.html
        }
}

and the html file mentioned

{{$useragent := .Req.Header.Get "User-Agent"}}
{{if regexMatch "^Kodi" $useragent}}
<!DOCTYPE html>
<html><body><table><tbody>
{{range .Items}}
  <tr>
    <td><a href="{{html .URL | replace "./" ""}}">{{html .Name}}</a></td>
    <td>{{.HumanModTime "2006-Jan-02 15:04:05"}}</td>
    <td>{{if .IsDir}}-{{else}}{{.HumanSize | replace " " "" | replace "iB" ""}}{{end}}</td>
    <td>{{if .IsDir}}Directory{{else}}application/octet-stream{{end}}</td>
  </tr>
{{end}}
<tbody></table></body></html>
{{else}}
... browse output for other user agents (not kodi) ...
{{end}}

this is for my kodi server, how do I declare this in my nix config above should I leave the html doc as a file and just reference it in the nix config? or can I do a file server another way ?

if you have any tips, advice or sites you think might help my understanding I would really appreciate it.

thanks in advance for the advice

1 Like

So Ive been experimenting and Iā€™ll answer some of my questions.

I tried pgsql as its what is stated in the wiki , so keeping it simple for the moment, obviously it does mean I cant migrate but no issue to set it all back up again.

This is true , but as others have mentioned in other posts Nextcloud has its own nginx integrate in the module so although I can add Caddy in front as a reverse proxy, Iā€™ve decided to go the wireguard vpn route negating a reverse proxy

This is correct, I stupidly got confused

This is correct, but I would rather go the route of installing via Nextcloud as not all my apps that I use are packaged in nixos yet and I feel more comfortable doing it this way than adding all my apps in nix config with fetchNextcloudApp

Iā€™m sure this is possible but as I said Iā€™m going the vpn route so only one caddy instance for a file server.

I havent tried this yet, I will try this next to test if this works.

This Iā€™m still unsure about.

it my current test setup up I didnā€™t need this .

yes this is the password file, Iā€™m not sure I set it correctly as I used

umask 077
sudo -i nano /var/nextcloud-admin-pass
sudo -i chown nextcloud /var/nextcloud-admin-pass

in the end which seemed to work.
not sure about where other users are saved yet, but Iā€™ll specify them in the Nextcloud web ui

I havenā€™t set this up yet, so I test and see
The wireguard vpn seems to work I was able to see my nextcloud install via the ip address, although I donā€™t want all traffic to route through my vpn just access local services. More testing is required but happy that it works so far.

this is my current working config the

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ā€˜nixos-helpā€™).

{ config, pkgs, ... }:

{
    services = {

    nextcloud = {
      enable = true;
      hostName = "192.168.1.217";

       # Need to manually increment with every major upgrade.
      package = pkgs.nextcloud27;

      # Let NixOS install and configure the database automatically.
      database.createLocally = true;

      # Let NixOS install and configure Redis caching automatically.
      configureRedis = true;

      # Increase the maximum file upload size to avoid problems uploading videos.
      maxUploadSize = "16G";
      enableBrokenCiphersForSSE = false;
	
      config = {
        
        defaultPhoneRegion = "GB";
        dbtype = "pgsql";
        adminuser = "greylinux";
        adminpassFile = "/var/nextcloud-admin-pass";
      };
    };
  };

  # enable NAT
  networking.nat.enable = true;
  networking.nat.externalInterface = "wlan0";
  networking.nat.internalInterfaces = [ "wg0" ];

  networking.wireguard.interfaces = {
    # "wg0" is the network interface name. You can name the interface arbitrarily.
    wg0 = {
      # Determines the IP address and subnet of the server's end of the tunnel interface.
      ips = [ "10.100.0.1/24" ];

      # The port that WireGuard listens to. Must be accessible by the client.
      listenPort = 51820;

      # Path to the private key file.
      #
      # Note: The private key can also be included inline via the privateKey option,
      # but this makes the private key world-readable; thus, using privateKeyFile is
      # recommended.
      privateKeyFile = "/home/user/wireguard-keys/private";

      peers = [
        # List of allowed peers.
        { # Feel free to give a meaning full name
          # Public key of the peer (not a file path).
          publicKey = "my peer public key";
          # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
          allowedIPs = [ "10.100.0.2/32" ];
        }
      ];
    };
  };
  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  services.openssh.enable = true;

  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  networking.firewall.enable = false;

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. Itā€˜s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "23.05"; # Did you read the comment?

}

I canā€™t seem to have it that nextcloud is over https although Iā€™m not sure why, or if it matters if Iā€™m using wireguard outside of an error in web ui because of using http

I got https working with a self signed cert , but my worry is that the nextcloud client will have an issue with the exception you have to make when browsing the site. not sure yet

The mysql option uses pkgs.mariadb in the nixos module. So you can do an install with that and import your current db.

Itā€™s also possible to do a migration to pgsql. Therefore you need to additionally declare a postgres db (via services.postgres) with a database for the nextcloud user. There is a nextcloud-occ command to do the migration (it also changes the db entries in config.php to pgsql).
After that you need to change your nextcloud config in nix to pgsql.

1 Like

thank you for this, I just switch the test setup to mysql at least I can migrate once Iā€™m happy with everything.

To answer some more of my questions:

this didnā€™t work , I had to mkdir /nextcloud add datadir = "/nextcloud"; to my nextcloud entry and sudo chown nextcloud:nexcloud nextcloud/ this allowed me save data on a second ssd. ( for other users who want to permanently mount a drive in NixOS I did this )

1) create directory
2) sudo mount /dev/sda1 (or whatever drive is called)
3) sudo nixos-generate-config
4)sudo nixos-rebuild switch
this only changes /etc/nixos/hardware-configuration.nix 

also added bonus Iā€™m really happy I got nextcloud talk working, with video calls working perfectly , over the Wireguard vpn, I had to set up a local coturn turn server on the same ā€œtestā€ server running nextcloud.

So my working config looks like this:

services = {

    nextcloud = {
      enable = true;
      hostName = "192.168.1.217";
      https = true;
      
       # Need to manually increment with every major upgrade.
      package = pkgs.nextcloud27;

      # Let NixOS install and configure the database automatically.
      database.createLocally = true;

      # Let NixOS install and configure Redis caching automatically.
      configureRedis = true;

      # Increase the maximum file upload size to avoid problems uploading videos.
      maxUploadSize = "16G";
      enableBrokenCiphersForSSE = false;
      datadir = "/nextcloud";      
     	
      config = {
        
        defaultPhoneRegion = "GB";
        dbtype = "mysql";
        adminuser = "greylinux";
        adminpassFile = "/var/nextcloud-admin-pass";
      };
    };
  };
  services.nginx.virtualHosts.${config.services.nextcloud.hostName} = {
     forceSSL = true;
     sslCertificate = "/etc/nc-selfsigned.crt";
     sslCertificateKey = "/etc/nc-selfsigned.key";
  };
  

  # enable NAT
  networking.nat.enable = true;
  networking.nat.externalInterface = "wlp4s0";
  networking.nat.internalInterfaces = [ "wg0" ];

  networking.wg-quick.interfaces = {
    # "wg0" is the network interface name. You can name the interface arbitrarily.
    wg0 = {
      # Determines the IP address and subnet of the server's end of the tunnel interface.
      address = [ "10.100.0.1/24" ];

      # The port that WireGuard listens to. Must be accessible by the client.
      listenPort = 51820;

      postUp = ''
        ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o wlp4s0 -j MASQUERADE
      '';

      # Undo the above
      preDown = ''
        ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o wlp4s0 -j MASQUERADE
      '';
      # Path to the private key file.
      #
      # Note: The private key can also be included inline via the privateKey option,
      # but this makes the private key world-readable; thus, using privateKeyFile is
      # recommended.
      privateKeyFile = "/home/user/wireguard-keys/private";

      peers = [
        # List of allowed peers.
        { # Feel free to give a meaning full name
          # Public key of the peer (not a file path).
          publicKey = "my peer public key";
          # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
          allowedIPs = [ "10.100.0.2/32" ];
        }
      ];
    };
  };
  services.coturn = rec {
    enable = true;
    no-cli = true;
    no-tcp-relay = true;
    min-port = 49000;
    max-port = 50000;
    use-auth-secret = true;
    static-auth-secret = "my secret code";
  };

  services.openssh.enable = true;
  networking.firewall.enable = false;

I then added the turn details in my talk settings. This turn server is not exposed to the internet it is LAN only.

just my caddy file server now to setup and test and all my questions are answered.

this is the guide I used to setup wireguard on android and the server here

Ok , so I finished with my test setup yesterday and got everything, including a few bonus pieces like samba and wireguard setup, which wasnt part of my original line of questions.

I then migrated my existing setup (fedora server) to NixOS, using the config from the test rig. Iā€™m happy to say I now have a secure and stable setup on NixOS now.

here is my final configuration.nix

 # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    wget
    htop
    duf
    ncdu
    bat
    tldr
    lsd
    unzip
  ];

  # List services that you want to enable:
  
  services.caddy = {
      enable = true;
      globalConfig = ''
        auto_https off
        http_port  7080
        https_port 7443
      '';
      virtualHosts."192.168.1.160:7080" = {
        extraConfig = ''
          root * /media/storage/media/ 
          file_server * {
            browse /var/lib/caddy/simple.html
          }
        '';     
      };
    };   
  
  services = {

    nextcloud = {
      enable = true;
      hostName = "192.168.1.160";
      https = true;
      
       # Need to manually increment with every major upgrade.
      package = pkgs.nextcloud27;

      # Let NixOS install and configure the database automatically.
      database.createLocally = true;

      # Let NixOS install and configure Redis caching automatically.
      configureRedis = true;

      # Increase the maximum file upload size to avoid problems uploading videos.
      maxUploadSize = "16G";
      enableBrokenCiphersForSSE = false;      
      
      phpOptions = {
        "opcache.interned_strings_buffer" = "10";
      };
           	
      config = {
        
        defaultPhoneRegion = "GB";
        dbtype = "mysql";
        adminuser = "greylinux";
        adminpassFile = "/var/nextcloud-admin-pass";
      };
    };
  };
  services.nginx.virtualHosts.${config.services.nextcloud.hostName} = {
     forceSSL = true;
     sslCertificate = "/etc/nc-selfsigned.crt";
     sslCertificateKey = "/etc/nc-selfsigned.key";
  };
  
  # enable NAT
  networking.nat.enable = true;
  networking.nat.externalInterface = "eno1";
  networking.nat.internalInterfaces = [ "wg0" ];

  networking.wg-quick.interfaces = {
    # "wg0" is the network interface name. You can name the interface arbitrarily.
    wg0 = {
      # Determines the IP address and subnet of the server's end of the tunnel interface.
      address = [ "10.100.0.1/24" ];

      # The port that WireGuard listens to. Must be accessible by the client.
      listenPort = 51820;
   
      postUp = ''
        ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eno1 -j MASQUERADE
      '';

      # Undo the above
      preDown = ''
        ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
        ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o eno1 -j MASQUERADE
      '';
      # Path to the private key file.
      #
      # Note: The private key can also be included inline via the privateKey option,
      # but this makes the private key world-readable; thus, using privateKeyFile is
      # recommended.
      privateKeyFile = "/home/user/wireguard-keys/private";

      peers = [
        # List of allowed peers.
        { # Peer 1
          # Public key of the peer (not a file path).
          publicKey = "peer 1 public key";
          # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
          allowedIPs = [ "10.100.0.2/32" ];
          # preshared key file 
          presharedKeyFile = "/home/user/wireguard-keys/pre-shared-peer1";
        }
        { # peer2
          # Public key of the peer (not a file path).
          publicKey = "peer 2 public key";
          # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
          allowedIPs = [ "10.100.0.3/32" ];
          # preshared key file 
          presharedKeyFile = "/home/user/wireguard-keys/pre-shared-peer2";
        }
      ];
    };
  };
  services.coturn = {
    enable = true;
    no-cli = true;
    no-tcp-relay = true;
    min-port = 49800;
    max-port = 50000;
    use-auth-secret = true;
    static-auth-secret = "coturn secret";
  };
  
  services.samba = {
    enable = true;
    extraConfig = ''
      hosts allow = 192.168.1.215
      hosts deny = 0.0.0.0/0
    '';
    shares = {
      music_share = {
        comment = "Music share";
        path = "/media/storage/media/music/";
        public = "yes";
        browseable = "yes";
        writable = "yes";	
        "create mask" = "0644";
        "directory mask" = "0755";
        "guest ok" = "no";
        "write list" = "user";
      };
    };
  };
  
  services.openssh.enable = true;
  networking.firewall.enable = false;



}

If any user has any questions I can help with Iā€™m more than happy to help , hopefully this config helps someone.

Can you tell me how you mounted your ssd and pointed your datadir to it? Iā€™m trying to put my datadir on a mounted network share.

So I use the default directory now so /var/lib/nextcloud/ , so nothing to declare. To mount my local ssd I created the directory as you normally would in linux and mounted the drive as you normally would , so

Sudo mkdir /somewhere/nextcloud 
sudo mount /dev/ssd  /somewhere/nextcloud  

Then

Sudo nixos-generate-config  # to add the mount permanently to my hardware-configuration.nix

Sudo nixos-rebuild switch

To point nextcloud to that directory I guess you would add

datadir = "/somewhere/nextcloud";

To your configuration.nix similar to my config example a few posts up from this one.