feat(git): adding gitea and postgresql, copied jtojnar setup to play around with

This commit is contained in:
2025-09-15 11:57:01 +02:00
parent 9f2c86920f
commit 13b18e64a0
8 changed files with 311 additions and 188 deletions

View File

@@ -124,7 +124,6 @@
./server/caddy
./server/fail2ban
./server/homepage-dashboard
./server/dashy
./server/vaultwarden
./server/bazarr
./server/prowlarr
@@ -138,6 +137,8 @@
./server/unbound
./server/uptime-kuma
./server/keepalived
./server/gitea
./server/postgres
];
};
settings = {

View File

@@ -1,151 +0,0 @@
{
pkgs,
config,
lib,
...
}: let
unit = "dashy";
cfg = config.server.${unit};
srv = config.server;
hl = config.server;
mergedServices = hl // (hl.podman or {});
dashyCategories = [
"Arr"
"Media"
"Downloads"
"Services"
"Smart Home"
];
getServicesByCategory = cat:
lib.attrsets.filterAttrs (name: value: (value ? category && value.category == cat)) mergedServices;
# This function was missing its 'services' argument at the end of the call.
mkItems = services:
lib.attrsets.mapAttrsToList (name: value: {
title = value.name or name;
description = value.description or "";
url =
if value ? href
then value.href
else if value ? url
then "https://${value.url}${value.path or ""}"
else "";
icon = value.icon or "";
})
services; # <-- FIX: Added the 'services' argument here.
esc = s: lib.replaceStrings ["\""] ["\\\""] (toString s);
renderSection = {
name,
icon,
items,
}: ''
- name: "${esc name}"
icon: "${esc icon}"
items:
${lib.concatStringsSep "\n" (
lib.lists.map (item: ''
- title: "${esc item.title}"
description: "${esc item.description}"
url: "${esc item.url}"
icon: "${esc item.icon}"
'')
items
)}
'';
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configFile = lib.mkOption {
type = lib.types.path;
readOnly = true;
internal = true;
description = "Path to the generated Dashy config file.";
};
misc = lib.mkOption {
default = [];
type = lib.types.listOf (
lib.types.attrsOf (
lib.types.submodule {
options = {
name = lib.mkOption {type = lib.types.str;};
description = lib.mkOption {
type = lib.types.str;
default = "";
};
href = lib.mkOption {type = lib.types.str;};
icon = lib.mkOption {type = lib.types.str;};
};
}
)
);
};
};
config = lib.mkIf cfg.enable {
services.glances.enable = true;
server.dashy.configFile = pkgs.writeText "conf.yml" ''
pageInfo:
title: "${esc "${srv.domain} Homelab"}"
description: "${esc "Homelab made with NixOS"}"
navLinks:
- title: "GitHub"
path: "https://github.com/cnsta/cnix"
appConfig:
theme: "material-dark"
layout: "auto"
iconSize: "medium"
language: "en"
statusCheck: true
hideComponents:
hideSettings: false
sections:
${lib.concatStringsSep "\n" (
lib.lists.map (
cat:
renderSection {
name = cat;
icon = "fas fa-box";
items = mkItems (getServicesByCategory cat);
}
)
dashyCategories
)}
${renderSection {
name = "Misc";
icon = "fas fa-ellipsis-h";
items =
lib.lists.map (x: {
title = x.name;
description = x.description or "";
url = x.href or "";
icon = x.icon or "";
})
cfg.misc;
}}
${renderSection {
name = "Monitoring";
icon = "fas fa-monitor-heart-rate";
items = [
{
title = "Glances";
description = "System Monitoring";
url = "http://localhost:${toString config.services.glances.port}";
icon = "hl-glances";
}
];
}}
'';
};
}

View File

@@ -0,0 +1,112 @@
# taken from @jtojnar
{
config,
lib,
...
}: let
unit = "gitea";
srv = config.server;
cfg = config.server.${unit};
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "git.${srv.domain}";
};
port = lib.mkOption {
type = lib.types.int;
default = 5003;
description = "The port to host Gitea on.";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Gitea";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Git with a cup of tea";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "gitea.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
appName = "cnix code forge";
database = {
type = "postgres";
socket = "/run/postgresql";
name = "gitea";
user = "gitea";
createDatabase = false;
};
lfs = {
enable = true;
};
settings = {
cors = {
ENABLED = true;
SCHEME = "https";
ALLOW_DOMAIN = cfg.url;
};
log = {
MODE = "console";
};
mailer = {
ENABLED = true;
MAILER_TYPE = "sendmail";
FROM = "noreply+adam@cnst.dev";
SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
};
picture = {
DISABLE_GRAVATAR = true;
};
repository = {
DEFAULT_BRANCH = "main";
DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls";
DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
};
server = {
DOMAIN = cfg.url;
LANDING_PAGE = "explore";
HTTP_PORT = cfg.port;
ROOT_URL = "https://${cfg.url}/";
};
security = {
DISABLE_GIT_HOOKS = false;
};
service = {
DISABLE_REGISTRATION = true;
};
session = {
COOKIE_SECURE = true;
};
};
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:5003
'';
};
server.postgresql.databases = [
{
database = "gitea";
}
];
};
}

View File

@@ -1,6 +1,7 @@
{
config,
lib,
pkgs,
...
}: let
srv = config.server;
@@ -23,18 +24,6 @@ in {
options.server.podman = {
enable = lib.mkEnableOption "Enables Podman";
gluetun.enable = lib.mkEnableOption "Enables gluetun";
dashy = {
enable = lib.mkEnableOption "Enable dashy";
port = lib.mkOption {
type = lib.types.int;
default = 8081;
description = "The port to host Dashy on.";
};
url = lib.mkOption {
type = lib.types.str;
default = "dashy.${srv.domain}";
};
};
qbittorrent = {
enable = lib.mkEnableOption "Enable qBittorrent";
@@ -149,15 +138,6 @@ in {
};
services.caddy.virtualHosts = lib.mkMerge [
(lib.mkIf cfg.dashy.enable {
"${cfg.dashy.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString cfg.dashy.port}
'';
};
})
(lib.mkIf cfg.qbittorrent.enable {
"${cfg.qbittorrent.url}" = {
useACMEHost = srv.domain;
@@ -216,17 +196,6 @@ in {
};
})
(lib.mkIf cfg.dashy.enable {
dashy = {
image = "lissy93/dashy:latest";
autoStart = true;
ports = ["${toString cfg.dashy.port}:80"];
volumes = [
"${srv.dashy.configFile}:/app/user-data/conf.yml"
];
};
})
(lib.mkIf cfg.qbittorrent.enable {
qbittorrent = {
image = "ghcr.io/hotio/qbittorrent:latest";

View File

@@ -0,0 +1,6 @@
{
imports = [
./postgres.nix
./postgres-upgrade.nix
];
}

View File

@@ -0,0 +1,48 @@
# taken from @jtojnar
{
config,
lib,
pkgs,
...
}: let
inherit (lib) types mkOption;
cfg = config.server.postgresql;
in {
options = {
server.postgresql = {
upgradeTargetPackage = mkOption {
type = types.nullOr types.package;
default = null;
description = "PostgreSQL package that we want to upgrade to. When set, an update script will be installed.";
};
};
};
config = {
# https://nixos.org/manual/nixos/unstable/#module-services-postgres-upgrading
environment.systemPackages = lib.mkIf (cfg.upgradeTargetPackage != null) [
(pkgs.writeScriptBin "upgrade-pg-cluster" ''
set -eux
# XXX it's perhaps advisable to stop all services that depend on postgresql
systemctl stop postgresql
export NEWDATA="/var/lib/postgresql/${cfg.upgradeTargetPackage.psqlSchema}"
export NEWBIN="${cfg.upgradeTargetPackage}/bin"
export OLDDATA="${config.services.postgresql.dataDir}"
export OLDBIN="${config.services.postgresql.package}/bin"
install -d -m 0700 -o postgres -g postgres "$NEWDATA"
cd "$NEWDATA"
sudo -u postgres $NEWBIN/initdb -D "$NEWDATA"
sudo -u postgres $NEWBIN/pg_upgrade \
--old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \
--old-bindir $OLDBIN --new-bindir $NEWBIN \
"$@"
'')
];
};
}

View File

@@ -0,0 +1,139 @@
# taken from @jtojnar
{
config,
lib,
pkgs,
...
}: let
inherit (lib) types mkOption;
cfg = config.server.postgresql;
database = {name, ...}: {
options = {
database = mkOption {
type = types.str;
description = "Database name";
};
extraUsers = mkOption {
type = types.listOf types.str;
default = [];
description = "List of extra users with access to this database.";
};
extensions = mkOption {
type = types.listOf types.str;
default = [];
description = "List of extensions to install and enable.";
};
};
};
in {
options = {
server.postgresql = {
databases = mkOption {
type = types.listOf (types.submodule database);
default = [];
description = "List of databases to set up.";
};
};
};
config = lib.mkIf (cfg.databases != []) {
services.postgresql = {
enable = true;
package = pkgs.postgresql_17;
extensions = lib.filter (x: x != null) (
lib.concatMap (
{extensions, ...}: map (ext: config.services.postgresql.package.pkgs.${ext} or null) extensions
)
cfg.databases
);
authentication = lib.mkForce ''
local all postgres peer
local sameuser all peer
# extra users
${lib.concatMapStringsSep "\n" (
{
database,
extraUsers,
...
}:
lib.concatMapStringsSep "\n" (user: "local ${database} ${user} peer") extraUsers
)
cfg.databases}
'';
ensureUsers = let
dbToUsers = {
database,
extraUsers,
...
}:
# we use same username as dbname
[database] ++ extraUsers;
in
map (name: {inherit name;}) (lib.unique (builtins.concatMap dbToUsers cfg.databases));
};
systemd.services = {
postgres-setup = let
pgsql = config.services.postgresql;
in {
after = ["postgresql.service"];
wantedBy = ["multi-user.target"];
path = [pgsql.package];
script =
lib.concatMapStringsSep "\n" (
{
database,
extensions,
extraUsers,
...
}: let
createExtensionsSql =
lib.concatMapStringsSep "; " (
ext: ''CREATE EXTENSION IF NOT EXISTS "${ext}"''
)
extensions;
createExtensionsIfAny = lib.optionalString (extensions != []) ''
$PSQL -d '${database}' -c '${createExtensionsSql}'
'';
in ''
set -eu
PSQL="${pkgs.util-linux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.settings.port} --tuples-only --no-align"
if ! $PSQL -c "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep --quiet 1; then
$PSQL -c 'CREATE DATABASE "${database}" WITH OWNER = "${database}"'
${createExtensionsIfAny}
fi
${
lib.optionalString (extraUsers != [])
"$PSQL '${database}' -c '${
lib.concatMapStringsSep "\n" (
user: "GRANT ALL ON ALL TABLES IN SCHEMA public TO ${user};"
)
extraUsers
}'"
}
''
)
cfg.databases;
serviceConfig = {
Type = "oneshot";
};
};
postgresql.serviceConfig = {
# Required by PLV8.
MemoryDenyWriteExecute = false;
SystemCallFilter = [
"@pkey"
];
};
};
};
}