feat(git): adding gitea and postgresql, copied jtojnar setup to play around with
This commit is contained in:
@@ -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";
|
||||
}
|
||||
];
|
||||
}}
|
||||
'';
|
||||
};
|
||||
}
|
||||
112
modules/server/gitea/default.nix
Normal file
112
modules/server/gitea/default.nix
Normal 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";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
6
modules/server/postgres/default.nix
Normal file
6
modules/server/postgres/default.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
imports = [
|
||||
./postgres.nix
|
||||
./postgres-upgrade.nix
|
||||
];
|
||||
}
|
||||
48
modules/server/postgres/postgres-upgrade.nix
Normal file
48
modules/server/postgres/postgres-upgrade.nix
Normal 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 \
|
||||
"$@"
|
||||
'')
|
||||
];
|
||||
};
|
||||
}
|
||||
139
modules/server/postgres/postgres.nix
Normal file
139
modules/server/postgres/postgres.nix
Normal 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"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user