Add selfhosted services
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./mariadb
|
||||
./notification
|
||||
./redis
|
||||
./seadoc
|
||||
./server
|
||||
];
|
||||
|
||||
options.selfhosted.seafile = {
|
||||
targetName = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.targets."${common.backend}-${cfg.targetName}" = {
|
||||
unitConfig = {
|
||||
Description = "Root target for ${cfg.targetName}";
|
||||
};
|
||||
after = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
requires = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
partOf = [ "${common.backend}-${common.rootTarget.name}.target" ];
|
||||
wantedBy = [ "${common.backend}-${common.rootTarget.name}.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
sops.secrets = {
|
||||
"seafile/mysql_password" = { };
|
||||
};
|
||||
|
||||
sops.templates."seafile-db.env".content = ''
|
||||
MYSQL_ROOT_PASSWORD=${config.sops.placeholder."seafile/mysql_password"}
|
||||
MYSQL_LOG_CONSOLE=true
|
||||
MARIADB_AUTO_UPGRADE=1
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
hostDataPath = "${common.dataDir}/seafile";
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ];
|
||||
|
||||
options.selfhosted.seafile.mariadb = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers.${cfg.mariadb.name} = {
|
||||
image = "docker.io/mariadb:10.11";
|
||||
environmentFiles = [ config.sops.templates."seafile-db.env".path ];
|
||||
volumes = [
|
||||
"${hostDataPath}/mysql:/var/lib/mysql"
|
||||
];
|
||||
log-driver = "journald";
|
||||
extraOptions = [
|
||||
"--network=${common.network.name}"
|
||||
"--health-cmd=/usr/local/bin/healthcheck.sh --connect --mariadbupgrade --innodb_initialized"
|
||||
"--health-interval=20s"
|
||||
"--health-start-period=30s"
|
||||
"--health-timeout=5s"
|
||||
"--health-retries=10"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."${common.backend}-${cfg.mariadb.name}" = {
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 90 "always";
|
||||
};
|
||||
after = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
requires = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
partOf = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
wantedBy = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
preStart = ''
|
||||
mkdir -p ${hostDataPath}/mysql
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.seafile;
|
||||
in
|
||||
{
|
||||
sops.templates."seafile-notification.env".content = ''
|
||||
SEAFILE_MYSQL_DB_HOST=${cfg.mariadb.name}
|
||||
SEAFILE_MYSQL_DB_PORT=3306
|
||||
SEAFILE_MYSQL_DB_USER=seafile
|
||||
SEAFILE_MYSQL_DB_PASSWORD=${config.sops.placeholder."seafile/mysql_password"}
|
||||
SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db
|
||||
SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db
|
||||
JWT_PRIVATE_KEY=${config.sops.placeholder."seafile/jwt_private_key"}
|
||||
SEAFILE_LOG_TO_STDOUT=false
|
||||
NOTIFICATION_SERVER_LOG_LEVEL=info
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
hostDataPath = "${common.dataDir}/seafile";
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ];
|
||||
|
||||
options.selfhosted.seafile.notification = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
hostHttpPort = mkOption {
|
||||
type = types.port;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers.${cfg.notification.name} = {
|
||||
image = "docker.io/seafileltd/notification-server:13.0-latest";
|
||||
ports = [
|
||||
"0.0.0.0:${toString cfg.notification.hostHttpPort}:8083"
|
||||
];
|
||||
environmentFiles = [ config.sops.templates."seafile-notification.env".path ];
|
||||
volumes = [
|
||||
"${hostDataPath}/notification/logs:/shared/seafile/logs"
|
||||
];
|
||||
log-driver = "journald";
|
||||
extraOptions = [
|
||||
"--network=${common.network.name}"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."${common.backend}-${cfg.notification.name}" = {
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 90 "always";
|
||||
};
|
||||
after = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${cfg.mariadb.name}.service"
|
||||
"${common.backend}-${cfg.server.name}.service"
|
||||
];
|
||||
requires = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${cfg.mariadb.name}.service"
|
||||
"${common.backend}-${cfg.server.name}.service"
|
||||
];
|
||||
partOf = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
wantedBy = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
path = with pkgs; [ curl gawk ];
|
||||
preStart = ''
|
||||
echo "Waiting for Seafile server to be ready..."
|
||||
for i in {1..60}; do
|
||||
status=$(curl -sI --max-time 5 "http://localhost:${toString cfg.server.hostHttpPort}" | head -1 | awk '{print $2}')
|
||||
|
||||
if [[ "$status" =~ ^(200|301|302)$ ]]; then
|
||||
echo "Seafile server is up (HTTP $status, attempt $i)"
|
||||
break
|
||||
fi
|
||||
|
||||
echo "Seafile not ready yet (status: $status) ... ($i/60)"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
mkdir -p ${hostDataPath}/notification
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
sops.secrets = {
|
||||
"seafile/redis_password" = { };
|
||||
};
|
||||
|
||||
sops.templates."seafile-redis.env".content = ''
|
||||
REDIS_PASSWORD=${config.sops.placeholder."seafile/redis_password"}
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ];
|
||||
|
||||
options.selfhosted.seafile.redis = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers.${cfg.redis.name} = {
|
||||
image = "docker.io/redis:7";
|
||||
environmentFiles = [ config.sops.templates."seafile-redis.env".path ];
|
||||
cmd = [ "/bin/sh" "-c" "exec redis-server --requirepass \"$REDIS_PASSWORD\"" ];
|
||||
log-driver = "journald";
|
||||
extraOptions = [
|
||||
"--network=${common.network.name}"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."${common.backend}-${cfg.redis.name}" = {
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 90 "always";
|
||||
};
|
||||
after = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
requires = [ "${common.backend}-network-${common.network.name}.service" ];
|
||||
partOf = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
wantedBy = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.seafile;
|
||||
in
|
||||
{
|
||||
sops.templates."seadoc.env".content = ''
|
||||
DB_HOST=${cfg.mariadb.name}
|
||||
DB_PORT=3306
|
||||
DB_USER=seafile
|
||||
DB_PASSWORD=${config.sops.placeholder."seafile/mysql_password"}
|
||||
DB_NAME=seahub_db
|
||||
TIME_ZONE=${config.time.timeZone}
|
||||
JWT_PRIVATE_KEY=${config.sops.placeholder."seafile/jwt_private_key"}
|
||||
NON_ROOT=false
|
||||
SEAHUB_SERVICE_URL=http://${cfg.server.name}
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
hostDataPath = "${common.dataDir}/seafile";
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ];
|
||||
|
||||
options.selfhosted.seafile.seadoc = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
hostHttpPort = mkOption {
|
||||
type = types.port;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers.${cfg.seadoc.name} = {
|
||||
image = "docker.io/seafileltd/sdoc-server:2.0-latest";
|
||||
ports = [
|
||||
"0.0.0.0:${toString cfg.seadoc.hostHttpPort}:80"
|
||||
];
|
||||
volumes = [
|
||||
"${hostDataPath}/seadoc/shared:/shared"
|
||||
];
|
||||
environmentFiles = [ config.sops.templates."seadoc.env".path ];
|
||||
log-driver = "journald";
|
||||
extraOptions = [
|
||||
"--network=${common.network.name}"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."${common.backend}-${cfg.seadoc.name}" = {
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 90 "always";
|
||||
};
|
||||
after = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${cfg.mariadb.name}.service"
|
||||
];
|
||||
requires = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${cfg.mariadb.name}.service"
|
||||
];
|
||||
partOf = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
wantedBy = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
preStart = ''
|
||||
mkdir -p ${hostDataPath}/seadoc/shared
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
cfg = config.selfhosted.seafile;
|
||||
poCfg = config.selfhosted.pocket-id;
|
||||
domain = config.sops.placeholder."domains/serv";
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"seafile/admin_email" = { };
|
||||
"seafile/admin_password" = { };
|
||||
"seafile/client_id" = { };
|
||||
"seafile/client_secret" = { };
|
||||
"seafile/jwt_private_key" = { };
|
||||
};
|
||||
|
||||
sops.templates."seafile.env".content = ''
|
||||
SEAFILE_MYSQL_DB_HOST=${cfg.mariadb.name}
|
||||
SEAFILE_MYSQL_DB_PORT=3306
|
||||
SEAFILE_MYSQL_DB_USER=seafile
|
||||
SEAFILE_MYSQL_DB_PASSWORD=${config.sops.placeholder."seafile/mysql_password"}
|
||||
SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db
|
||||
SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db
|
||||
SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=seahub_db
|
||||
TIME_ZONE=${config.time.timeZone}
|
||||
INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${config.sops.placeholder."seafile/mysql_password"}
|
||||
INIT_SEAFILE_ADMIN_EMAIL=${config.sops.placeholder."seafile/admin_email"}
|
||||
INIT_SEAFILE_ADMIN_PASSWORD=${config.sops.placeholder."seafile/admin_password"}
|
||||
SEAFILE_SERVER_HOSTNAME=${cfg.server.subdomain}.${domain}
|
||||
SEAFILE_SERVER_PROTOCOL=https
|
||||
SEAFILE_SERVER_LETSENCRYPT=false
|
||||
SITE_ROOT=/
|
||||
NON_ROOT=false
|
||||
JWT_PRIVATE_KEY=${config.sops.placeholder."seafile/jwt_private_key"}
|
||||
SEAFILE_LOG_TO_STDOUT=false
|
||||
ENABLE_GO_FILESERVER=true
|
||||
ENABLE_SEADOC=true
|
||||
SEADOC_SERVER_URL=https://${cfg.server.subdomain}.${domain}/sdoc-server
|
||||
CACHE_PROVIDER=redis
|
||||
REDIS_HOST=${cfg.redis.name}
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=${config.sops.placeholder."seafile/redis_password"}
|
||||
ENABLE_NOTIFICATION_SERVER=true
|
||||
INNER_NOTIFICATION_SERVER_URL=http://${cfg.notification.name}:8083
|
||||
NOTIFICATION_SERVER_URL=https://${cfg.server.subdomain}.${domain}/notification
|
||||
ENABLE_SEAFILE_AI=false
|
||||
MD_FILE_COUNT_LIMIT=100000
|
||||
'';
|
||||
|
||||
sops.templates."seahub_settings.py".content = ''
|
||||
ENABLE_VIDEO_THUMBNAIL = True
|
||||
|
||||
ENABLE_OAUTH = True
|
||||
OAUTH_CREATE_UNKNOWN_USER = True
|
||||
OAUTH_ACTIVATE_USER_AFTER_CREATION = True
|
||||
OAUTH_ENABLE_INSECURE_TRANSPORT = False
|
||||
OAUTH_CLIENT_ID = "${config.sops.placeholder."seafile/client_id"}"
|
||||
OAUTH_CLIENT_SECRET = "${config.sops.placeholder."seafile/client_secret"}"
|
||||
OAUTH_REDIRECT_URL = "https://${cfg.server.subdomain}.${domain}/oauth/callback"
|
||||
OAUTH_PROVIDER = "pocket-id"
|
||||
OAUTH_PROVIDER_DOMAIN = "pocket-id"
|
||||
OAUTH_AUTHORIZATION_URL = "https://${poCfg.subdomain}.${domain}/authorize"
|
||||
OAUTH_TOKEN_URL = "https://${poCfg.subdomain}.${domain}/api/oidc/token"
|
||||
OAUTH_USER_INFO_URL = "https://${poCfg.subdomain}.${domain}/api/oidc/userinfo"
|
||||
OAUTH_SCOPE = [
|
||||
"openid",
|
||||
"profile",
|
||||
"email"
|
||||
]
|
||||
OAUTH_ATTRIBUTE_MAP = {
|
||||
"sub": (True, "uid"),
|
||||
"name": (False, "name"),
|
||||
"email": (False, "contact_email"),
|
||||
}
|
||||
CLIENT_SSO_VIA_LOCAL_BROWSER = True
|
||||
|
||||
ENABLE_WEBDAV_SECRET = True
|
||||
WEBDAV_SECRET_MIN_LENGTH = 8
|
||||
SERVICE_URL = "https://${cfg.server.subdomain}.${domain}"
|
||||
USE_X_FORWARDED_HOST = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
ALLOWED_HOSTS = [".${domain}"]
|
||||
CSRF_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SAMESITE = "Lax"
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
"https://${cfg.server.subdomain}.${domain}"
|
||||
]
|
||||
'';
|
||||
|
||||
sops.templates."seafdav.conf".content = ''
|
||||
[WEBDAV]
|
||||
enabled = true
|
||||
port = 8080
|
||||
debug = true
|
||||
share_name = /seafdav
|
||||
workers = 5
|
||||
timeout = 1200
|
||||
'';
|
||||
|
||||
sops.templates."seafile.conf".content = ''
|
||||
[quota]
|
||||
default = 100
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{ config, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
common = config.selfhosted.common;
|
||||
cfg = config.selfhosted.seafile;
|
||||
hostDataPath = "${common.dataDir}/seafile";
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ];
|
||||
|
||||
options.selfhosted.seafile.server = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
subdomain = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
hostHttpPort = mkOption {
|
||||
type = types.port;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers.${cfg.server.name} = {
|
||||
image = "docker.io/seafileltd/seafile-mc:13.0-latest";
|
||||
ports = [
|
||||
"0.0.0.0:${toString cfg.server.hostHttpPort}:80"
|
||||
];
|
||||
environmentFiles = [ config.sops.templates."seafile.env".path ];
|
||||
volumes = [
|
||||
"${hostDataPath}/server/shared:/shared"
|
||||
];
|
||||
log-driver = "journald";
|
||||
extraOptions = [
|
||||
"--network=${common.network.name}"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."${common.backend}-${cfg.server.name}" = {
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 90 "always";
|
||||
};
|
||||
after = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${config.selfhosted.seafile.mariadb.name}.service"
|
||||
"${common.backend}-${config.selfhosted.seafile.redis.name}.service"
|
||||
];
|
||||
requires = [
|
||||
"${common.backend}-network-${common.network.name}.service"
|
||||
"${common.backend}-${config.selfhosted.traefik.name}.service"
|
||||
"${common.backend}-${cfg.mariadb.name}.service"
|
||||
"${common.backend}-${cfg.redis.name}.service"
|
||||
];
|
||||
partOf = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
wantedBy = [ "${common.backend}-${cfg.targetName}.target" ];
|
||||
preStart = ''
|
||||
mkdir -p ${hostDataPath}/server/shared/seafile/conf
|
||||
|
||||
cp -f ${config.sops.templates."seahub_settings.py".path} \
|
||||
${hostDataPath}/server/shared/seafile/conf/seahub_settings.py
|
||||
cp -f ${config.sops.templates."seafdav.conf".path} \
|
||||
${hostDataPath}/server/shared/seafile/conf/seafdav.conf
|
||||
cp -f ${config.sops.templates."seafile.conf".path} \
|
||||
${hostDataPath}/server/shared/seafile/conf/seafile.conf
|
||||
chmod 644 ${hostDataPath}/server/shared/seafile/conf/{seafile.conf,seafdav.conf,seahub_settings.py}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user