{ pkgs, config, ... }: # don't forget the database backup before upgrading # ------------------------------------------------- # https://docs.nextcloud.com/server/stable/admin_manual/maintenance/backup.html # https://docs.nextcloud.com/server/stable/admin_manual/maintenance/upgrade.html # # ! use lvm snapshots to do rollback ! let hostInterface = "enp3s0"; hostAddress = "192.168.100.10"; containerAddress = "192.168.100.11"; nextcloudUid = 1000; borg_backup_folder = "/media/syncthing/nextcloud_backup/robi"; in { # Host Setup # ========== # give containers internet access networking.nat.enable = true; networking.nat.internalInterfaces = [ "ve-nextcloud" ]; networking.nat.externalInterface = hostInterface; # don't let networkmanager manger container network networking.networkmanager.unmanaged = [ "interface-name:ve-*" ]; # open ports for logging #networking.firewall.interfaces."ve-nextcloud".allowedTCPPorts = # [ 5044 12304 12305 ]; #networking.firewall.interfaces."ve-nextcloud".allowedUDPPorts = # [ 5044 12304 12305 ]; # host nginx # ---------- networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedUDPPorts = [ 80 443 ]; services.nginx = { enable = true; recommendedProxySettings = true; virtualHosts = { "nextcloud.ingolf-wagner.de" = { forceSSL = true; enableACME = true; locations = { "/" = { proxyPass = "http://${containerAddress}"; extraConfig = '' sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; # used for view/edit office file via Office Online Server client_max_body_size 0; ''; }; "= /.well-known/carddav" = { priority = 210; extraConfig = "return 301 $scheme://$host/remote.php/dav;"; }; "= /.well-known/caldav" = { priority = 210; extraConfig = "return 301 $scheme://$host/remote.php/dav;"; }; "~ .(?:css|js|svg|gif)$" = { proxyPass = "http://${containerAddress}$request_uri"; extraConfig = '' expires 6M; # Cache-Control policy borrowed from `.htaccess` access_log off; # Optional: Don't log access to assets sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de"; # used for view/edit office file via Office Online Server client_max_body_size 0; ''; }; "~ .woff2?$" = { proxyPass = "http://${containerAddress}$request_uri"; extraConfig = '' expires 7d; # Cache-Control policy borrowed from `.htaccess` access_log off; # Optional: Don't log access to assets sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de"; # used for view/edit office file via Office Online Server client_max_body_size 0; ''; }; }; }; }; }; sops.secrets.nextcloud_database_password.owner = "nextcloud"; sops.secrets.nextcloud_root_password.owner = "nextcloud"; users.users.nextcloud = { isSystemUser = true; uid = nextcloudUid; group = "nextcloud"; }; users.groups.nextcloud = { }; # Container Setup # =============== # # running: # * nextcloud (php) # * mysql containers.nextcloud = { # mount host folders bindMounts = { rootpassword = { hostPath = "/run/secrets/nextcloud_root_password"; mountPoint = "/run/secrets/nextcloud_root_password"; isReadOnly = true; }; databasepassword = { hostPath = "/run/secrets/nextcloud_database_password"; mountPoint = "/run/secrets/nextcloud_database_password"; isReadOnly = true; }; home = { # make sure this folder exist on the host hostPath = toString "/var/lib/nextcloud"; mountPoint = "/var/lib/nextcloud"; isReadOnly = false; }; db = { # make sure this folder exist on the host hostPath = toString "/var/lib/nextcloud_mysql"; mountPoint = "/var/lib/mysql"; isReadOnly = false; }; samples = { mountPoint = toString config.services.syncthing.folders.samples.path; hostPath = toString config.services.syncthing.folders.samples.path; isReadOnly = true; }; movies = { mountPoint = toString config.services.syncthing.folders.movies.path; hostPath = toString config.services.syncthing.folders.movies.path; isReadOnly = true; }; music = { mountPoint = toString config.services.syncthing.folders.music-library.path; hostPath = toString config.services.syncthing.folders.music-library.path; isReadOnly = true; }; series = { mountPoint = toString config.services.syncthing.folders.series.path; hostPath = toString config.services.syncthing.folders.series.path; isReadOnly = true; }; }; # container network setup # see also nating on host system. privateNetwork = true; hostAddress = hostAddress; localAddress = containerAddress; autoStart = true; config = { config, pkgs, lib, ... }: { users.users.nextcloud.uid = nextcloudUid; services.nginx = { # Use recommended settings recommendedGzipSettings = lib.mkDefault true; recommendedOptimisation = lib.mkDefault true; recommendedProxySettings = lib.mkDefault true; recommendedTlsSettings = lib.mkDefault true; }; networking.firewall.allowedTCPPorts = [ 80 ]; networking.firewall.allowedUDPPorts = [ 80 ]; # nextcloud database # ================== # # set user password: # ----------------- # #> mysql # mysql> ALTER USER 'nextcloud'@'localhost' IDENTIFIED BY 'nextcloud-password'; # # recreate database: # ------------------ # mysql> DROP DATABASE nextcloud; # mysql> CREATE DATABASE nextcloud; # # migration: # ---------- # nextcloud-occ db:convert-type --all-apps mysql nextcloud 127.0.0.1 nextcloud # # 4-byte stuff: # ------------- # https://docs.nextcloud.com/server/18/admin_manual/configuration_database/mysql_4byte_support.html # if you do this don't forget --default-character-set=utf8mb4 for mysqldump services.mysql = { enable = true; package = pkgs.mysql; # https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-20.09-incompatibilities ensureDatabases = [ "nextcloud" ]; ensureUsers = [{ name = "nextcloud"; ensurePermissions = { "nextcloud.*" = "ALL PRIVILEGES"; }; }]; settings.mysqld = { innodb_large_prefix = true; innodb_file_format = "barracuda"; innodb_file_per_table = 1; innodb_read_only_compressed = 0; }; }; # Backup database # --------------- services.mysqlBackup = { enable = true; databases = config.services.mysql.ensureDatabases; singleTransaction = true; location = "/var/lib/nextcloud/database_backups"; }; systemd.services."mysql-backup".serviceConfig = { ExecStartPre = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --on" ]; ExecStopPost = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --off" ]; }; # in php services.phpfpm.phpPackage = pkgs.php73; # nextcloud setup services.nextcloud = { enable = true; package = pkgs.nextcloud22; autoUpdateApps.enable = true; #nginx.enable = true; hostName = "nextcloud.ingolf-wagner.de"; logLevel = 2; https = true; config = { adminpassFile = "/run/secrets/nextcloud_root_password"; overwriteProtocol = "https"; trustedProxies = [ "144.76.13.147" hostAddress ]; dbtype = "mysql"; dbpassFile = "/run/secrets/nextcloud_database_password"; dbport = 3306; }; }; }; }; # Backup Config # ------------- #backup.dirs = [ # "/home/nextcloud/config" # "/home/nextcloud/database_backups" # created by mysqlBackup #]; # Backup Files # ------------ services.borgbackup.jobs = { "nextcloud-to-media" = { repo = borg_backup_folder; # make sure syncthing is capable of reading the files postHook = '' chown -R syncthing:syncthing ${borg_backup_folder} ''; compression = "lz4"; paths = [ "/var/lib/nextcloud/data/tina/files" "/var/lib/nextcloud/data/palo/files" "/var/lib/nextcloud/data/palo-windows/files" ]; doInit = true; encryption = { mode = "repokey-blake2"; passCommand = "cat ${config.sops.secrets.backup_repository_passphrase.path}"; }; startAt = "0/3:00:00"; prune.keep = { within = "2d"; # Keep all backups in the last 10 days. daily = 10; # Keep 10 additional end of day archives weekly = 8; # Keep 8 additional end of week archives. month = 8; # Keep 8 additional end of month archives. }; }; }; }