diff --git a/flake.nix b/flake.nix index 647d35a..2747858 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,7 @@ let allowed-unfree-packages = [ "corefonts" + "mongodb" ]; configFiles = pkgs.stdenv.mkDerivation { name = "config-files"; diff --git a/host/test-corp/configuration.nix b/host/test-corp/configuration.nix index 9ffd382..bcad4de 100644 --- a/host/test-corp/configuration.nix +++ b/host/test-corp/configuration.nix @@ -9,6 +9,7 @@ caddy.enable = true; cloud-init.enable = false; do-agent.enable = true; + librechat.enable = true; podman.enable = true; sillytavern.enable = false; }; diff --git a/modules/system/default.nix b/modules/system/default.nix index f91db50..b8d74cd 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -9,6 +9,7 @@ ./do-agent.nix ./element-web.nix ./fish.nix + ./librechat.nix ./openssh.nix ./podman.nix ./seafile.nix diff --git a/modules/system/librechat.nix b/modules/system/librechat.nix new file mode 100644 index 0000000..9673b03 --- /dev/null +++ b/modules/system/librechat.nix @@ -0,0 +1,52 @@ +{ pkgs, lib, config, ... }: +with lib; +{ + options.myModules.librechat.enable = mkEnableOption "custom librechat configuration"; + + config = mkIf config.myModules.librechat.enable { + environment.systemPackages = [ + pkgs.librechat + ]; + services.caddy.virtualHosts."ai.gleipnir.technology".extraConfig = '' + reverse_proxy http://localhost:10050 + ''; + services.mongodb = { + enable = true; + }; + sops.secrets.librechat-env = { + format = "dotenv"; + group = "librechat"; + mode = "0440"; + owner = "librechat"; + restartUnits = ["librechat"]; + sopsFile = ../../secrets/librechat.env; + }; + systemd.services.librechat = { + after=["network.target" "network-online.target"]; + description="Self-hosted LLM chat frontend"; + documentation=["https://www.librechat.ai/docs"]; + requires=["network-online.target"]; + serviceConfig = { + EnvironmentFile="/var/run/secrets/librechat-env"; + Type = "simple"; + User = "librechat"; + Group = "librechat"; + ExecStart = "${pkgs.librechat}/bin/librechat-server"; + TimeoutStopSec = "5s"; + PrivateTmp = true; + WorkingDirectory = "/opt/librechat"; + }; + wantedBy = ["multi-user.target"]; + }; + systemd.tmpfiles.rules = [ + "d /opt/librechat 0755 librechat librechat" + ]; + users.groups.librechat = {}; + users.users.librechat = { + group = "librechat"; + isNormalUser = false; + isSystemUser = true; + }; + + }; +} diff --git a/secrets/librechat.env b/secrets/librechat.env index 809f290..5511765 100644 --- a/secrets/librechat.env +++ b/secrets/librechat.env @@ -7,6 +7,8 @@ JWT_SECRET=ENC[AES256_GCM,data:i49UDNjY23RnDR0DD0Bxy7c0LRLZ0ghWHoNipuy3CytJXozGd JWT_REFRESH_SECRET=ENC[AES256_GCM,data:RBV7SiQdF4Z+/UwL3ZVKL1F4Q9hgFgna9XLFJoH1nbthyd5HbIgrcNukVTErBXyX4i1tzGPHinlA47PeGmvzfQ==,iv:B7kB2u0tcBXvVPyPA4FXJ4OONH9MQMW7c69OnlahZ/s=,tag:rFvrTMibyBLdTnMEHamjRg==,type:str] MEILI_MASTER_KEY=ENC[AES256_GCM,data:IE7MYj8labkJkMEENZ6uzVx56s6g+f7JHgyy1orNlYY=,iv:uT2YYuGIrkyV23e1d/qsSFn9zIbCsnIX6jyXsBADq6A=,tag:Vl0zXCZNlDdDa96bTczcZA==,type:str] MONGO_URI=ENC[AES256_GCM,data:kFGetISiqS7KI7S/naIldKREPzytxaQn5g==,iv:LCf/llNHEQilCQaU+gu+hOxxrGdhp3/c+JiaP5y4pWM=,tag:ZU2LZCV+hqNd7JOqA6gOdQ==,type:str] +DEBUG_LOGGING=ENC[AES256_GCM,data:TP1H8q4=,iv:27aS8J/G4xQ06xI0mtwehVzF8Vw++QC2fHRdEXdzNPM=,tag:eb13lCri0TYoEhEFV1zYvQ==,type:str] +DEBUG_CONSOLE=ENC[AES256_GCM,data:nTfOpYo=,iv:vlHoSAOUO+Cv19Myg9nTmavEJpfiHOglpKXxkdRp1EY=,tag:QwYTXeykOMKflHfcIxhstA==,type:str] DOMAIN_CLIENT=ENC[AES256_GCM,data:K7OLRb4xP70aQ/zItSbxsCtLIjxLnRT/PkA0SjdW,iv:AJjLIU12cMY4R1pUaxfnLyEcppy335Oym+gdIWWcMck=,tag:BlZ1UaipeZhg2QnaSSEYrA==,type:str] DOMAIN_SERVER=ENC[AES256_GCM,data:/yXEdixU7Pq0jx22cw/sz3pgbWXfWem1BHmLJ1LI,iv:WXFPLVZ+LMdLkk4px8HUhZrsg0T1ORnAjlWdi3af5+M=,tag:39gV5ZjDux0XhvkaKuZXiw==,type:str] NO_INDEX=ENC[AES256_GCM,data:4ALRXw==,iv:he85VQ/H7NXhQmshYIZME3lN3hkO49fnYT8Qh9QO2lw=,tag:3mNaTa/7uVMWTB0IyDxezw==,type:str] @@ -15,7 +17,7 @@ ANTHROPIC_MODELS=ENC[AES256_GCM,data:8b91KAT3PO16qsT5iDZIWyFJToX8q+9IkviPiKOQzgG OPENID_CLIENT_ID=ENC[AES256_GCM,data:AsF2ReMjdgEAe9Jf7F+37tA06iuAGxMLwvyYL1FJXLY+xFVB2pk4/Q==,iv:Bb5a1KBI+Uo5wYOlgLNdQMTi3BMRZhRSzGkEds1Tv/w=,tag:0gjJHgjSlu9EZ0KJwOSdbA==,type:str] OPENID_CLIENT_SECRET=ENC[AES256_GCM,data:BXiSAzOGPKkZk46ot5jE84QPF5Kxv/+Bo3scN6+8mGRlVNlDOVOZB2iadOo9lUz78Ubj0SdukqCyhRsAdNY4Kyo7DNPnJU9sHNOmfH6t19sk5WSHUnad00kRH0O0f93f4MllCRjAVmIsqPzcO/fth3QDhTlDRBJvwDypgunRNJg=,iv:zNVlfSP89UyU9yk/Lcr2KLKy6D/G1LkQOdZzup6ZfMU=,tag:AKAo7wgdCp0nuFl/bSUQQQ==,type:str] OPENID_IMAGE_URL=ENC[AES256_GCM,data:Uqcpn+qPv66W4TP0bzhB5kueKjz0pCzxgoTgl/sTnNG4745F3Y1uuirQpj1z6omQgX5eGNcH6YlATv4=,iv:lF7JB703cDlo30UzXsiaIBU5oyJy8HKhYk7PB6sAq24=,tag:XOWAnqLJXpI8YbCceEwqUg==,type:str] -OPENID_ISSUER=ENC[AES256_GCM,data:hZv0LuDY5LGdc9Nupl2xkt1ltc0c1nP5yujRnzjkI6Ux/uuGblTBm1ki0Ix9kqhMPbDHzamUdb5PB2f7/tSbU+tt8CpCw4HLr0m7ODIMfxriKc7M6B07Mu4b,iv:YTxPj8ASa6Fm8787cTmZmNoVplYDsdBAnT5CEaRAKEo=,tag:Wywx+g8nVnxGQM3w9NLrLA==,type:str] +OPENID_ISSUER=ENC[AES256_GCM,data:STDmpARJ6eckTHKgU5LMy6YB/kwvBwW1RS6T5ABSOHNKn6RAE7AK0AixjWXPjF9HyVMspTlGez7a/9y5Pqu3g6loE4AOrn+3ymL56atZ3+b+vcaO397UQH/u,iv:UNkvkQV3/eUz29bz6zmKOclogOYaTI4leDVIR6Zx5FM=,tag:Sjl4q7r+4Cfmcpw6HaejtQ==,type:str] OPENID_SESSION_SECRET=ENC[AES256_GCM,data:GDljJMWalWPxwNUUHabWrmNviQ9YH8kkH8Q8mEApghoYZxK3,iv:/AfcVFGn/R+UfEj0OMtbb/8iQnB6KKFTwEW0s14RcXU=,tag:drOzahVhTqWUg2GwNRyrcQ==,type:str] OPENID_SCOPE=ENC[AES256_GCM,data:w7kyJDR4uPKGFihIwLP8qYI7cv8=,iv:mVaSBvlyDUs5QLHAmXZMxliBDB2Z4k25tkT30rlZTyM=,tag:QNB2UHaZgCZADMqLIDEdHA==,type:str] OPENID_CALLBACK_URL=ENC[AES256_GCM,data:wK2W107IUkSP0S0qz3lIDHllFyXTUw==,iv:Hu92cIiWUYKcOj0hIb9fGOcqbkrhTC8RLygRRe5I9V8=,tag:dL+1FuiY+d2JSzr3vgNx4g==,type:str] @@ -33,7 +35,7 @@ sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb2 sops_age__list_2__map_recipient=age1kgwk20cc6t68kqj5nhem6swvx6k4e7zjx2xdwy382360h8tdyqrq0nn3gf sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnWkhmQ3NmYUVybzl5b3d2\ncGRBb2dHdDhiUEw2eU0welVmRXk2ak1nMVJVCnNnemR3ckFIYWtqSHV3VXZkWjZZ\nSXY3MGhQSkNQdy9lY21LTFFicEFsejQKLS0tIC8vckx1SmxnWCtNMTBlYjlmUUNm\ncHNJNlJMWkQ5YTlURDZRZUFrZ1BHdTgKLjxOPzdSKxbtO6o+fyzEfr1huOyQydH+\nSq+KO0ua6u2wGFylPkAzZ8MyH6JHEjpTYj4vIXrXMLBHWckEGuQFiQ==\n-----END AGE ENCRYPTED FILE-----\n sops_age__list_3__map_recipient=age1t3ryfktuhr3cysf49m9q2n8fkjf9ajjjnhztxw9hz8paxgk4lpcq065jge -sops_lastmodified=2025-07-21T19:29:23Z -sops_mac=ENC[AES256_GCM,data:37qwziGXAr+FXfFkeKXRRLc6GDq9LsYhsiTWm1gKaXvQnvKVLHkzeICWpCtruhHAwtZ3a7LouDdAFd3o1ZDXTFRE9OyIiqRLEtf6hEV1n7DPViBF8/0v+MlVeVr1rQoDip2UDWmtZt0g5q8xdd5soAby20HPoCrJTO43pQN89GI=,iv:+SyJHSFJyVwuSmY7afTEhSXtxtfBjeR+pFLFkOVx02I=,tag:wx2rF6qnyjD1iMFm3Pd6CQ==,type:str] +sops_lastmodified=2025-07-21T20:10:22Z +sops_mac=ENC[AES256_GCM,data:MccusdAI4b8ot4/bRTsMT1E4pTTrCxHkttJLSmjrup11WQWhMdRymkESanbsQ9kS9ffWEDKzNLM4AX7Uq4OPYFvqtqHzheQ9d85/c5Q5xEbbozdUX6r7ejmA7ieZq0TbepoA8NsJqymRMnpgQmvwc5BRxZSWXkyvVOxXByC+PYQ=,iv:PJbGO0nw0j+aO68rg3FuiiXsgjayGMXs+HPtKcZqeFk=,tag:z7iOx7OgfI8/IK/J1ke5sA==,type:str] sops_unencrypted_suffix=_unencrypted sops_version=3.10.2