import opia roles
10 files changed, 370 insertions(+), 3 deletions(-)
M flake.lock → flake.lock
@@ -365,6 +365,24 @@ "repo": "flake-utils", "type": "github" } }, + "flake-utils_5": { + "inputs": { + "systems": "systems_8" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "fromYaml": { "flake": false, "locked": {@@ -472,6 +490,31 @@ "repo": "gomod2nix", "type": "github" } }, + "gomod2nix_3": { + "inputs": { + "flake-utils": [ + "tg-auth", + "flake-utils" + ], + "nixpkgs": [ + "tg-auth", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770585520, + "narHash": "sha256-yBz9Ozd5Wb56i3e3cHZ8WcbzCQ9RlVaiW18qDYA/AzA=", + "owner": "nix-community", + "repo": "gomod2nix", + "rev": "1201ddd1279c35497754f016ef33d5e060f3da8d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "gomod2nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [@@ -517,7 +560,7 @@ }, "impermanence": { "inputs": { "home-manager": "home-manager_2", - "nixpkgs": "nixpkgs_6" + "nixpkgs": "nixpkgs_7" }, "locked": { "lastModified": 1769548169,@@ -728,6 +771,22 @@ } }, "nixpkgs_6": { "locked": { + "lastModified": 1770562336, + "narHash": "sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d6c71932130818840fc8fe9509cf50be8c64634f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_7": { + "locked": { "lastModified": 1768564909, "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", "owner": "nixos",@@ -742,7 +801,7 @@ "repo": "nixpkgs", "type": "github" } }, - "nixpkgs_7": { + "nixpkgs_8": { "locked": { "lastModified": 1773375660, "narHash": "sha256-SEzUWw2Rf5Ki3bcM26nSKgbeoqi2uYy8IHVBqOKjX3w=",@@ -920,6 +979,7 @@ "scriptura": "scriptura", "searchix": "searchix", "srvos": "srvos", "stylix": "stylix", + "tg-auth": "tg-auth", "vpsadminos": "vpsadminos" } },@@ -1143,6 +1203,39 @@ "repo": "default", "type": "github" } }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "tg-auth": { + "inputs": { + "flake-utils": "flake-utils_5", + "gomod2nix": "gomod2nix_3", + "nixpkgs": "nixpkgs_6" + }, + "locked": { + "lastModified": 1773585135, + "narHash": "sha256-1NO3lNwGBV1Atlq9fbCxT+gRipRUXGvUTAB45LQBLoQ=", + "rev": "a81eb46a5298e315eb64a4094ca0eb93489ff935", + "type": "tarball", + "url": "https://codeberg.org/api/v1/repos/opia/tg-auth/archive/a81eb46a5298e315eb64a4094ca0eb93489ff935.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://codeberg.org/opia/tg-auth/archive/main.tar.gz" + } + }, "tinted-foot": { "flake": false, "locked": {@@ -1294,7 +1387,7 @@ }, "vpsadminos": { "inputs": { "impermanence": "impermanence", - "nixpkgs": "nixpkgs_7", + "nixpkgs": "nixpkgs_8", "nixpkgsUnstable": "nixpkgsUnstable" }, "locked": {
A secrets/lauti.age
@@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 knHzXw 1P1pJW14/othkCbDU+6qggkRV3Z6hzeYVE9OqtRS3xE +P/Mo9K8k67fG+3P6E/KA9tNAp17zHh2mJA4GL4ha9io +-> piv-p256 VBDKjg AwEFtu2ckaEi1YPdSGHz4aWLp+fv70vAybPZPGq3u8WO +reCJXHyoFzzIx12Mt7i9rg07QgfP1vPSH2CN5r6HXEA +--- XBVN+h4YHO2bFzOKTZWjd0n++cc6Gkw4FilLeOXttl4 +S6²¿JQ¢þ¥_IX� ¹%{,JÞ¼õ›µMÄ�ÞÝOLCp^Ãs¶ã£ÂÐÿ<âAÔÀŒºÛ}�F6šW£Ï–óGð>0æ�}×�ùiéS6
A secrets/tg_archive.age
@@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 knHzXw P0PJJgZ++oJW0jAyvAl+UwzF8nwjDyFimhnIC86I1Ug +S7sHqCk1rYRIfNSJZG2F3A1XX1eaRr7JG759rt5sbU0 +-> piv-p256 VBDKjg A9EBq4BwUoIUcv1zZ+SWegbySpPLIw7RDTEoRvxALLGz +5ZcvVYly0Rf+rr9+WTfAXKaWLtc1URbBgqhFoEkU4HY +--- AcFoA3k7VRGD6AVptdWEO27IfbJKnXxbO709Dkh51Uk +T»»À20î¹¶•ò=‡mÖü¢M�O°^ßg=nÿp—|›êOК æËÄKV2\Ð'@ãþ&4b©Ã—ô*ŒÝLe¶¢þÅ“,—w÷Û\¡!Ç„—»žbÿ
A secrets/tgauth.age
@@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 knHzXw g88Ckhi0ORYj+Tc+pup4Wy9RdHePsDo+SP81mAjoox8 +AhrPtng7I0jECnTTw1mWmyY8W/JgnXI5KnuJGWdUN/A +-> piv-p256 VBDKjg AkhWOZMTQb/PVpnfREIiPLuGLVjZb5z22dmSDvbHkuG+ +wLTG9z9fbowDgT3EJfxQd/gUM03/Gc9+8pR7rsVF2GA +--- RpE3fOI6W4RlqKOu3V07GeXPN0a+V8apGegXKH1FnwI +Çáa<û„3ÆÎ˜)‹WÛž}…[WøµŒÅ´•Å𥇔Ê�6 *9ŽãëÌçîAnÖ„lWo¤“õ»¶”{¤>¿p맺QG;Ê{Ø,E „1|áé3à”óÎåL(jÀZD÷Û1©gŸCjîHŸÓk‘8ÕsOͤ˜½Û·+¢êS×Å¢G^脺È,æ¨ÒÇaRŽô’q\ë£
M system/hosts/smrk.nix → system/hosts/smrk.nix
@@ -31,6 +31,11 @@ ../roles/searchix.nix ../roles/sso.nix ../roles/subdomain-redirector.nix ../roles/video-library.nix + + ../roles/opia/archive.nix + ../roles/opia/auth.nix + ../roles/opia/calendar.nix + ../roles/opia/wiki.nix ]; system.stateVersion = "25.11";
A system/roles/opia/archive.nix
@@ -0,0 +1,124 @@ +{ + config, + lib, + pkgs, + ... +}: +let + domain = "opia.ovh"; + subdomain = "archive"; + + # pkg = pkgs.tg-archive; + # format = pkgs.formats.yaml { }; + + # groups = { + # main = (-1002285871016); + # }; + + # # see https://github.com/knadh/tg-archive/blob/master/tgarchive/example/config.yaml + # genCfg = name: group: { + # inherit group; + + # download_media = true; + # download_avatars = true; + # avatar_size = [ + # 64 + # 64 + # ]; + # media_dir = "media"; + + # media_mime_types = [ ]; + + # proxy = { + # enable = false; + # }; + + # fetch_batch_size = 2000; + # fetch_wait = 5; + # fetch_limit = 0; + + # publish_dir = "${config.users.users.archive.home}/sites/${name}"; + # static_dir = "static"; + # per_page = 500; + # show_day_index = true; + + # telegram_url = "https://t.me/{id}"; + # show_sender_fullname = false; + # timezone = "Europe/Berlin"; + + # publish_rss_feed = false; + # rss_feed_entries = 100; + + # site_url = "https://${subdomain}.${domain}"; + # site_name = "@{group} - Telegram group archive"; + # site_description = "Public archive of Telegram messages."; + # meta_description = "@{group} {date} - Telegram message archive."; + # page_title = "Page {page} - {date} @{group} Telegram message archive."; + # }; + + # genScript = + # name: group: + # let + # cfgFile = format.generate "tg-archive.yaml" (genCfg name group); + # dir = "data/${name}"; + # in + # '' + # if test ! -d "${dir}" + # then + # ${lib.getExe pkg} --config ${cfgFile} --new --path ${dir} + # fi + # cd "${dir}" + + # ${lib.getExe pkg} --config ${cfgFile} --sync + + # ${lib.getExe pkg} --config ${cfgFile} --build + # ''; +in +{ + age.secrets.tg_archive.file = ../../../secrets/tg_archive.age; + + users.groups.tg-archive = { }; + users.users.tg-archive = { + home = "/var/lib/tg-archive"; + createHome = true; + isSystemUser = true; + group = "tg-archive"; + extraGroups = [ "caddy" ]; + }; + + # TODO telethon build failure + # environment.systemPackages = [ pkgs.tg-archive ]; + + # systemd.services.tg-archive = { + # description = "Telegram Archive"; + # serviceConfig = { + # Type = "oneshot"; + # WorkingDirectory = config.users.users.archive.home; + # EnvironmentFile = [ config.age.secrets.tg_archive.path ]; + # User = "archive"; + # Group = "archive"; + # }; + + # preStart = '' + # if test ! -d data + # then + # mkdir data + # fi + # cd data + # ''; + # script = lib.concatMapAttrsStringSep "\n" genScript groups; + # }; + + services.caddy.virtualHosts = { + "${subdomain}.${domain}" = { + extraConfig = '' + tls { + dns_challenge_override_domain _acme-challenge.${subdomain}.opia.${config.networking.domain} + } + encode + root ${config.users.users.tg-archive.home}/data + file_server browse + ''; + }; + }; +}
A system/roles/opia/auth.nix
@@ -0,0 +1,58 @@ +{ + config, + inputs, + ... +}: +let + domain = "opia.ovh"; + subdomain = "auth"; + port = 8083; +in +{ + imports = [ + inputs.tg-auth.nixosModules.tg-auth + ]; + + age.secrets.tgauth.file = ../../../secrets/tgauth.age; + + services.caddy = { + extraConfig = '' + (tg_auth) { + forward_auth localhost:${toString port} { + uri / + } + } + ''; + virtualHosts."${subdomain}.${domain}" = { + extraConfig = '' + tls { + dns_challenge_override_domain _acme-challenge.${subdomain}.opia.${config.networking.domain} + } + encode zstd gzip + reverse_proxy localhost:${toString port} + ''; + }; + }; + + services.tg-auth = { + enable = true; + + environment = { + PORT = toString port; + BOT_NAME = "OpiaCommunityBot"; # Username without @ + + SIGNIN_URL = "https://${subdomain}.${domain}/signin"; + SIGNIN_REDIRECT_CALLBACK_URL = "https://${subdomain}.${domain}/signin/callback"; + SIGNIN_AFTER_SIGNIN_URL = "https://${subdomain}.${domain}/"; + + AUTHZ_CHANNEL_IDS = "-1002285871016"; # may need "-100" in front, just "-" or neither + AUTHZ_CACHE = "5m"; + + AUTHN_COOKIE_NAME = "tgauth_session"; + AUTHN_COOKIE_DOMAIN = domain; + AUTHN_SESSION_TTL = "48h"; + }; + + environmentFile = config.age.secrets.tgauth.path; + }; +}
A system/roles/opia/calendar.nix
@@ -0,0 +1,41 @@ +{ config, pkgs, ... }: +let + domain = "opia.ovh"; + subdomain = "cal"; +in +{ + age.secrets.lauti.file = ../../../secrets/lauti.age; + + services.lauti = { + enable = true; + settings = { + LAUTI_ADDR = "localhost:3333"; + LAUTI_MAIL_ADDRESS = "lauti@${domain}"; + LAUTI_ADMIN_EMAIL = "lauti@${domain}"; + LAUTI_TIMEZONE = config.time.timeZone; + LAUTI_BASE_URL = "https://${subdomain}.${domain}"; + # LAUTI_ADMIN_PASSWORD = in secret + }; + secrets = [ config.age.secrets.lauti.path ]; + }; + # for debugging the database + environment.systemPackages = with pkgs; [ litecli ]; + + services.caddy = { + virtualHosts."${subdomain}.${domain}" = { + extraConfig = '' + tls { + dns_challenge_override_domain _acme-challenge.${subdomain}.opia.${config.networking.domain} + } + encode zstd gzip + + reverse_proxy ${config.services.lauti.settings.LAUTI_ADDR} { + header_up -Accept-Encoding + transport http { + compression off + } + } + ''; + }; + }; +}
A system/roles/opia/wiki.nix
@@ -0,0 +1,24 @@ +{ config, ... }: +let + domain = "opia.ovh"; + subdomain = "wiki"; +in +{ + services.gollum = { + enable = true; + emoji = true; + branch = "main"; + }; + + services.caddy.virtualHosts."${subdomain}.${domain}" = { + extraConfig = '' + tls { + dns_challenge_override_domain _acme-challenge.${subdomain}.opia.${config.networking.domain} + } + encode zstd gzip + reverse_proxy localhost:${toString config.services.gollum.port} + + import tg_auth + ''; + }; +}