Can I set up a Nextcloud-specific hostname?

I’ve cobbled together the following module to set up Nextcloud, based on a couple of blog posts. It works in the sense that I can access Nextcloud via de machine’s (Raspberry Pi’s) hostname or local IP address, if I add those to services.nextcloud.settings.trusted_domains.

However, I think the blog posts implied that I could set a custom hostname, i.e. nextcloud.tld in the configuration below, and then access it on my network via that hostname. Is that actually true, and if so, which changes do I need to make to achieve that?

(I still know very little of home networking, unfortunately. There are also references to potentially making it accessible from outside my home network via my domain, but I figured I’d make this work first, and then afterwards think about whether that’s even a good idea.))

{ config, pkgs, ... }:

{
  sops.secrets = {
    "nextcloud.admin_pass" = {
      owner = "nextcloud";
    };
    "nextcloud.db_pass" = {};
    "nextcloud.cloudflare_api_token" = {};
  };

  # PostgreSQL service configuration
  services.postgresql = {
    enable = true;
    package = pkgs.postgresql_17;
    ensureDatabases = [ "nextcloud" ];
    ensureUsers = [
      {
        name = "nextcloud";
        ensureDBOwnership = true;
      }
    ];
  };

  services.nginx = {
    enable = true;
    virtualHosts = {
      "${config.services.nextcloud.hostName}" = {
        forceSSL = true;
        enableACME = true;
      };
    };
  };

  networking.firewall.allowedTCPPorts = [ 80 443 ];

  security.acme = {
    acceptTerms = true;
    defaults.email = "email@example.com";
  };

  # Nextcloud service configuration
  services.nextcloud = {
    enable = true;
    package = pkgs.nextcloud30;
    hostName = "nextcloud.tld";

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

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

    config = {
      dbtype = "pgsql";
      dbuser = "nextcloud";
      dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
      dbname = "nextcloud";
      adminpassFile = config.sops.secrets."nextcloud.admin_pass".path;
      adminuser = "root";
    };
    settings = {
      default_phone_region = "NL";
      overwriteprotocol = "https";
      trusted_domains = [
        "nextcloud.tld"
      ];
    };
    extraAppsEnable = true;
    extraApps = with config.services.nextcloud.package.packages.apps; {
      # List of apps we want to install and are already packaged in
      # https://github.com/NixOS/nixpkgs/blob/e135e7f1ae9dd7e9dc4b2924e20bfea19e1a9d98/pkgs/servers/nextcloud/packages/nextcloud-apps.json
      inherit calendar contacts mail notes onlyoffice tasks;

      solid = pkgs.fetchNextcloudApp rec {
        url =
          "https://github.com/pdsinterop/solid-nextcloud/releases/download/v0.9.0/solid.tar.gz";
        license = "gpl3";
        sha256 = "d5b8d8304c4878678d2865d1c5ebdd90d571e1855a956dac55209572df0cbafb";
      };
    };
    maxUploadSize = "1G"; # Adjust for max upload size
    https = true;
  };

  services.ddclient = {
    enable = true;
    protocol = "cloudflare";
    ssl = true;
    zone = "example.com";
    domains = [ "nextcloud.example.com" ];
    passwordFile = config.sops.secrets."nextcloud.cloudflare_api_token".path;
  };

  # ensure that postgres is running *before* running the setup
  systemd.services."nextcloud-setup" = {
    requires = ["postgresql.service"];
    after = ["postgresql.service"];
  };

}

Yes, and not many. You need to ensure that whatever domain you’re setting resolves to your raspberry pi’s IP address on a DNS level (probably your issue), and you need to make sure that your SSL certificate is valid for that domain.

You seem to use ddns for setting up your pi’s domain, using that as the domain for your nextcloud subdomain would probably work. Alternatively, set up your router to point DNS requests of a local domain to your server, and use that as your nextcloud domain, use a local dns server (e.g. unbound) directly on your computer, or edit your computer’s /etc/hosts to contain the correct host → IP mapping.

Hmm OK. I did not get my domain working yet - I can’t even reach Nextcloud by connecting to its public IP, so presumably I need to open something up on my router first. Since I’m not confident about the implications of that, it’s probably a good idea to leave that be for now :sweat_smile:

I would prefer not having to setup every device on my network individually, so that leaves me with either setting it up on the router or on the Pi. I just fiddled with the router settings a bit, but could not find out how to make it point DNS requests of a local domain to my Pi - and ideally, I’d have it configured as part of my NixOS config, just like I did for the main hostname. But I take it that that’s not possible then?

No, or well, not how you’d like most likely. Ultimately your clients need to know the IP address of your pi, and before your pi shares that information with the network there’s no
way for them to know. It’d be a mess if any machine could just claim any arbitrary domain name, so there’s no way to do that.

You’ll have to run a DNS server somewhere, or configure your router’s DHCP settings to assign a hostname - you already do the latter, and clearly your pi is available under that hostname.

What you could do is use nextcloud.${hostname}, and then access nextcloud on your intranet that way, if you just care about the subdomain.

Or if you really wanted to, you could host a DNS server on your pi, configure your chosen local zone on there, and configure your router to send across your pi’s IP address as the DNS server’s. Then all your computers (save for those that override the dhcp DNS server, though you could MITM DNS requests, unless your devices use one of the secure DNS transports) would go and ask your pi about all domain names, and you could pretty much configure anything you want (with your NixOS config). That’d be the way to go for a more serious homelab setup.

You could even go a step further and host wireguard on your pi and then have it host its own dhcp server, then you could use dyndns to let your devices use it as a VPN (after forwarding whatever port your wireguard setup expects), expanding access to your intranet to any device anywhere with a very minimal attack surface - you wouldn’t even need to do the masquerading thing that people usually associate with VPNs, it can just be a subnet. That’d be the really serious homelab setup :wink:

1 Like

Thanks, this is enlightening! Eventually I’ll probably go the hosting-a-DNS-server on my Pi, since I’d like to look at running Pi-Hole there too. However, for now…

What you could do is use nextcloud.${hostname}, and then access nextcloud on your intranet that way, if you just care about the subdomain.

This actually sounds perfect! Would you have any pointers that I could look into on how to set that up, by any chance?

Afaict all you need to do is change this:

To this:

services.nextcloud = {
    enable = true;
    package = pkgs.nextcloud30;
    hostName = "nextcloud.${config.networking.hostName}";

The only thing this changes is that nginx will now read the incoming URL and if it matches “nextcloud.<hostname>” it will serve the nextcloud php files. Any requests to your hostname will resolve to your pi, and the subdomain should be ignored for that IP assignment, so it’s basically just metadata for nginx.

Hmm, that would’ve been amazing, but unfortunately doesn’t seem to do it. At first it fails as such:

× acme-nextcloud.pi.service - Renew ACME certificate for nextcloud.pi
     Loaded: loaded (/etc/systemd/system/acme-nextcloud.pi.service; enabled; preset: ignored)
     Active: failed (Result: exit-code) since Tue 2025-02-11 21:28:45 CET; 9s ago

After commenting out

        #forceSSL = true;
        #enableACME = true;

it does succeed, but then trying to visit http://nextcloud.pi results in a server not found error :frowning:

Yes, you can’t ask letsencrypt to certify that you are the canonical owner of the hostname pi. If you want to have SSL on your intranet, you’ll have to use a self-signed certificate (or have your own root CA whose certificates you install on all your devices).

That’s unfortunate, I dug around a bit and it looks like not all dhcp implementations support this. Perhaps a local DNS server is your only option. Many routers come with features for this, though, check if it supplies a .local tld somewhere.