feat(ente): move server state to persistent data directory
This commit is contained in:
parent
27d34fcea0
commit
1925039252
5 changed files with 296 additions and 1 deletions
|
|
@ -38,6 +38,7 @@ let
|
|||
|
||||
packageSet = pkgs: {
|
||||
codeberg-themes = pkgs.callPackage ../packages/codeberg-themes { };
|
||||
ente-server = pkgs.callPackage ../packages/ente-server { };
|
||||
ente-web-auth = pkgs.callPackage ../packages/ente-web-auth { };
|
||||
linkwarden = pkgs.callPackage ../packages/linkwarden { };
|
||||
redlib = pkgs.callPackage ../packages/redlib { };
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ let
|
|||
|
||||
enteApp = cfg.package.override {
|
||||
extraBuildEnv = {
|
||||
NEXT_PUBLIC_ENTE_ENDPOINT = "https://ente.monapona.de";
|
||||
NEXT_PUBLIC_ENTE_ENDPOINT = cfg.apiEndpoint;
|
||||
NEXT_TELEMETRY_DISABLED = "1";
|
||||
};
|
||||
};
|
||||
|
|
@ -33,6 +33,12 @@ in
|
|||
default = "ente.stahl.sh";
|
||||
};
|
||||
|
||||
apiEndpoint = mkOption {
|
||||
description = "The public Ente API endpoint used by the Auth frontend.";
|
||||
type = types.str;
|
||||
default = "https://ente.stahl.sh/api";
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = mkEnabledOption "Enable nginx for this service.";
|
||||
};
|
||||
|
|
|
|||
229
modules/nixos/services/ente-server/default.nix
Normal file
229
modules/nixos/services/ente-server/default.nix
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
namespace,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with lib.${namespace};
|
||||
let
|
||||
cfg = config.${namespace}.services.ente-server;
|
||||
sopsCfg = config.${namespace}.system.sops;
|
||||
in
|
||||
{
|
||||
options.${namespace}.services.ente-server = {
|
||||
enable = mkEnableOption "native Ente Auth backend server";
|
||||
|
||||
package = mkOption {
|
||||
description = "The Ente server package to run.";
|
||||
type = types.package;
|
||||
default = pkgs.${namespace}.ente-server;
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
description = "Public domain of the Ente Auth frontend and backend.";
|
||||
type = types.str;
|
||||
default = "ente.stahl.sh";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
description = "Local TCP port the Ente server listens on.";
|
||||
type = types.port;
|
||||
default = 6789;
|
||||
};
|
||||
|
||||
secretsFile = mkOption {
|
||||
description = "SOPS file containing the Ente server secrets.";
|
||||
type = types.path;
|
||||
default = sopsCfg.secretsDir + "/blarm-ente-server.yaml";
|
||||
};
|
||||
|
||||
credentialsFile = mkOption {
|
||||
description = "Rendered Ente server credentials YAML file.";
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
default = config.sops.templates."ente-server-credentials.yaml".path;
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
description = "Persistent state directory for the Ente server.";
|
||||
type = types.path;
|
||||
default = "/data/ente";
|
||||
};
|
||||
|
||||
database = {
|
||||
name = mkOption {
|
||||
description = "PostgreSQL database name for Ente.";
|
||||
type = types.str;
|
||||
default = "ente";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
description = "PostgreSQL user for Ente. This must match the systemd service user for peer auth.";
|
||||
type = types.str;
|
||||
default = "ente";
|
||||
};
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = mkEnabledOption "Enable nginx reverse proxy for Ente server.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.database.name == cfg.database.user;
|
||||
message = "awesome-flake.services.ente-server.database.name must match database.user because PostgreSQL ensureDBOwnership requires a database with the same name as the owner.";
|
||||
}
|
||||
];
|
||||
|
||||
${namespace} = {
|
||||
system.sops = enabled;
|
||||
services.acme.enable = mkIf cfg.nginx.enable true;
|
||||
};
|
||||
|
||||
sops.secrets = {
|
||||
"ente-server/key/encryption" = {
|
||||
format = "yaml";
|
||||
key = "ente/key/encryption";
|
||||
sopsFile = cfg.secretsFile;
|
||||
};
|
||||
"ente-server/key/hash" = {
|
||||
format = "yaml";
|
||||
key = "ente/key/hash";
|
||||
sopsFile = cfg.secretsFile;
|
||||
};
|
||||
"ente-server/jwt/secret" = {
|
||||
format = "yaml";
|
||||
key = "ente/jwt/secret";
|
||||
sopsFile = cfg.secretsFile;
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."ente-server-credentials.yaml" = {
|
||||
owner = cfg.database.user;
|
||||
group = "ente";
|
||||
mode = "0400";
|
||||
restartUnits = [ "ente-server.service" ];
|
||||
content = ''
|
||||
# Generated by sops-nix. Do not edit manually.
|
||||
# For Ente Auth only, no S3 section is required.
|
||||
http:
|
||||
use-tls: false
|
||||
port: ${toString cfg.port}
|
||||
|
||||
db:
|
||||
# lib/pq treats an absolute host path as a PostgreSQL Unix socket directory.
|
||||
host: /run/postgresql
|
||||
port: 5432
|
||||
name: ${cfg.database.name}
|
||||
user: ${cfg.database.user}
|
||||
password: ""
|
||||
sslmode: disable
|
||||
|
||||
apps:
|
||||
accounts: https://${cfg.domain}
|
||||
|
||||
key:
|
||||
encryption: ${config.sops.placeholder."ente-server/key/encryption"}
|
||||
hash: ${config.sops.placeholder."ente-server/key/hash"}
|
||||
|
||||
jwt:
|
||||
secret: ${config.sops.placeholder."ente-server/jwt/secret"}
|
||||
'';
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.nginx.enable [
|
||||
80
|
||||
443
|
||||
];
|
||||
|
||||
users.groups.ente = { };
|
||||
users.users.${cfg.database.user} = {
|
||||
isSystemUser = true;
|
||||
group = "ente";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.dataDir} 0700 ${cfg.database.user} ente -"
|
||||
];
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = cfg.database.user;
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services.ente-server = {
|
||||
description = "Ente Auth backend server";
|
||||
after = [
|
||||
"postgresql.service"
|
||||
"postgresql-setup.service"
|
||||
];
|
||||
requires = [ "postgresql.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
environment = {
|
||||
ENVIRONMENT = "local";
|
||||
ENTE_CREDENTIALS_FILE = cfg.credentialsFile;
|
||||
GIN_MODE = "release";
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/museum";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/test -r ${lib.escapeShellArg cfg.credentialsFile}";
|
||||
User = cfg.database.user;
|
||||
Group = "ente";
|
||||
WorkingDirectory = "${cfg.package}/share/ente-server";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
DevicePolicy = "closed";
|
||||
LockPersonality = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = mkIf cfg.nginx.enable {
|
||||
enable = true;
|
||||
virtualHosts."${cfg.domain}" = {
|
||||
locations = {
|
||||
"/api".return = "301 /api/";
|
||||
"/api/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.port}/";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
38
packages/ente-server/default.nix
Normal file
38
packages/ente-server/default.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
lib,
|
||||
buildGoModule,
|
||||
fetchFromGitHub,
|
||||
}:
|
||||
|
||||
buildGoModule (finalAttrs: {
|
||||
pname = "ente-server";
|
||||
version = "4.4.25";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "ente-io";
|
||||
repo = "ente";
|
||||
tag = "auth-v${finalAttrs.version}";
|
||||
hash = "sha256-LmgfqLibMnL9N+5bv2MoTeR0xojqSgtIf9Bv/arjenk=";
|
||||
};
|
||||
|
||||
sourceRoot = "${finalAttrs.src.name}/server";
|
||||
|
||||
subPackages = [ "cmd/museum" ];
|
||||
vendorHash = "sha256-Nbh9fs+43e1iE1ujr9T5vu7K1QscG+jdq5+iad4HkDc=";
|
||||
|
||||
env.CGO_ENABLED = 0;
|
||||
|
||||
postInstall = ''
|
||||
install -d "$out/share/ente-server"
|
||||
cp -r configurations migrations mail-templates web-templates "$out/share/ente-server/"
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Ente server backend for Ente Auth";
|
||||
homepage = "https://ente.io/";
|
||||
changelog = "https://github.com/ente-io/ente/releases";
|
||||
license = lib.licenses.agpl3Only;
|
||||
mainProgram = "museum";
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
})
|
||||
21
secrets/blarm-ente-server.yaml
Normal file
21
secrets/blarm-ente-server.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
ente:
|
||||
key:
|
||||
encryption: ENC[AES256_GCM,data:8Fj9t5pAx+r8kggRvdCCp3IGTvO+0GGu7dNlOyKyRiXQfpuqtJDcl47Tc68=,iv:2Xo2ZHsnxoXJPaaQG8hzvieMSakELwyKjDBUvFcL5mI=,tag:qTNpHIQvvjaKrq7EBXUivw==,type:str]
|
||||
hash: ENC[AES256_GCM,data:dKYUSzqY9Sn27ZbSLbbYmV4ccMt8mGMuTC+QI85qGRnhV3ZQ3LDRrJdLSr9zBM9xTHOA7QzpHsCKuPY1fLnzyEdScTQnuw+m3YEMOLfDFm5XcrfnrGA0/w==,iv:FDcF1NzzRrmlsIPXvDu0BEEvO76aZ++qczVWzhhtVsM=,tag:RMDdmfHwY9ReKiE50ls9tQ==,type:str]
|
||||
jwt:
|
||||
secret: ENC[AES256_GCM,data:qT1fMW/q6XD5tCOM938TkkBMQsx42FEfA9UDP0ahKhRCc2A1E768+rg98Gw=,iv:8dYDVNmOibzDBVaAkaTqTcQfJvBxWO3KqdkISULU7AY=,tag:u+04smg8lzA2MhIV425eZw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4ZkMvK2hJNVVxOHVhTmlD
|
||||
aXZSd3dQeklSMXFJWW5BVzlhOXZNa3pZdkFFCnA3WXlXL0RCM0R3aTl6RGM0RURR
|
||||
M3N5Z1dweWlZT09zMTZOMXZwWHF1ZzgKLS0tIFZVS3BmakNGWThLRXZwQWRBbk05
|
||||
YUlsR1paWnF3cGVON25raVpMVHFqdjQKOJsEsUDK3bNKviXfRZd0+6c24/HKy4Jp
|
||||
6qY6LiB8dvQXI96jU7qF2tkc2vvlUC7yoRzRTSjztdTplLv6XBvQFg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age132m0pg4utk3cjve2lgcjffvz7cevl0fq5krufu9sgud7wu2wgurqk49kgl
|
||||
lastmodified: "2026-09-03T12:13:44Z"
|
||||
mac: ENC[AES256_GCM,data:wzmZnYF2f00qvjIk1UzauuX8wRQPxtvR3NJvjx9zcAHb1J05nUvPGH0iDnBOWjR9NGyMyxdpCBq/VaYyOYGi0GuUHs4oFYVuvkRxIceP71cEGtYbK1ghACL+hMMf+QtLZy6KZDVm3LOb8hqy4x+X4BDJqRZUxOWy7pFaV9pg1Ao=,iv:wkNYb01vGDtVCdUjfJ3mXW982eVfmy/VhmknbX+37SI=,tag:UQfqqYHyNyAjrVhXKR+J3g==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.13.3
|
||||
Loading…
Add table
Add a link
Reference in a new issue