1
0
Fork 0

add(acme,nginx): add certificate generation and nginx for the services

This replaces caddy and the port exposure, this is more efficent and
easier to manage in the future.
This commit is contained in:
Philipp 2025-05-25 00:32:54 +02:00
parent 7dd87536aa
commit 5792e478af
Signed by: Philipp
GPG key ID: 9EBD8439AFBAB750
9 changed files with 244 additions and 74 deletions

View file

@ -21,3 +21,7 @@ creation_rules:
key_groups:
- age:
- *primary
- path_regex: secrets/blarm-acme.env
key_groups:
- age:
- *primary

View file

@ -0,0 +1,38 @@
{
lib,
config,
namespace,
...
}:
with lib;
with lib.${namespace};
let
cfg = config.${namespace}.services.acme;
in
{
options.${namespace}.services.acme = {
enable = mkBoolOpt false "ACME";
};
config = mkIf cfg.enable {
security.acme = {
acceptTerms = true;
defaults.email = "admin+acme@stahl.sh";
certs."stahl.sh" = {
domain = "stahl.sh";
extraDomainNames = [ "*.stahl.sh" ];
dnsProvider = "infomaniak";
dnsPropagationCheck = true;
environmentFile = "/run/secrets/acme";
};
};
users.users.nginx.extraGroups = [ "acme" ];
sops.secrets.acme = {
format = "dotenv";
sopsFile = ../../../../secrets/blarm-acme.env;
};
};
}

View file

@ -13,6 +13,13 @@ in
{
options.${namespace}.services.cinny = {
enable = mkEnableOption "Cinny";
nginx = {
enable = mkEnableOption {
description = "Enable nginx for this service.";
type = types.bool;
default = true;
};
};
package = mkOption {
description = "The package of Cinny to use.";
@ -20,45 +27,44 @@ in
default = pkgs.cinny-unwrapped;
};
port = mkOption {
description = "The port to serve Cinny on.";
type = types.nullOr types.int;
default = 8686;
domain = mkOption {
description = "The domain to serve Cinny on.";
type = types.nullOr types.str;
default = "cinny.stahl.sh";
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [
cfg.port
80
443
];
services.caddy = {
awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true;
services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts.":${builtins.toString cfg.port}" = {
extraConfig = ''
root * ${cfg.package}
file_server
@index {
not path /index.html
not path /public/*
not path /assets/*
virtualHosts."${cfg.domain}" = {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/" = {
root = "${cfg.package}";
extraConfig = ''
rewrite ^/config.json$ /config.json break;
rewrite ^/manifest.json$ /manifest.json break;
not path /config.json
rewrite ^/sw.js$ /sw.js break;
rewrite ^/pdf.worker.min.js$ /pdf.worker.min.js break;
not path /manifest.json
not path /sw.js
rewrite ^/public/(.*)$ /public/$1 break;
rewrite ^/assets/(.*)$ /assets/$1 break;
not path /pdf.worker.min.js
not path /olm.wasm
path /*
}
rewrite /*/olm.wasm /olm.wasm
rewrite @index /index.html
'';
rewrite ^(.+)$ /index.html break;
'';
};
};
};
};
}

View file

@ -20,28 +20,41 @@ in
default = pkgs.awesome-flake.ente-web-auth;
};
port = mkOption {
description = "The port to serve Ente-Auth on.";
type = types.nullOr types.int;
default = 1338;
domain = mkOption {
description = "The domain to serve ente-auth on.";
type = types.nullOr types.str;
default = "ente.stahl.sh";
};
nginx = {
enable = mkEnableOption {
description = "Enable nginx for this service.";
type = types.bool;
default = true;
};
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [
cfg.port
networking.firewall.allowedTCPPorts = mkIf cfg.nginx.enable [
80
443
];
services.caddy = {
awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true;
services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts = {
":${builtins.toString cfg.port}" = {
extraConfig = ''
root * ${cfg.package}
file_server
'';
virtualHosts."${cfg.domain}" = {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/" = {
root = "${cfg.package}";
};
};
};
};
}

View file

@ -13,6 +13,13 @@ in
{
options.${namespace}.services.forgejo = {
enable = mkEnableOption "Forgejo";
nginx = {
enable = mkEnableOption {
description = "Enable nginx for this service.";
type = types.bool;
default = true;
};
};
package = mkOption {
description = "The package of Forgejo to use.";
@ -29,13 +36,13 @@ in
domain = mkOption {
description = "The domain to serve Forgejo on.";
type = types.nullOr types.str;
default = "git.monapona.dev";
default = "git.stahl.sh";
};
ssh_domain = mkOption {
description = "The domain to serve Forgejo on.";
type = types.nullOr types.str;
default = "monapona.dev";
default = "stahl.sh";
};
user = mkOption {
@ -47,7 +54,8 @@ in
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [
cfg.port
80
443
];
systemd.services.codeberg-themes = {
@ -78,7 +86,7 @@ in
server = {
DOMAIN = cfg.domain;
HTTP_PORT = cfg.port;
ROOT_URL = "https://git.monapona.dev";
ROOT_URL = "https://" + cfg.domain;
SSH_DOMAIN = cfg.ssh_domain;
};
ui = {
@ -87,5 +95,17 @@ in
};
};
};
awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true;
services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts."${cfg.domain}" = {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}";
};
};
};
}

View file

@ -21,6 +21,19 @@ in
options.${namespace}.services.linkwarden = {
enable = mkEnableOption "Linkwarden";
package = lib.mkPackageOption pkgs.awesome-flake "linkwarden" { };
nginx = {
enable = mkEnableOption {
description = "Enable nginx for this service.";
type = types.bool;
default = true;
};
};
domain = mkOption {
description = "The domain to serve linkwarden on.";
type = types.nullOr types.str;
default = "link.stahl.sh";
};
storageLocation = mkOption {
type = types.path;
@ -69,24 +82,22 @@ in
host = mkOption {
type = types.str;
default = "0.0.0.0";
default = "127.0.0.1";
description = "The host that Linkwarden will listen on.";
};
port = mkOption {
type = types.port;
default = 3000;
description = "The port that Linkwarden will listen on.";
};
openFirewall = mkOption {
type = types.bool;
default = true;
description = "Whether to open the Linkwarden port in the firewall";
};
user = mkOption {
type = types.str;
default = "linkwarden";
description = "The user Linkwarden should run as.";
};
group = mkOption {
type = types.str;
default = "linkwarden";
@ -99,25 +110,30 @@ in
// {
default = true;
};
createDB = mkEnableOption "the automatic creation of the database for Linkwarden." // {
default = true;
};
name = mkOption {
type = types.str;
default = "linkwarden";
description = "The name of the Linkwarden database.";
};
host = mkOption {
type = types.str;
default = "/run/postgresql";
example = "127.0.0.1";
description = "Hostname or address of the postgresql server. If an absolute path is given here, it will be interpreted as a unix socket path.";
};
port = mkOption {
type = types.port;
default = 5432;
description = "Port of the postgresql server.";
};
user = mkOption {
type = types.str;
default = "linkwarden";
@ -146,19 +162,25 @@ in
];
};
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
networking.firewall.allowedTCPPorts = [
80
443
];
${namespace}.services.linkwarden.environment = {
LINKWARDEN_HOST = cfg.host;
LINKWARDEN_PORT = toString cfg.port;
LINKWARDEN_CACHE_DIR = cfg.cacheLocation;
STORAGE_FOLDER = cfg.storageLocation;
NEXT_PUBLIC_DISABLE_REGISTRATION = mkIf (!cfg.enableRegistration) "true";
DATABASE_URL = mkIf isPostgresUnixSocket "postgresql://${lib.strings.escapeURL cfg.database.user}@localhost/${lib.strings.escapeURL cfg.database.name}?host=${cfg.database.host}";
DATABASE_PORT = toString cfg.database.port;
DATABASE_HOST = mkIf (!isPostgresUnixSocket) cfg.database.host;
DATABASE_NAME = cfg.database.name;
DATABASE_USER = cfg.database.user;
${namespace}.services = {
acme.enable = mkIf cfg.nginx.enable true;
linkwarden.environment = {
LINKWARDEN_HOST = cfg.host;
LINKWARDEN_PORT = toString cfg.port;
LINKWARDEN_CACHE_DIR = cfg.cacheLocation;
STORAGE_FOLDER = cfg.storageLocation;
NEXT_PUBLIC_DISABLE_REGISTRATION = mkIf (!cfg.enableRegistration) "true";
DATABASE_URL = mkIf isPostgresUnixSocket "postgresql://${lib.strings.escapeURL cfg.database.user}@localhost/${lib.strings.escapeURL cfg.database.name}?host=${cfg.database.host}";
DATABASE_PORT = toString cfg.database.port;
DATABASE_HOST = mkIf (!isPostgresUnixSocket) cfg.database.host;
DATABASE_NAME = cfg.database.name;
DATABASE_USER = cfg.database.user;
};
};
systemd.services.linkwarden = {
@ -221,6 +243,16 @@ in
};
users.groups = mkIf (cfg.group == "linkwarden") { linkwarden = { }; };
services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts."${cfg.domain}" = {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/".proxyPass = "http://:${cfg.host}" + builtins.toString cfg.port;
};
};
sops.secrets.linkwarden = {
format = "dotenv";
sopsFile = ../../../../secrets/blarm-linkwarden.env;

View file

@ -12,37 +12,86 @@ in
{
options.${namespace}.services.searxng = with types; {
enable = mkBoolOpt false "SearXNG";
redlib = mkBoolOpt true "Whether or not to enable redlib.";
domain = mkOption {
description = "The domain to serve searxng on.";
type = types.nullOr types.str;
default = "search.stahl.sh";
};
nginx = {
enable = mkEnableOption {
description = "Enable nginx for this service.";
type = types.bool;
default = true;
};
};
redlib = {
enable = mkEnableOption {
description = "Whether or not to enable redlib.";
type = type.bool;
default = true;
};
domain = mkOption {
description = "The domain to serve reddit on.";
type = types.nullOr types.str;
default = "reddit.stahl.sh";
};
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 1340 ];
networking.firewall.allowedTCPPorts = mkIf cfg.nginx.enable [
80
443
];
services.searx = {
enable = true;
environmentFile = "/run/secrets/searxng";
settings.server = {
port = "1340";
bind_address = "0.0.0.0";
bind_address = "127.0.0.1";
use_default_settings = true;
secret_key = "@secret_key@";
};
};
services.redlib = mkIf cfg.redlib {
services.redlib = mkIf cfg.redlib.enable {
enable = true;
address = "0.0.0.0";
address = "127.0.0.1";
port = 1341;
openFirewall = true;
};
services.searx.settings.searx = mkIf cfg.redlib {
services.searx.settings.searx = mkIf cfg.redlib.enable {
plugins.hostnames.SXNGPlugin.active = true;
};
services.searx.settings.hostnames.replace = mkIf cfg.redlib {
"(.*\.)?reddit\.com$" = "reddit.monapona.dev";
"(.*\.)?redd\.it$" = "reddit.monapona.dev";
services.searx.settings.hostnames.replace = mkIf cfg.redlib.enable {
"(.*\.)?reddit\.com$" = cfg.redlib.domain;
"(.*\.)?redd\.it$" = cfg.redlib.domain;
};
awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true;
services.nginx = mkIf cfg.nginx.enable {
enable = true;
virtualHosts = {
"${cfg.domain}" = {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/".proxyPass = "http://127.0.01:1340";
};
"${cfg.redlib.domain}" = mkIf cfg.redlib.enable {
forceSSL = true;
useACMEHost = "stahl.sh";
locations."/".proxyPass = "http://127.0.01:1341";
};
};
};
sops.secrets.searxng = {

View file

@ -13,7 +13,7 @@
monolith,
nodejs,
openssl,
playwright-driver,
#playwright-driver,
prisma,
prisma-engines,
}:
@ -41,7 +41,7 @@ let
in
stdenvNoCC.mkDerivation rec {
pname = "linkwarden";
version = "2.10.0";
version = "2.10.2";
src = fetchFromGitHub {
owner = "linkwarden";
@ -120,7 +120,6 @@ stdenvNoCC.mkDerivation rec {
--set-default PRISMA_QUERY_ENGINE_LIBRARY "${prisma-engines}/lib/libquery_engine.node" \
--set-default PRISMA_QUERY_ENGINE_BINARY "${prisma-engines}/bin/query-engine" \
--set-default PRISMA_SCHEMA_ENGINE_BINARY "${prisma-engines}/bin/schema-engine" \
--set-default PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH ${playwright-driver.browsers-chromium}/chromium-*/chrome-linux/chrome \
--set-default LINKWARDEN_CACHE_DIR /var/cache/linkwarden \
--set-default LINKWARDEN_HOST localhost \
--set-default LINKWARDEN_PORT 3000 \
@ -129,6 +128,8 @@ stdenvNoCC.mkDerivation rec {
runHook postInstall
'';
#--set-default PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH ${playwright-driver.browsers-chromium}/chromium-*/chrome-linux/chrome \
passthru.tests = {
inherit (nixosTests) linkwarden;
};

7
secrets/blarm-acme.env Normal file
View file

@ -0,0 +1,7 @@
INFOMANIAK_ACCESS_TOKEN=ENC[AES256_GCM,data:xwYJQZkiPktUcPaWEG2oNiBMCzL8jQm1HnjdO756LjFkqJzLKvmaJA6DvR7GbI3YFCYBXTDhwiy++2U5juvWTeVnQWlEE48IhSeKKVtnDfg=,iv:h/JPjTfypSwXV2mhZ5k9fkXWjvvH5+SsjlikSh8S3uU=,tag:QTSuvsp8Yteq4LroRZVE5g==,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSMUhBNFJVSklOWDYycjZx\nR3ZJSVpVZ3VoR3RJZmNwZVlZOWQ4SHRVTXdZCml6TXVpZU4zYVNlY295ejZJYU5m\ndG1JaTQxVnBncnVXSHRPYThvM1FMckkKLS0tIEQxaEI2R0JYTmNrbko0SXFEOGdK\nMkFQRVJ5WlB3a2FwMnBsdlNiTWE1a1EKMagGidGhLXp3XJAoY9TBcOjx+h7T06yQ\nC7wGzRtrYcVkUx6aEmcIg78MvgcD67QtjOMLDani9gC2DWTxlLmH1A==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age132m0pg4utk3cjve2lgcjffvz7cevl0fq5krufu9sgud7wu2wgurqk49kgl
sops_lastmodified=2025-05-24T12:52:22Z
sops_mac=ENC[AES256_GCM,data:452ZNGwzol6doKb1uG1KExqojiEv0yixGkxxB6x1Rn9S6RKEiaPu79MskN2MaSdyxNdvd8R5YiDE2AG1eE6FEO4nHWOhB014EG5HIqSHxkLvGyq521SxkyAsVxS+qwWUWBPzPDUMU3sgCLxOsMOzrPV+RDYyr01IRAvexXAdvZg=,iv:AQy1vG1jKZJ2kXd0sdZW6TWDsYZcyFwVO1rOosZi3KU=,tag:XScja+Z0yxny62vbpRtSjA==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.10.2