{ config, lib, pkgs, ... }: let svc_domain = "nextcloud.${config.mine.shared.settings.domain}"; default_storage_quota = "100MB"; # place data into own zfs dataset stateDir = config.mine.zfsMounts."rpool/safe/svcs/nextcloud"; # helper variables nextcloud_user = config.users.users.nextcloud.name; nextcloud_group = config.users.groups.nextcloud.name; AUTHELIA_AUTH_NAME = "nextcloud"; # occ bin occ = config.services.nextcloud.occ + "/bin/nextcloud-occ"; # script for setting up ldap for nextcloud # - ensure user_ldap app is intalled # - ensure user_ldap app is enabled # - delete all ldap configurations # - add new configuration with our settings nextcloudSetupLdap = let ldap_settings = { ldapHost = "localhost"; ldapPort = 3890; ldapAgentName = config.mine.shared.settings.ldap.bind_dn; # ldapAgentPassword = ""; ldapBase = config.mine.shared.settings.ldap.dc; ldapBaseUsers = config.mine.shared.settings.ldap.dc; ldapBaseGroups = config.mine.shared.settings.ldap.dc; ldapLoginFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib: llib.mkAnd [ (llib.mkOC lconfig.oc.person) (llib.mkSearch lconfig.attr.uid "%uid") ] ); # EDIT: nextcloud_users group, contains the users who can login to Nextcloud ldapUserFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib: llib.mkAnd [ (llib.mkOC lconfig.oc.person) (llib.mkGroup lconfig.groups.member) ] ); ldapUserFilterObjectclass = config.mine.shared.settings.ldap.oc.person; ldapGroupFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib: llib.mkAnd [ (llib.mkOC lconfig.oc.groupOfUniqueNames) (llib.mkOr [ "cn=${lconfig.groups.admin}" "cn=${lconfig.groups.member}"]) ] ); ldapGroupFilterGroups = "admin;user"; ldapGroupFilterObjectclass = config.mine.shared.settings.ldap.oc.groupOfUniqueNames; ldapGroupMemberAssocAttr = "uniqueMember"; ldapEmailAttribute = config.mine.shared.settings.ldap.attr.email; ldapUserFilterMode = 1; ldapExpertUsernameAttr = config.mine.shared.settings.ldap.attr.uid; ldapConfigurationActive = 1; }; ldap_commands = lib.mapAttrsToList (n: v: "${occ} ldap:set-config $NEW_CONFIG_ID ${n} '${builtins.toString v}'") ldap_settings; in pkgs.writeShellScript "nextcloud-add-ldap.sh" '' # enable ldap service, remove config and create new empty one ${occ} app:install user_ldap ${occ} app:enable user_ldap # create new empty config NEW_CONFIG_ID="$(${occ} ldap:create-empty-config -p)" # setup ldap password BIND_USERPASS="$(cat $CREDENTIALS_DIRECTORY/lldap-bind-user-pass)" ${occ} ldap:set-config $NEW_CONFIG_ID ldapAgentPassword "$BIND_USERPASS" # set settings ${builtins.concatStringsSep "\n" ldap_commands} # delete all other configurations CONFIGS=$(${occ} ldap:show-config --output=json | ${pkgs.jq}/bin/jq -r '. | keys | .[]') echo "$CONFIGS" | while read CONFIG_ID; do if [[ "$NEW_CONFIG_ID" != "$CONFIG_ID" ]]; then ${occ} ldap:delete-config "$CONFIG_ID" fi done # promote ldap admin group to admins ${occ} ldap:promote-group ${config.mine.shared.settings.ldap.groups.admin} --yes -n ''; # script for resetting nextcloud admin password on each startup nextcloudSetupAdmin = pkgs.writeShellScript "nextcloud-setup-admin.sh" '' # reset admin password on each start export OC_PASS="$(cat $CREDENTIALS_DIRECTORY/nextcloud-admin-pass)" ${occ} user:resetpassword --password-from-env -- ${config.services.nextcloud.config.adminuser} ''; # script for setting encryption for nextcloud # - ensure encryption app is intalled # - ensure encryption app is enabled # - enable encryption # - ensure all files are encrypted nextcloudSetupEncryption = pkgs.writeShellScript "nextcloud-setup-encryption.sh" '' # enable encryption ${occ} app:install encryption ${occ} app:enable encryption ${occ} encryption:enable echo "Ensuring everything is encrypted!" if [[ ! -e ${stateDir}/.encrypt-setup ]]; then echo "Running encrypt-all!" printf "y\n" | ${occ} encryption:encrypt-all touch ${stateDir}/.encrypt-setup else echo "Encrypt all has already ran, not running again." fi ''; # script for setting up tho storage quota # possible to set based on groups # https://github.com/nextcloud/groupquota nextcloudSetupStorageQuota = pkgs.writeShellScript "nextcloud-setup-storage-quota.sh" '' # set default quota ${occ} config:app:set files default_quota --value '${default_storage_quota}' ''; in { services.nextcloud = { enable = true; package = pkgs.nextcloud29; datadir = stateDir; config.adminpassFile = config.age.secrets.nextcloud-admin-pass.path; hostName = svc_domain; https = true; configureRedis = true; # apps extraAppsEnable = true; extraApps = { inherit (config.services.nextcloud.package.packages.apps) contacts calendar tasks; oidc_login = let version = "3.1.1"; # TODO(eyJhb): add to niv in pkgs.fetchNextcloudApp { sha256 = "sha256-b/tKk+y+ZypCHGNDtunDua2msYD6/TzA0haoC0k85F4="; url = "https://github.com/pulsejet/nextcloud-oidc-login/releases/download/v${version}/oidc_login.tar.gz"; license = "agpl3Only"; }; }; # secrets secretFile = config.age.secrets.nextcloud-secrets.path; # settings settings = { # open connect/oidc oidc_login_provider_url = "https://${config.mine.shared.settings.authelia.domain}"; oidc_login_client_id = AUTHELIA_AUTH_NAME; # oidc_login_client_secret = ""; oidc_login_proxy_ldap = true; # SUPER IMPORTANT! oidc_login_auto_redirect = true; oidc_login_button_text = "Log in with Authelia"; oidc_login_use_id_token = true; oidc_login_attributes = { id = "preferred_username"; ldap_uid = "preferred_username"; name = "name"; mail = "email"; groups = "groups"; }; oidc_login_scope = "openid profile email groups"; oidc_login_code_challenge_method = "S256"; }; }; systemd.services.nextcloud-setup = { # runs this after all the main nextcloud-setup stuff script = lib.mkAfter '' ${nextcloudSetupLdap} ${nextcloudSetupAdmin} ${nextcloudSetupEncryption} ${nextcloudSetupStorageQuota} ''; # setup credentials for service serviceConfig.LoadCredential = [ "lldap-bind-user-pass:${config.age.secrets.lldap-bind-user-pass.path}" "nextcloud-admin-pass:${config.age.secrets.nextcloud-admin-pass.path}" ]; # do not run on each nixos rebuild switch!!!!!!!!!!! serviceConfig.RemainAfterExit = true; }; # ensure that nextcloud can access stateDir systemd.tmpfiles.rules = [ "Z ${stateDir} 6770 ${nextcloud_user} ${nextcloud_group} -" ]; # setup authelia for nextcloud services.authelia.instances.main.settings.identity_providers.oidc.clients = [{ client_id = AUTHELIA_AUTH_NAME; client_name = "Nextcloud"; client_secret = "$pbkdf2-sha512$310000$kLNQ/1A.uasSN4g8q94jUQ$8OKNUNNumHCh8dVG5/QWys7u.y1guqFXlrL.bMm7/HKTsWhpib/W.8qlU6VU7V1Be/h14Y.fJi3RLvbkEdo2kA"; redirect_uris = [ "https://${svc_domain}/apps/oidc_login/oidc" ]; scopes = [ "openid" "profile" "email" "groups" ]; }]; services.nginx.virtualHosts."${svc_domain}" = { forceSSL = true; enableACME = true; }; age.secrets = { nextcloud-admin-pass.owner = nextcloud_user; nextcloud-secrets.owner = nextcloud_user; }; mine.shared.meta.nextcloud = { name = "Nextcloud"; description = "We host our own Nextcloud for having a central place for personal files, etc. (all files are encrypted using the standard encryption module)! Login using your credentials."; url = "https://${svc_domain}"; package = let pkg = config.services.nextcloud.package; in { name = pkg.pname; version = pkg.version; meta = pkg.meta; }; }; }