feat(nextcloud): tweaks to nextcloud

This commit is contained in:
2025-09-20 12:31:12 +02:00
parent 2e1d28450b
commit c63daec95c
10 changed files with 184 additions and 146 deletions

View File

@@ -77,7 +77,7 @@ in {
keycloakCloudflared.file = "${self}/secrets/keycloakCloudflared.age";
keycloakDbPasswordFile.file = "${self}/secrets/keycloakDbPasswordFile.age";
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
ocisCloudflared.file = "${self}/secrets/ocisCloudflared.age";
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
homepageEnvironment.file = "${self}/secrets/homepageEnvironment.age";

View File

@@ -39,6 +39,16 @@ in {
group = config.services.caddy.group;
environmentFile = getCloudflareCredentials config.networking.hostName;
};
certs.${config.server.domainPublic} = {
reloadServices = ["caddy.service"];
domain = "${config.server.domainPublic}";
extraDomainNames = ["*.${config.server.domainPublic}"];
dnsProvider = "cloudflare";
dnsResolver = "1.1.1.1:53";
dnsPropagationCheck = true;
group = config.services.caddy.group;
environmentFile = getCloudflareCredentials config.networking.hostName;
};
};
services.caddy = {
@@ -57,6 +67,17 @@ in {
redir https://{host}{uri}
'';
};
"http://${config.server.domainPublic}" = {
extraConfig = ''
redir https://{host}{uri}
'';
};
"http://*.${config.server.domainPublic}" = {
extraConfig = ''
redir https://{host}{uri}
'';
};
};
};
};

View File

@@ -1,14 +1,16 @@
{
lib,
config,
pkgs,
...
}:
let
}: let
hardDrives = [
"/dev/disk/by-label/data"
];
inherit (lib) mkOption types;
cfg = config.server;
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
in
{
in {
options.server = {
enable = lib.mkEnableOption "The server services and configuration variables";
email = mkOption {
@@ -25,6 +27,13 @@ in
Domain name to be used to access the server services via Caddy reverse proxy
'';
};
domainPublic = mkOption {
default = "";
type = types.str;
description = ''
Public domain name to be used to access the server services via Caddy reverse proxy
'';
};
user = lib.mkOption {
default = "share";
type = lib.types.str;
@@ -93,5 +102,17 @@ in
];
};
};
systemd.services.hd-idle = {
description = "External HD spin down daemon";
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "simple";
ExecStart = let
idleTime = toString 900;
hardDriveParameter = lib.strings.concatMapStringsSep " " (x: "-a ${x} -i ${idleTime}") hardDrives;
in "${pkgs.hd-idle}/bin/hd-idle -i 0 ${hardDriveParameter}";
};
};
};
}

View File

@@ -4,7 +4,7 @@
lib,
...
}: let
unit = "ocis";
unit = "nextcloud";
cfg = config.server.${unit};
srv = config.server;
in {
@@ -12,24 +12,24 @@ in {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
adminUser = lib.mkOption {
adminpassFile = lib.mkOption {
type = lib.types.path;
};
adminuser = lib.mkOption {
type = lib.types.str;
default = "cnst";
};
adminPass = lib.mkOption {
type = lib.types.path;
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "cloud.${srv.domain}";
default = "cloud.${srv.domainPublic}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "OCIS";
default = "Nextcloud";
};
homepage.description = lib.mkOption {
type = lib.types.str;
@@ -37,118 +37,114 @@ in {
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "owncloud.svg";
default = "nextcloud.svg";
};
homepage.category = lib.mkOption {
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"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
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 {
server = {
postgresql.databases = [
{
database = "ocis";
}
];
fail2ban = lib.mkIf config.server.fail2ban.enable {
jails = {
nextcloud = {
serviceName = "phpfm-nextcloud";
failRegex = "^.*Login failed:.*(Remote IP: <HOST>).*$";
};
services.nginx.virtualHosts."nextcloud".listen = [
{
addr = "127.0.0.1";
port = 8083;
}
];
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 = {
serviceName = "phpfpm-nextcloud";
failRegex = "^.*Login failed:.*(Remote IP: <HOST>).*$";
};
};
};
systemd.services.ocis.preStart = ''
${lib.getExe pkgs.ocis} init || true
'';
services = {
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://${config.services.ocis.address}:${toString config.services.ocis.port}";
};
services.${unit} = {
enable = true;
package = pkgs.nextcloud31;
hostName = "nextcloud";
configureRedis = true;
caching = {
redis = true;
};
${unit} = {
enable = true;
url = "https://${cfg.url}";
environment = let
cspFormat = pkgs.formats.yaml {};
cspConfig = {
directives = {
child-src = ["'self'"];
connect-src = [
"'self'"
"blob:"
"https://${srv.keycloak.url}"
];
default-src = ["'none'"];
font-src = ["'self'"];
frame-ancestors = ["'none'"];
frame-src = [
"'self'"
"blob:"
"https://embed.diagrams.net"
];
img-src = [
"'self'"
"data:"
"blob:"
];
manifest-src = ["'self'"];
media-src = ["'self'"];
object-src = [
"'self'"
"blob:"
];
script-src = [
"'self'"
"'unsafe-inline'"
];
style-src = [
"'self'"
"'unsafe-inline'"
];
};
};
in {
PROXY_AUTOPROVISION_ACCOUNTS = "true";
PROXY_ROLE_ASSIGNMENT_DRIVER = "oidc";
OCIS_OIDC_ISSUER = "https://${srv.keycloak.url}/realms/ownCloud";
PROXY_OIDC_REWRITE_WELLKNOWN = "true";
WEB_OIDC_CLIENT_ID = "ocis";
OCIS_LOG_LEVEL = "error";
PROXY_TLS = "false";
PROXY_USER_OIDC_CLAIM = "preferred_username";
PROXY_USER_CS3_CLAIM = "username";
OCIS_ADMIN_USER_ID = "";
OCIS_INSECURE = "false";
OCIS_EXCLUDE_RUN_SERVICES = "idp";
GRAPH_ASSIGN_DEFAULT_USER_ROLE = "false";
PROXY_CSP_CONFIG_FILE_LOCATION = toString (cspFormat.generate "csp.yaml" cspConfig);
GRAPH_USERNAME_MATCH = "none";
PROXY_ROLE_ASSIGNMENT_ENABLED = "true";
PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM = "realm_access.roles";
PROXY_ROLE_ASSIGNMENT_MAPPING = "ocisAdmin:admin,ocisUser:user";
};
occ = {
maintenance = "install";
};
database.createLocally = true;
maxUploadSize = "50G";
settings = {
trusted_proxies = ["127.0.0.1"];
trusted_domains = ["cloud.${srv.domainPublic}" "192.168.88.14"];
overwriteprotocol = "https";
overwritehost = "cloud.${srv.domainPublic}";
overwrite.cli.url = "https://cloud.${srv.domainPublic}";
# mail_smtpmode = "sendmail";
# mail_sendmailmode = "pipe";
# user_oidc = {
# allow_multiple_user_backends = 0;
# };
forwarded_for_headers = [
"HTTP_CF_CONNECTING_IP"
];
enabledPreviewProviders = [
"OC\\Preview\\BMP"
"OC\\Preview\\GIF"
"OC\\Preview\\JPEG"
"OC\\Preview\\Krita"
"OC\\Preview\\MarkDown"
"OC\\Preview\\MP3"
"OC\\Preview\\OpenDocument"
"OC\\Preview\\PNG"
"OC\\Preview\\TXT"
"OC\\Preview\\XBitmap"
"OC\\Preview\\HEIC"
];
};
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql";
dbname = "nextcloud";
adminuser = "cnst";
adminpassFile = cfg.adminpassFile;
};
};
services.caddy.virtualHosts."${srv.domainPublic}" = {
useACMEHost = srv.domainPublic;
extraConfig = ''
reverse_proxy http://127.0.0.1:8083
'';
};
server.postgresql.databases = [
{
database = "nextcloud";
}
];
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
};
}