From b7527810647c164f4ad661d95e0353018c49f414 Mon Sep 17 00:00:00 2001 From: cnst Date: Sun, 21 Sep 2025 13:27:02 +0200 Subject: [PATCH] feat(nextcloud): switch from nginx to caddy --- hosts/sobotka/server.nix | 4 - modules/server/acme/default.nix | 20 ++--- modules/server/nextcloud/default.nix | 128 +++++++++++++++------------ 3 files changed, 82 insertions(+), 70 deletions(-) diff --git a/hosts/sobotka/server.nix b/hosts/sobotka/server.nix index 2202fdcf..77dbd606 100644 --- a/hosts/sobotka/server.nix +++ b/hosts/sobotka/server.nix @@ -65,10 +65,6 @@ nextcloud = { enable = true; adminpassFile = config.age.secrets.nextcloudAdminPass.path; - cloudflared = { - tunnelId = "35802b60-7012-4f70-a686-f493c8f2dec0"; - credentialsFile = config.age.secrets.nextcloudCloudflared.path; - }; }; fail2ban = { enable = true; diff --git a/modules/server/acme/default.nix b/modules/server/acme/default.nix index b412dd01..7093de10 100644 --- a/modules/server/acme/default.nix +++ b/modules/server/acme/default.nix @@ -39,16 +39,16 @@ in { group = config.services.caddy.group; environmentFile = getCloudflareCredentials config.networking.hostName; }; - certs.${config.server.domainPublic} = { - reloadServices = ["nginx.service"]; - domain = "${config.server.domainPublic}"; - extraDomainNames = ["*.${config.server.domainPublic}"]; - dnsProvider = "cloudflare"; - dnsResolver = "1.1.1.1:53"; - dnsPropagationCheck = true; - group = config.services.nginx.group; - environmentFile = getCloudflareCredentials config.networking.hostName; - }; + # certs.${config.server.domainPublic} = { + # reloadServices = ["nginx.service"]; + # domain = "${config.server.domainPublic}"; + # extraDomainNames = ["*.${config.server.domainPublic}"]; + # dnsProvider = "cloudflare"; + # dnsResolver = "1.1.1.1:53"; + # dnsPropagationCheck = true; + # group = config.services.nginx.group; + # environmentFile = getCloudflareCredentials config.networking.hostName; + # }; }; services.caddy = { diff --git a/modules/server/nextcloud/default.nix b/modules/server/nextcloud/default.nix index 84d70abf..c024dd34 100644 --- a/modules/server/nextcloud/default.nix +++ b/modules/server/nextcloud/default.nix @@ -25,7 +25,7 @@ in { }; url = lib.mkOption { type = lib.types.str; - default = "cloud.${srv.domainPublic}"; + default = "cloud.${srv.domain}"; }; homepage.name = lib.mkOption { type = lib.types.str; @@ -43,29 +43,8 @@ in { type = lib.types.str; default = "Services"; }; - cloudflared.credentialsFile = lib.mkOption { - type = lib.types.str; - example = lib.literalExpression '' - pkgs.writeText "cloudflare-credentials.json" ''' - {"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"} - ''' - ''; - }; - cloudflared.tunnelId = lib.mkOption { - type = lib.types.str; - example = "00000000-0000-0000-0000-000000000000"; - }; }; config = lib.mkIf cfg.enable { - services.cloudflared = { - enable = true; - tunnels.${cfg.cloudflared.tunnelId} = { - credentialsFile = cfg.cloudflared.credentialsFile; - default = "http_status:404"; - ingress."${cfg.url}".service = "http://127.0.0.1:8083"; - }; - }; - server.fail2ban = lib.mkIf config.server.fail2ban.enable { jails = { nextcloud = { @@ -84,23 +63,17 @@ in { redis = true; }; phpOptions = { - "opcache.jit" = "tracing"; - "opcache.jit_buffer_size" = "100M"; - "opcache.interned_strings_buffer" = "16"; - "opcache.max_accelerated_files" = "10000"; - "opcache.memory_consumption" = "1280"; + "opcache.interned_strings_buffer" = "32"; }; maxUploadSize = "50G"; settings = { maintenance_window_start = "1"; - trusted_proxies = ["127.0.0.1"]; - trusted_domains = ["cloud.${srv.domainPublic}"]; - overwriteprotocol = "https"; - overwritehost = "cloud.${srv.domainPublic}"; - overwrite.cli.url = "https://cloud.${srv.domainPublic}"; - forwarded_for_headers = [ - "HTTP_CF_CONNECTING_IP" + trusted_proxies = [ + "127.0.0.1" + "::1" ]; + trusted_domains = ["cloud.${srv.domain}"]; + overwriteprotocol = "https"; enabledPreviewProviders = [ "OC\\Preview\\BMP" "OC\\Preview\\GIF" @@ -124,30 +97,73 @@ in { adminpassFile = cfg.adminpassFile; }; }; + users.groups.nextcloud.members = [ + config.services.caddy.user + ]; services = { - nginx = { - virtualHosts.nextcloud = { - useACMEHost = srv.domainPublic; - listen = [ - { - addr = "127.0.0.1"; - port = 8083; - } - ]; - extraConfig = '' - add_header Referrer-Policy "no-referrer" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Download-Options "noopen" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Permitted-Cross-Domain-Policies "none" always; - add_header X-Robots-Tag "none" always; - add_header X-XSS-Protection "1; mode=block" always; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains;"; + nginx.enable = false; - access_log /var/log/nginx/nextcloud.access.log; - error_log /var/log/nginx/nextcloud.error.log; - ''; - }; + phpfpm.pools.nextcloud.settings = { + "listen.owner" = config.services.caddy.user; + "listen.group" = config.services.caddy.group; + }; + + caddy.virtualHosts.${cfg.url} = let + webroot = config.services.nginx.virtualHosts.nextcloud.root; + in { + useACMEHost = srv.domain; + extraConfig = '' + encode zstd gzip + + root * ${webroot} + + redir /.well-known/carddav /remote.php/dav 301 + redir /.well-known/caldav /remote.php/dav 301 + redir /.well-known/* /index.php{uri} 301 + redir /remote/* /remote.php{uri} 301 + + header { + Strict-Transport-Security max-age=31536000 + Permissions-Policy interest-cohort=() + X-Content-Type-Options nosniff + X-Frame-Options SAMEORIGIN + Referrer-Policy no-referrer + X-XSS-Protection "1; mode=block" + X-Permitted-Cross-Domain-Policies none + X-Robots-Tag "noindex, nofollow" + -X-Powered-By + } + + php_fastcgi unix/${config.services.phpfpm.pools.nextcloud.socket} { + root ${webroot} + env front_controller_active true + env modHeadersAvailable true + } + + @forbidden { + path /build/* /tests/* /config/* /lib/* /3rdparty/* /templates/* /data/* + path /.* /autotest* /occ* /issue* /indie* /db_* /console* + not path /.well-known/* + } + error @forbidden 404 + + @immutable { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + query v=* + } + header @immutable Cache-Control "max-age=15778463, immutable" + + @static { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + not query v=* + } + header @static Cache-Control "max-age=15778463" + + @woff2 path *.woff2 + header @woff2 Cache-Control "max-age=604800" + + file_server + ''; }; }; server.postgresql.databases = [