2023-06-23 06:22:34 +02:00
{ config , pkgs , lib , . . . }:
let
cfg = config . shb . nextcloud ;
2023-07-16 00:09:54 +02:00
fqdn = " ${ cfg . subdomain } . ${ cfg . domain } " ;
2023-06-23 06:22:34 +02:00
in
{
options . shb . nextcloud = {
enable = lib . mkEnableOption " s e l f h o s t b l o c k s . n e x t c l o u d - s e r v e r " ;
2023-07-16 00:09:54 +02:00
subdomain = lib . mkOption {
type = lib . types . str ;
description = " S u b d o m a i n u n d e r w h i c h h o m e - a s s i s t a n t w i l l b e s e r v e d . " ;
example = " n e x t c l o u d " ;
} ;
domain = lib . mkOption {
description = lib . mdDoc " D o m a i n t o s e r v e s i t e s u n d e r . " ;
2023-06-23 06:22:34 +02:00
type = lib . types . str ;
2023-07-16 00:09:54 +02:00
example = " d o m a i n . c o m " ;
2023-06-23 06:22:34 +02:00
} ;
sopsFile = lib . mkOption {
type = lib . types . path ;
description = " S o p s f i l e l o c a t i o n " ;
example = " s e c r e t s / n e x t c l o u d . y a m l " ;
} ;
} ;
config = lib . mkIf cfg . enable {
users . users = {
nextcloud = {
name = " n e x t c l o u d " ;
group = " n e x t c l o u d " ;
isSystemUser = true ;
} ;
} ;
users . groups = {
nextcloud = {
members = [ " b a c k u p " ] ;
} ;
} ;
2023-08-10 05:40:38 +02:00
# LDAP is manually configured through
# https://github.com/lldap/lldap/blob/main/example_configs/nextcloud.md, see also
# https://docs.nextcloud.com/server/latest/admin_manual/configuration_user/user_auth_ldap.html
2023-08-12 08:30:04 +02:00
#
# Verify setup with:
# - On admin page
# - https://scan.nextcloud.com/
# - https://www.ssllabs.com/ssltest/
# As of writing this, we got no warning on admin page and A+ on both tests.
#
# Content-Security-Policy is hard. I spent so much trying to fix lingering issues with .js files
# not loading to realize those scripts are inserted by extensions. Doh.
2023-06-23 06:22:34 +02:00
services . nextcloud = {
enable = true ;
package = pkgs . nextcloud26 ;
# Enable php-fpm and nginx which will be behind the shb haproxy instance.
2023-07-16 00:09:54 +02:00
hostName = fqdn ;
2023-08-12 06:35:51 +02:00
nginx . hstsMaxAge = 31536000 ; # Needs > 1 year for https://hstspreload.org to be happy
2023-06-23 06:22:34 +02:00
config = {
dbtype = " p g s q l " ;
adminuser = " r o o t " ;
adminpassFile = " / r u n / s e c r e t s / n e x t c l o u d / a d m i n p a s s " ;
# Not using dbpassFile as we're using socket authentication.
defaultPhoneRegion = " U S " ;
trustedProxies = [ " 1 2 7 . 0 . 0 . 1 " ] ;
} ;
database . createLocally = true ;
# Enable caching using redis https://nixos.wiki/wiki/Nextcloud#Caching.
configureRedis = true ;
caching . apcu = false ;
# https://docs.nextcloud.com/server/26/admin_manual/configuration_server/caching_configuration.html
caching . redis = true ;
# Adds appropriate nginx rewrite rules.
webfinger = true ;
2023-08-12 06:35:27 +02:00
# Very important for a bunch of scripts to load correctly. Otherwise you get Content-Security-Policy errors. See https://docs.nextcloud.com/server/13/admin_manual/configuration_server/harden_server.html#enable-http-strict-transport-security
https = true ;
2023-06-23 06:22:34 +02:00
extraOptions = {
2023-07-16 00:09:54 +02:00
" o v e r w r i t e . c l i . u r l " = " h t t p s : / / " + fqdn ;
" o v e r w r i t e h o s t " = fqdn ;
2023-08-12 01:38:13 +02:00
# 'trusted_domains' needed otherwise we get this issue https://help.nextcloud.com/t/the-polling-url-does-not-start-with-https-despite-the-login-url-started-with-https/137576/2
" t r u s t e d _ d o m a i n s " = [ fqdn ] ;
" o v e r w r i t e p r o t o c o l " = " h t t p s " ; # Needed if behind a reverse_proxy
" o v e r w r i t e c o n d a d d r " = " " ; # We need to set it to empty otherwise overwriteprotocol does not work.
2023-06-23 06:22:34 +02:00
} ;
phpOptions = {
# The OPcache interned strings buffer is nearly full with 8, bump to 16.
2023-07-30 07:13:09 +02:00
catch_workers_output = " y e s " ;
display_errors = " s t d e r r " ;
error_reporting = " E _ A L L & ~ E _ D E P R E C A T E D & ~ E _ S T R I C T " ;
expose_php = " O f f " ;
" o p c a c h e . e n a b l e _ c l i " = " 1 " ;
" o p c a c h e . f a s t _ s h u t d o w n " = " 1 " ;
2023-06-23 06:22:34 +02:00
" o p c a c h e . i n t e r n e d _ s t r i n g s _ b u f f e r " = " 1 6 " ;
2023-07-30 07:13:09 +02:00
" o p c a c h e . m a x _ a c c e l e r a t e d _ f i l e s " = " 1 0 0 0 0 " ;
" o p c a c h e . m e m o r y _ c o n s u m p t i o n " = " 1 2 8 " ;
" o p c a c h e . r e v a l i d a t e _ f r e q " = " 1 " ;
" o p e n s s l . c a f i l e " = " / e t c / s s l / c e r t s / c a - c e r t i f i c a t e s . c r t " ;
short_open_tag = " O f f " ;
# Needed to avoid corruption per https://docs.nextcloud.com/server/21/admin_manual/configuration_server/caching_configuration.html#id2
" r e d i s . s e s s i o n . l o c k i n g _ e n a b l e d " = " 1 " ;
" r e d i s . s e s s i o n . l o c k _ r e t r i e s " = " - 1 " ;
" r e d i s . s e s s i o n . l o c k _ w a i t _ t i m e " = " 1 0 0 0 0 " ;
2023-06-23 06:22:34 +02:00
} ;
} ;
# Secret needed for services.nextcloud.config.adminpassFile.
sops . secrets . " n e x t c l o u d / a d m i n p a s s " = {
inherit ( cfg ) sopsFile ;
mode = " 0 4 4 0 " ;
owner = " n e x t c l o u d " ;
group = " n e x t c l o u d " ;
} ;
2023-07-16 00:09:54 +02:00
services . nginx . virtualHosts . ${ fqdn } = {
# listen = [ { addr = "0.0.0.0"; port = 443; } ];
sslCertificate = " / v a r / l i b / a c m e / ${ cfg . domain } / c e r t . p e m " ;
sslCertificateKey = " / v a r / l i b / a c m e / ${ cfg . domain } / k e y . p e m " ;
2023-08-12 00:53:05 +02:00
forceSSL = true ;
2023-06-23 06:22:34 +02:00
} ;
systemd . services . phpfpm-nextcloud . serviceConfig = {
# Setup permissions needed for backups, as the backup user is member of the jellyfin group.
UMask = lib . mkForce " 0 0 2 7 " ;
} ;
# Sets up backup for Nextcloud.
shb . backup . instances . nextcloud = {
sourceDirectories = [
config . services . nextcloud . datadir
] ;
2023-07-22 18:54:19 +02:00
excludePatterns = [ " . r n d " ] ;
2023-06-23 06:22:34 +02:00
} ;
} ;
}