Initial proposal for momo infrastructure setup
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
b1d2bfef98
commit
f291e88d86
|
@ -16,7 +16,6 @@ in {
|
|||
./triton-vmtools.nix
|
||||
|
||||
./caddy.nix
|
||||
./drone.nix
|
||||
./keycloak.nix
|
||||
./gitea.nix
|
||||
./mailman.nix
|
||||
|
@ -27,11 +26,18 @@ in {
|
|||
|
||||
"${latestModulesPath}/services/misc/gitea.nix"
|
||||
];
|
||||
|
||||
disabledModules = [
|
||||
"services/misc/gitea.nix"
|
||||
];
|
||||
|
||||
config = {
|
||||
age.secrets.mailing-password = {
|
||||
file = "${self}/secrets/gitea-database-password.age";
|
||||
mode = "700";
|
||||
owner = "root";
|
||||
};
|
||||
|
||||
# # #
|
||||
# # # pub.solar options
|
||||
# # #
|
||||
|
@ -41,6 +47,16 @@ in {
|
|||
lite = true;
|
||||
};
|
||||
|
||||
pub-solar.infra-node = {
|
||||
mailing = {
|
||||
type = "smtp";
|
||||
user = "admin@momo.koeln";
|
||||
host = "mx2.greenbaum.cloud:465";
|
||||
from = ''"pub.solar git server" <gitea@pub.solar>'';
|
||||
passwordFile = config.age.secrets.mailing-password.path;
|
||||
};
|
||||
};
|
||||
|
||||
# Allow sudo without a password for the barkeeper user
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
|
@ -55,19 +71,17 @@ in {
|
|||
];
|
||||
|
||||
# Machine user for CI pipelines
|
||||
users.users.hakkonaut = {
|
||||
description = "CI and automation user";
|
||||
users.users.www-user = {
|
||||
description = "user";
|
||||
home = "/var/nix/iso-cache";
|
||||
useDefaultShell = true;
|
||||
uid = 998;
|
||||
group = "hakkonaut";
|
||||
uid = 10001;
|
||||
group = "www-user";
|
||||
isSystemUser = true;
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGP5MvCwNRtCcP1pSDrn0XZTNlpOqYnjHDm9/OI4hECW hakkonaut@flora-6"
|
||||
];
|
||||
openssh.authorizedKeys.keys = [];
|
||||
};
|
||||
|
||||
users.groups.hakkonaut = {};
|
||||
users.groups.www-user = {};
|
||||
|
||||
# # #
|
||||
# # # Triton host specific options
|
55
hosts/0001/caddy.nix
Normal file
55
hosts/0001/caddy.nix
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
services.caddy = {
|
||||
enable = lib.mkForce true;
|
||||
group = "www-user";
|
||||
email = "admins@pub.solar";
|
||||
globalConfig = lib.mkForce "";
|
||||
virtualHosts = {
|
||||
"momo.koeln" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
# website
|
||||
handle {
|
||||
root * /srv/www/momo.koeln
|
||||
try_files {path}.html {path}
|
||||
file_server
|
||||
}
|
||||
# minimal error handling, respond with status code and text
|
||||
handle_errors {
|
||||
respond "{http.error.status_code} {http.error.status_text}"
|
||||
}
|
||||
'';
|
||||
};
|
||||
"www.momo.koeln" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir https://momo.koeln{uri}
|
||||
'';
|
||||
};
|
||||
"list.momo.koeln" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
handle_path /static/* {
|
||||
root * /var/lib/mailman/web
|
||||
file_server
|
||||
}
|
||||
|
||||
reverse_proxy :8000
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [80 443];
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
{...}: {
|
||||
imports = [
|
||||
./flora-6.nix
|
||||
./0001.nix
|
||||
];
|
||||
}
|
120
hosts/0001/gitea.nix
Normal file
120
hosts/0001/gitea.nix
Normal file
|
@ -0,0 +1,120 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
hostAddress = "10.10.42.1";
|
||||
serviceAddress = "10.10.42.3";
|
||||
|
||||
hostname = "git.momo.koeln";
|
||||
|
||||
dbUserName = "gitea";
|
||||
|
||||
hostStateDir = "/mnt/internal/gitea";
|
||||
containerStateDir = "/var/lib/gitea";
|
||||
in {
|
||||
age.secrets.gitea-database-password = {
|
||||
file = "${self}/secrets/gitea-database-password.age";
|
||||
mode = "600";
|
||||
owner = "gitea";
|
||||
};
|
||||
|
||||
age.secrets.gitea-mailer-password = {
|
||||
file = "${self}/secrets/gitea-mailer-password.age";
|
||||
mode = "600";
|
||||
owner = "gitea";
|
||||
};
|
||||
|
||||
services.caddy.virtualHosts.${hostname} = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir /user/login /user/oauth2/${config.containers.keycloak.config.services.keycloak.settings.hostname} temporary
|
||||
reverse_proxy ${serviceAddress}:8080
|
||||
'';
|
||||
};
|
||||
|
||||
containers."gitea" = {
|
||||
privateNetwork = true;
|
||||
hostAddress = hostAddress;
|
||||
localAddress = serviceAddress;
|
||||
|
||||
bindMounts."${containerStateDir}" = {
|
||||
hostPath = hostStateDir;
|
||||
isReadOnly = false;
|
||||
};
|
||||
|
||||
bindMounts."${config.age.secrets.gitea-database-password.path}" = {
|
||||
hostPath = config.age.secrets.gitea-database-password.path;
|
||||
isReadOnly = true;
|
||||
};
|
||||
|
||||
bindMounts."${config.age.secrets.gitea-mailer-password.path}" = {
|
||||
hostPath = config.age.secrets.gitea-mailer-password.path;
|
||||
isReadOnly = true;
|
||||
};
|
||||
|
||||
config = {
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# gitea
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
appName = "pub.solar git server";
|
||||
database = {
|
||||
type = "postgres";
|
||||
passwordFile = config.age.secrets.gitea-database-password.path;
|
||||
};
|
||||
domain = domain;
|
||||
httpAddress = "0.0.0.0";
|
||||
httpPort = 3000;
|
||||
lfs.enable = true;
|
||||
mailerPasswordFile = config.pub-solar.infra-node.mailing.passwordFile;
|
||||
rootUrl = "https://git.pub.solar";
|
||||
settings = {
|
||||
mailer = mkIf config.pub-solar.infra-node.mailing.enabled {
|
||||
ENABLED = true;
|
||||
MAILER_TYPE = config.pub-solar.infra-node.mailing.type;
|
||||
HOST = config.pub-solar.infra-node.mailing.host;
|
||||
FROM = config.pub-solar.infra-node.mailing.from;
|
||||
USER = config.pub-solar.infra-node.mailing.user;
|
||||
};
|
||||
# currently broken, gpg core dumps
|
||||
#"repository.signing" = {
|
||||
# SIGNING_KEY = "default";
|
||||
# MERGES = "always";
|
||||
#};
|
||||
openid = {
|
||||
ENABLE_OPENID_SIGNIN = true;
|
||||
ENABLE_OPENID_SIGNUP = true;
|
||||
};
|
||||
# uncomment after initial deployment, first user is admin user
|
||||
# required to setup SSO (oauth openid-connect, keycloak auth provider)
|
||||
service.ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
|
||||
session.COOKIE_SECURE = lib.mkForce true;
|
||||
};
|
||||
};
|
||||
|
||||
# Required for gitea server side gpg signatures
|
||||
# configured / setup manually in
|
||||
# /var/lib/gitea/data/home/.gitconfig and
|
||||
# /var/lib/gitea/data/home/.gnupg/
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
pinentryFlavor = "curses";
|
||||
};
|
||||
# Required to make gpg work without a graphical environment?
|
||||
# otherwise generating a new gpg key fails with this error:
|
||||
# gpg: agent_genkey failed: No pinentry
|
||||
# see: https://github.com/NixOS/nixpkgs/issues/97861#issuecomment-827951675
|
||||
environment.variables = {
|
||||
GPG_TTY = "$(tty)";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
73
hosts/0001/keycloak.nix
Normal file
73
hosts/0001/keycloak.nix
Normal file
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
hostAddress = "10.10.42.1";
|
||||
serviceAddress = "10.10.42.1";
|
||||
|
||||
hostname = "auth.momo.koeln";
|
||||
|
||||
dbUserName = "keycloak";
|
||||
|
||||
hostStateDir = "/mnt/internal/keycloak";
|
||||
containerStateDir = "/var/lib/keycloak";
|
||||
in {
|
||||
age.secrets.keycloak-database-password = {
|
||||
file = "${self}/secrets/keycloak-database-password.age";
|
||||
mode = "700";
|
||||
#owner = "keycloak";
|
||||
};
|
||||
|
||||
services.caddy.virtualHosts.${hostname} = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir / /realms/momo.koeln/account temporary
|
||||
reverse_proxy ${serviceAddress}:8080
|
||||
'';
|
||||
};
|
||||
|
||||
containers."keycloak" = {
|
||||
privateNetwork = true;
|
||||
hostAddress = hostAddress;
|
||||
localAddress = serviceAddress;
|
||||
|
||||
bindMounts."${containerStateDir}" = {
|
||||
hostPath = hostStateDir;
|
||||
isReadOnly = false;
|
||||
};
|
||||
|
||||
bindMounts."${config.age.secrets.keycloak-database-password.path}" = {
|
||||
hostPath = config.age.secrets.keycloak-database-password.path;
|
||||
isReadOnly = true;
|
||||
};
|
||||
|
||||
config = {
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# keycloak
|
||||
services.keycloak = {
|
||||
enable = true;
|
||||
database.passwordFile = config.age.secrets.keycloak-database-password.path;
|
||||
|
||||
settings = {
|
||||
hostname = domain;
|
||||
http-host = "0.0.0.0";
|
||||
http-port = 8080;
|
||||
proxy = "edge";
|
||||
};
|
||||
|
||||
# themes = {
|
||||
# "momo.koeln" = inputs.keycloak-theme-pub-solar.legacyPackages.${pkgs.system}.keycloak-theme-pub-solar;
|
||||
# };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
88
hosts/0001/nextcloud.nix
Normal file
88
hosts/0001/nextcloud.nix
Normal file
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
hostAddress = "10.10.42.1";
|
||||
serviceAddress = "10.10.42.2";
|
||||
|
||||
hostname = "cloud.momo.koeln";
|
||||
|
||||
dbUserName = "nextcloud";
|
||||
|
||||
hostStateDir = "/mnt/internal/nextcloud";
|
||||
containerStateDir = "/var/lib/nextcloud";
|
||||
in {
|
||||
age.secrets.nextcloud-db-password = {
|
||||
file = "${self}/secrets/nextcloud-db-password.age";
|
||||
mode = "700";
|
||||
owner = "nextcloud";
|
||||
};
|
||||
|
||||
age.secrets.nextcloud-admin-password = {
|
||||
file = "${self}/secrets/nextcloud-admin-password";
|
||||
mode = "700";
|
||||
owner = "nextcloud";
|
||||
};
|
||||
|
||||
services.caddy.virtualHosts.${hostname} = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
reverse_proxy ${serviceAddress}:80
|
||||
'';
|
||||
};
|
||||
|
||||
containers."nextcloud" = {
|
||||
privateNetwork = true;
|
||||
hostAddress = hostAddress;
|
||||
localAddress = serviceAddress;
|
||||
|
||||
bindMounts."${containerStateDir}" = {
|
||||
hostPath = hostStateDir;
|
||||
isReadOnly = false;
|
||||
};
|
||||
|
||||
config = {
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
networking.firewall.allowedTCPPorts = [80];
|
||||
|
||||
# nextcloud
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
hostName = hostname;
|
||||
home = containerStateDir;
|
||||
config = {
|
||||
dbuser = dbUserName;
|
||||
dbtype = "pgsql";
|
||||
dbport = 5432;
|
||||
dbpassFile = config.age.secrets.nextcloud-db-password.path;
|
||||
|
||||
adminUser = "admin";
|
||||
adminpassFile = config.age.secrets.nextcloud-admin-password.path;
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = dbUserName;
|
||||
ensurePermissions = {
|
||||
"DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
ensureDatabases = ["nextcloud"];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
services.caddy = {
|
||||
enable = lib.mkForce true;
|
||||
group = "hakkonaut";
|
||||
email = "admins@pub.solar";
|
||||
globalConfig = lib.mkForce "";
|
||||
virtualHosts = {
|
||||
"pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
# PubSolarOS images
|
||||
handle /os/download/* {
|
||||
root * /srv/www
|
||||
file_server /os/download/* browse
|
||||
}
|
||||
# serve base domain pub.solar for mastodon.pub.solar
|
||||
# https://masto.host/mastodon-usernames-different-from-the-domain-used-for-installation/
|
||||
handle /.well-known/host-meta {
|
||||
redir https://mastodon.pub.solar{uri}
|
||||
}
|
||||
# pub.solar website
|
||||
handle {
|
||||
root * /srv/www/pub.solar
|
||||
try_files {path}.html {path}
|
||||
file_server
|
||||
}
|
||||
# minimal error handling, respond with status code and text
|
||||
handle_errors {
|
||||
respond "{http.error.status_code} {http.error.status_text}"
|
||||
}
|
||||
'';
|
||||
};
|
||||
"www.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir https://pub.solar{uri}
|
||||
'';
|
||||
};
|
||||
"auth.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir / /realms/pub.solar/account temporary
|
||||
reverse_proxy :8080
|
||||
'';
|
||||
};
|
||||
"git.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
redir /user/login /user/oauth2/keycloak temporary
|
||||
reverse_proxy :3000
|
||||
'';
|
||||
};
|
||||
"ci.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
reverse_proxy :4000
|
||||
'';
|
||||
};
|
||||
"list.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
handle_path /static/* {
|
||||
root * /var/lib/mailman/web
|
||||
file_server
|
||||
}
|
||||
|
||||
reverse_proxy :8000
|
||||
'';
|
||||
};
|
||||
"obs-portal.pub.solar" = {
|
||||
logFormat = lib.mkForce ''
|
||||
output discard
|
||||
'';
|
||||
extraConfig = ''
|
||||
reverse_proxy obs-portal.svc.e5756d08-36fd-424b-f8bc-acdb92ca7b82.lev-1.int.greenbaum.zone:3000
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [80 443];
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
age.secrets.gitea-database-password = {
|
||||
file = "${self}/secrets/gitea-database-password.age";
|
||||
mode = "600";
|
||||
owner = "gitea";
|
||||
};
|
||||
age.secrets.gitea-mailer-password = {
|
||||
file = "${self}/secrets/gitea-mailer-password.age";
|
||||
mode = "600";
|
||||
owner = "gitea";
|
||||
};
|
||||
|
||||
# gitea
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
appName = "pub.solar git server";
|
||||
database = {
|
||||
type = "postgres";
|
||||
passwordFile = config.age.secrets.gitea-database-password.path;
|
||||
};
|
||||
domain = "git.pub.solar";
|
||||
httpAddress = "127.0.0.1";
|
||||
httpPort = 3000;
|
||||
lfs.enable = true;
|
||||
mailerPasswordFile = config.age.secrets.gitea-mailer-password.path;
|
||||
rootUrl = "https://git.pub.solar";
|
||||
settings = {
|
||||
mailer = {
|
||||
ENABLED = true;
|
||||
MAILER_TYPE = "smtp";
|
||||
HOST = "mx2.greenbaum.cloud:465";
|
||||
FROM = ''"pub.solar git server" <gitea@pub.solar>'';
|
||||
USER = "admins@pub.solar";
|
||||
};
|
||||
# currently broken, gpg core dumps
|
||||
#"repository.signing" = {
|
||||
# SIGNING_KEY = "default";
|
||||
# MERGES = "always";
|
||||
#};
|
||||
openid = {
|
||||
ENABLE_OPENID_SIGNIN = true;
|
||||
ENABLE_OPENID_SIGNUP = true;
|
||||
};
|
||||
# uncomment after initial deployment, first user is admin user
|
||||
# required to setup SSO (oauth openid-connect, keycloak auth provider)
|
||||
service.ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
|
||||
session.COOKIE_SECURE = lib.mkForce true;
|
||||
};
|
||||
};
|
||||
|
||||
# Required for gitea server side gpg signatures
|
||||
# configured / setup manually in
|
||||
# /var/lib/gitea/data/home/.gitconfig and
|
||||
# /var/lib/gitea/data/home/.gnupg/
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
pinentryFlavor = "curses";
|
||||
};
|
||||
# Required to make gpg work without a graphical environment?
|
||||
# otherwise generating a new gpg key fails with this error:
|
||||
# gpg: agent_genkey failed: No pinentry
|
||||
# see: https://github.com/NixOS/nixpkgs/issues/97861#issuecomment-827951675
|
||||
environment.variables = {
|
||||
GPG_TTY = "$(tty)";
|
||||
};
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
age.secrets.keycloak-database-password = {
|
||||
file = "${self}/secrets/keycloak-database-password.age";
|
||||
mode = "700";
|
||||
#owner = "keycloak";
|
||||
};
|
||||
|
||||
# keycloak
|
||||
services.keycloak = {
|
||||
enable = true;
|
||||
database.passwordFile = config.age.secrets.keycloak-database-password.path;
|
||||
settings = {
|
||||
hostname = "auth.pub.solar";
|
||||
http-host = "127.0.0.1";
|
||||
http-port = 8080;
|
||||
proxy = "edge";
|
||||
};
|
||||
themes = {
|
||||
"pub.solar" = inputs.keycloak-theme-pub-solar.legacyPackages.${pkgs.system}.keycloak-theme-pub-solar;
|
||||
};
|
||||
};
|
||||
}
|
42
modules/infra-node/default.nix
Normal file
42
modules/infra-node/default.nix
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.pub-solar;
|
||||
in {
|
||||
options.pub-solar = {
|
||||
infra-node = {
|
||||
mailing = {
|
||||
enabled = mkEnableOption "Whether to enable mailing for services on the host";
|
||||
type = mkOption {
|
||||
description = "Mail server type";
|
||||
type = types.nullOr types.str;
|
||||
default = "smtp";
|
||||
};
|
||||
host = mkOption {
|
||||
description = "Mailing server host";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
from = mkOption {
|
||||
description = "Mailing server from";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
user = mkOption {
|
||||
description = "Mailing server user";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
passwordFile = mkOption {
|
||||
description = "Mailing server passwordFile";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue