nextcloud: Use a hardened systemd unit instead of a container
This commit is contained in:
		
							parent
							
								
									6a81ce4c1d
								
							
						
					
					
						commit
						d6bb65f739
					
				
					 4 changed files with 68 additions and 214 deletions
				
			
		|  | @ -9,6 +9,7 @@ | ||||||
|     ./services/nextcloud.nix |     ./services/nextcloud.nix | ||||||
|     ./services/webserver.nix |     ./services/webserver.nix | ||||||
|     ./services/starbound.nix |     ./services/starbound.nix | ||||||
|  |     ./services/postgres.nix | ||||||
|     ./ids.nix |     ./ids.nix | ||||||
|     ./sops.nix |     ./sops.nix | ||||||
|   ]; |   ]; | ||||||
|  | @ -82,7 +83,6 @@ | ||||||
|     in { |     in { | ||||||
|       "${domain}" = proxyPassToPort 3002 {serverAliases = ["www.${domain}"];}; |       "${domain}" = proxyPassToPort 3002 {serverAliases = ["www.${domain}"];}; | ||||||
|       "gitea.${domain}" = proxyPassToPort 3000 {}; |       "gitea.${domain}" = proxyPassToPort 3000 {}; | ||||||
|       "nextcloud.${domain}" = proxyPassToPort 3001 {}; |  | ||||||
|     }; |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,167 +0,0 @@ | ||||||
| worker_processes auto; |  | ||||||
| 
 |  | ||||||
| error_log  /var/log/nginx/error.log warn; |  | ||||||
| pid        /var/run/nginx.pid; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| events { |  | ||||||
|     worker_connections  1024; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| http { |  | ||||||
|     include       /etc/nginx/mime.types; |  | ||||||
|     default_type  application/octet-stream; |  | ||||||
| 
 |  | ||||||
|     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' |  | ||||||
|                       '$status $body_bytes_sent "$http_referer" ' |  | ||||||
|                       '"$http_user_agent" "$http_x_forwarded_for"'; |  | ||||||
| 
 |  | ||||||
|     access_log  /var/log/nginx/access.log  main; |  | ||||||
| 
 |  | ||||||
|     sendfile        on; |  | ||||||
|     #tcp_nopush     on; |  | ||||||
| 
 |  | ||||||
|     keepalive_timeout  65; |  | ||||||
| 
 |  | ||||||
|     #gzip  on; |  | ||||||
| 
 |  | ||||||
|     upstream php-handler { |  | ||||||
|         server localhost:9000; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     server { |  | ||||||
|         listen 80; |  | ||||||
| 
 |  | ||||||
|         # HSTS settings |  | ||||||
|         # WARNING: Only add the preload option once you read about |  | ||||||
|         # the consequences in https://hstspreload.org/. This option |  | ||||||
|         # will add the domain to a hardcoded list that is shipped |  | ||||||
|         # in all major browsers and getting removed from this list |  | ||||||
|         # could take several months. |  | ||||||
|         #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; |  | ||||||
| 
 |  | ||||||
|         # HTTP response headers borrowed from Nextcloud `.htaccess` |  | ||||||
|         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; |  | ||||||
| 
 |  | ||||||
|         # Remove X-Powered-By, which is an information leak |  | ||||||
|         fastcgi_hide_header X-Powered-By; |  | ||||||
| 
 |  | ||||||
|         # Path to the root of your installation |  | ||||||
|         root /var/www/html; |  | ||||||
| 
 |  | ||||||
|         # Specify how to handle directories -- specifying `/index.php$request_uri` |  | ||||||
|         # here as the fallback means that Nginx always exhibits the desired behaviour |  | ||||||
|         # when a client requests a path that corresponds to a directory that exists |  | ||||||
|         # on the server. In particular, if that directory contains an index.php file, |  | ||||||
|         # that file is correctly served; if it doesn't, then the request is passed to |  | ||||||
|         # the front-end controller. This consistent behaviour means that we don't need |  | ||||||
|         # to specify custom rules for certain paths (e.g. images and other assets, |  | ||||||
|         # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus |  | ||||||
|         # `try_files $uri $uri/ /index.php$request_uri` |  | ||||||
|         # always provides the desired behaviour. |  | ||||||
|         index index.php index.html /index.php$request_uri; |  | ||||||
| 
 |  | ||||||
|         # Rule borrowed from `.htaccess` to handle Microsoft DAV clients |  | ||||||
|         location = / { |  | ||||||
|             if ( $http_user_agent ~ ^DavClnt ) { |  | ||||||
|                 return 302 /remote.php/webdav/$is_args$args; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         location = /robots.txt { |  | ||||||
|             allow all; |  | ||||||
|             log_not_found off; |  | ||||||
|             access_log off; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Make a regex exception for `/.well-known` so that clients can still |  | ||||||
|         # access it despite the existence of the regex rule |  | ||||||
|         # `location ~ /(\.|autotest|...)` which would otherwise handle requests |  | ||||||
|         # for `/.well-known`. |  | ||||||
|         location ^~ /.well-known { |  | ||||||
|             # The rules in this block are an adaptation of the rules |  | ||||||
|             # in `.htaccess` that concern `/.well-known`. |  | ||||||
| 
 |  | ||||||
|             location = /.well-known/carddav { return 301 /remote.php/dav/; } |  | ||||||
|             location = /.well-known/caldav  { return 301 /remote.php/dav/; } |  | ||||||
| 
 |  | ||||||
|             location /.well-known/acme-challenge    { try_files $uri $uri/ =404; } |  | ||||||
|             location /.well-known/pki-validation    { try_files $uri $uri/ =404; } |  | ||||||
| 
 |  | ||||||
|             # Let Nextcloud's API for `/.well-known` URIs handle all other |  | ||||||
|             # requests by passing them to the front-end controller. |  | ||||||
|             return 301 /index.php$request_uri; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # set max upload size |  | ||||||
|         client_max_body_size 10G; |  | ||||||
|         fastcgi_buffers 64 4K; |  | ||||||
| 
 |  | ||||||
|         # Enable gzip but do not remove ETag headers |  | ||||||
|         gzip on; |  | ||||||
|         gzip_vary on; |  | ||||||
|         gzip_comp_level 4; |  | ||||||
|         gzip_min_length 256; |  | ||||||
|         gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; |  | ||||||
|         gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; |  | ||||||
| 
 |  | ||||||
|         # Pagespeed is not supported by Nextcloud, so if your server is built |  | ||||||
|         # with the `ngx_pagespeed` module, uncomment this line to disable it. |  | ||||||
|         #pagespeed off; |  | ||||||
| 
 |  | ||||||
|         # Rules borrowed from `.htaccess` to hide certain paths from clients |  | ||||||
|         location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; } |  | ||||||
|         location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; } |  | ||||||
| 
 |  | ||||||
|         # Ensure this block, which passes PHP files to the PHP process, is above the blocks |  | ||||||
|         # which handle static assets (as seen below). If this block is not declared first, |  | ||||||
|         # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php` |  | ||||||
|         # to the URI, resulting in a HTTP 500 error response. |  | ||||||
|         location ~ \.php(?:$|/) { |  | ||||||
|             fastcgi_split_path_info ^(.+?\.php)(/.*)$; |  | ||||||
|             set $path_info $fastcgi_path_info; |  | ||||||
| 
 |  | ||||||
|             try_files $fastcgi_script_name =404; |  | ||||||
| 
 |  | ||||||
|             include fastcgi_params; |  | ||||||
|             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; |  | ||||||
|             fastcgi_param PATH_INFO $path_info; |  | ||||||
|             #fastcgi_param HTTPS on; |  | ||||||
| 
 |  | ||||||
|             fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice |  | ||||||
|             fastcgi_param front_controller_active true;     # Enable pretty urls |  | ||||||
|             fastcgi_pass php-handler; |  | ||||||
| 
 |  | ||||||
|             fastcgi_intercept_errors on; |  | ||||||
|             fastcgi_request_buffering off; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         location ~ \.(?:css|js|svg|gif)$ { |  | ||||||
|             try_files $uri /index.php$request_uri; |  | ||||||
|             expires 6M;         # Cache-Control policy borrowed from `.htaccess` |  | ||||||
|             access_log off;     # Optional: Don't log access to assets |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         location ~ \.woff2?$ { |  | ||||||
|             try_files $uri /index.php$request_uri; |  | ||||||
|             expires 7d;         # Cache-Control policy borrowed from `.htaccess` |  | ||||||
|             access_log off;     # Optional: Don't log access to assets |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         # Rule borrowed from `.htaccess` |  | ||||||
|         location /remote { |  | ||||||
|             return 301 /remote.php$request_uri; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         location / { |  | ||||||
|             try_files $uri $uri/ /index.php$request_uri; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,53 +1,43 @@ | ||||||
| {config, ...}: { | { | ||||||
|   virtualisation.pods.nextcloud = { |   pkgs, | ||||||
|     hostname = "nextcloud.tlater.net"; |   config, | ||||||
|     publish = ["3001:80"]; |   ... | ||||||
|     network = "slirp4netns"; | }: let | ||||||
|  |   inherit (pkgs) fetchNextcloudApp; | ||||||
|  |   nextcloud = pkgs.nextcloud23; | ||||||
|  |   hostName = "nextcloud.${config.services.nginx.domain}"; | ||||||
|  | in { | ||||||
|  |   services.nextcloud = { | ||||||
|  |     inherit hostName; | ||||||
| 
 | 
 | ||||||
|     containers = { |     package = nextcloud; | ||||||
|       nextcloud = { |     enable = true; | ||||||
|         image = "nextcloud:fpm-alpine"; |     maxUploadSize = "2G"; | ||||||
|         dependsOn = ["postgres"]; |     https = true; | ||||||
|         volumes = [ |  | ||||||
|           "nextcloud-root:/var/www/html" |  | ||||||
|           "nextcloud-apps:/var/www/html/custom_apps" |  | ||||||
|           "nextcloud-config:/var/www/html/config" |  | ||||||
|           "nextcloud-data:/var/www/html/data" |  | ||||||
|         ]; |  | ||||||
|         environment = { |  | ||||||
|           POSTGRES_DB = "nextcloud"; |  | ||||||
|           POSTGRES_USER = "nextcloud"; |  | ||||||
|           POSTGRES_HOST = "localhost"; |  | ||||||
|           OVERWRITEPROTOCOL = "https"; |  | ||||||
|           TRUSTED_PROXIES = "127.0.0.1"; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 | 
 | ||||||
|       cron = { |     config = { | ||||||
|         image = "nextcloud:fpm-alpine"; |       overwriteProtocol = "https"; | ||||||
|         entrypoint = "/cron.sh"; |  | ||||||
|         dependsOn = ["postgres" "nextcloud"]; |  | ||||||
|         extraOptions = ["--volumes-from=nextcloud-nextcloud"]; |  | ||||||
|       }; |  | ||||||
| 
 | 
 | ||||||
|       nginx = { |       dbtype = "pgsql"; | ||||||
|         image = "nginx:alpine"; |       dbhost = "/run/postgresql"; | ||||||
|         dependsOn = ["nextcloud"]; |  | ||||||
|         volumes = [ |  | ||||||
|           "nextcloud-root:/var/www/html:ro" |  | ||||||
|           "${./configs/nginx-nextcloud.conf}:/etc/nginx/nginx.conf:ro" |  | ||||||
|         ]; |  | ||||||
|         extraOptions = ["--volumes-from=nextcloud-nextcloud"]; |  | ||||||
|       }; |  | ||||||
| 
 | 
 | ||||||
|       postgres = { |       adminuser = "tlater"; | ||||||
|         image = "postgres:alpine"; |       adminpassFile = config.sops.secrets."nextcloud/tlater".path; | ||||||
|         environment = { | 
 | ||||||
|           POSTGRES_DB = "nextcloud"; |       defaultPhoneRegion = "AT"; | ||||||
|           POSTGRES_USER = "nextcloud"; |  | ||||||
|         }; |  | ||||||
|         volumes = ["nextcloud-postgres-14:/var/lib/postgresql/data"]; |  | ||||||
|       }; |  | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     # TODO(tlater): Add redis config. This will be much easier | ||||||
|  |     # starting with 22.11, since this will add an `extraOptions` where | ||||||
|  |     # the necessary redis config can go. | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   # Ensure that this service doesn't start before postgres is ready | ||||||
|  |   systemd.services.nextcloud-setup.after = ["postgresql.service"]; | ||||||
|  | 
 | ||||||
|  |   # Set up SSL | ||||||
|  |   services.nginx.virtualHosts."${hostName}" = { | ||||||
|  |     forceSSL = true; | ||||||
|  |     enableACME = true; | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								configuration/services/postgres.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								configuration/services/postgres.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | {pkgs, ...}: { | ||||||
|  |   services.postgresql = { | ||||||
|  |     package = pkgs.postgresql_14; | ||||||
|  |     enable = true; | ||||||
|  | 
 | ||||||
|  |     # Only enable connections via the unix socket, and check with the | ||||||
|  |     # OS to make sure the user matches the database name. | ||||||
|  |     # | ||||||
|  |     # See https://www.postgresql.org/docs/current/auth-pg-hba-conf.html | ||||||
|  |     authentication = '' | ||||||
|  |       local sameuser all peer | ||||||
|  |     ''; | ||||||
|  | 
 | ||||||
|  |     # Note: The following options with ensure.* are set-only; i.e., | ||||||
|  |     # when permissions/users/databases are removed from these lists, | ||||||
|  |     # that operation needs to be performed manually on the system as | ||||||
|  |     # well. | ||||||
|  |     ensureUsers = [ | ||||||
|  |       { | ||||||
|  |         name = "nextcloud"; | ||||||
|  |         ensurePermissions = { | ||||||
|  |           "DATABASE nextcloud" = "ALL PRIVILEGES"; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     ensureDatabases = [ | ||||||
|  |       "nextcloud" | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue