mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-12 07:49:25 +08:00
Compare commits
113 Commits
switch-srv
...
sops
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e1b621434 | |||
| f9dc3d7357 | |||
| 72350f15dd | |||
| e8eb6de0c0 | |||
| d3e290f19b | |||
| 5c8b43334f | |||
| 8cc28f6629 | |||
| d3024094ef | |||
| 984a80e1e3 | |||
| 94bfc5f711 | |||
| f4d71c9062 | |||
| 4581ab444c | |||
| 2557a33bc4 | |||
| ae705f203b | |||
| 1dd86833b9 | |||
| 96dbb612d0 | |||
| 1880d6edff | |||
| a72bac2f00 | |||
| 173f7bd6ba | |||
| dc66b05259 | |||
| c4a860ccac | |||
| a028de0e7b | |||
| 34278afedf | |||
| 4d2c9fd540 | |||
| 3244384cd2 | |||
| dbee578ed4 | |||
| 3700de79cb | |||
| 53f77d2873 | |||
| d77e71439d | |||
| aee3956c10 | |||
| 4080010669 | |||
| 502b09d6bc | |||
| 694cc41bf7 | |||
| e0a113747b | |||
| b6b5a7fecd | |||
| d5c7f2d842 | |||
| 28ee978c62 | |||
| a18d464a58 | |||
| c3491c8804 | |||
| 33f4031edc | |||
| 81ef46a464 | |||
| bb46b3b409 | |||
| efbfbb5eb0 | |||
| d1a6a37ed2 | |||
| d9d7bef796 | |||
| 325da64812 | |||
| 6c62d499f1 | |||
| 3639585a86 | |||
| 79084dc8e0 | |||
| ca15905e1a | |||
| bdb0652d24 | |||
| 6a375e241e | |||
| e4583277d3 | |||
| 17f9eb9d8f | |||
| 3d434264b9 | |||
| 411411d0af | |||
| 091f5dfc38 | |||
| c65f295518 | |||
| 50ca8f8232 | |||
| 9acf5a9afb | |||
| 9c13e4efdc | |||
| 04cb3b86dd | |||
| 81874a7bbb | |||
| 6f422a9689 | |||
| f1be2f0d52 | |||
| 37d8d2ecde | |||
| 5afcec1f12 | |||
| cc785838de | |||
| e126b0cb2c | |||
| 25d6f8f4c7 | |||
| ced0fbf714 | |||
| 73d20da10f | |||
| 55a5085c23 | |||
| 6c89c350b1 | |||
| 21074ef749 | |||
| 510185f0ce | |||
| c1a3857389 | |||
| 2eabbf2796 | |||
| 74894efbde | |||
| 055599b5c7 | |||
| 5dabd06e71 | |||
| 289035d755 | |||
| abd242c99b | |||
| 4248975e94 | |||
| 1147ec64b7 | |||
| ab3300d7b4 | |||
| fd8d210336 | |||
| 08c8665cd6 | |||
| 041fc5e3af | |||
| 8493b31634 | |||
| 7f9dae314f | |||
| 1119f659b3 | |||
| a15ee17f22 | |||
| d2630dc2d2 | |||
| 9a0d1dc6a6 | |||
| 9f63ace01e | |||
| 378e8aad93 | |||
| 0f59021493 | |||
| 9d1179e422 | |||
| 06a2d200f3 | |||
| a96d365d58 | |||
| aad50566c8 | |||
| 4f254a863c | |||
| bcd14f67b2 | |||
| 143e14de8b | |||
| f17517d3df | |||
| 1d3022ea5a | |||
| ab3723b0e0 | |||
| 1d0a7261a3 | |||
| 96e7162e61 | |||
| 637620ab1d | |||
| 4979b39f73 | |||
| ba83828393 |
@@ -54,6 +54,3 @@ creation_rules:
|
||||
- path_regex: devices/cross/secrets/chn.yaml$
|
||||
key_groups:
|
||||
- age: [ *chn, *pc, *one, *nas ]
|
||||
- path_regex: devices/cross/secrets/acme.yaml$
|
||||
key_groups:
|
||||
- age: [ *chn, *nas, *pc, *srv3, *vps4, *vps6 ]
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
acme:
|
||||
token: ENC[AES256_GCM,data:Zm4vCgYbrm8wtYMYqtRkMF7hm8feTcZXITKbJgWsgagWbbHE5Z8zoA==,iv:RSRw188gjoAdhTErApuF8tBSsD+aT3LGhifcy417Qzw=,tag:4ZHfkW8aCJ6BW8mtL261yQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwOFEwcjQyUmlpRDJ1WVFt
|
||||
WUJVM29wdTFwZmNWTHNkMFpjeThCaGt0VkJjCjZ1bnNGVnF0dmdKVE1VdzJoeXJk
|
||||
ZXM0b0NZeENMY2g0R203Rnc4Y2x3QTQKLS0tIHVPc1NuaGx5ZE92R3VTenpiRGNI
|
||||
UWhxZVBpL1VSMVFabVJ3WWUrMjlrRTAKpya6EFm4EQ3o35C5Bdyyaw4Qys8IM2fe
|
||||
OrA5b9xElsEhfGzkpRXkEtsbMhbbpNu0zvDBpylU8rU70tffcWh1sA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age19lhcwk37jmvn6z0v4dpdfh0k4u23f76twdjknc0p7atktf37rd7s4t4wj3
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvdUowREVqOXBiZE02RUU2
|
||||
RVU3MkxNVFRiaUFHQzlzdXpQNFRvanhDMGdjCm1qUytTNzAyY3g1OXI4L0hmK2Va
|
||||
a0hJem5FNkFYTnBxbnhJT0QrbVBzdk0KLS0tIDkxeGYwTnNaUVVBa2NxT1dGWVRF
|
||||
UE9uY2tjdE1ZTVFXSWI5czE1ZHVBV0UKYHyDTeejdMwfYW2u6r9MWZ9qJU2mTYJx
|
||||
qK2/91+T5/paq23+gEpMJeCbCMfcws9xeaf4KgWdBr/JNgjNQ3mhyQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1ffvr5pqd2lfj24e3fh53s92z6h76fda3du4y4k6r3yjumdwvpfgqzj033a
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIbjBLelBWR0ZpZEFrL3A2
|
||||
UExIamd3aElvZUNCK2VwZVJrdHMyWGZNYnhJCnBoUlF4ZWtKMDVIYzhqUlpxZXpr
|
||||
UlY4VnVwcFkxMzc0Q0VoQW03QU9BODQKLS0tIGtoRStxL3BFd09CMi9zT0pwZEwr
|
||||
d0hRWnVQOWVxdGRxRXpBZGtMQ24xbm8KtlIU+T++8IQRDLXAH1pBXa6hNqHD19ti
|
||||
AIZGn7+Eh/b6wOkndNpzLCWGVVm9yo7qMY7AzYNIz7SU/9a0JPGuGQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1n4lhfwv7g0vhx54exmwx9yv2z04m3h2lunzpa5zdzgtcvjjuf5nqc36g8a
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxbFVkbjdHWm9xTlEwbzBE
|
||||
Ky9KcjVvc0l2ZkJnOVdxVzFpUDMydDRuNWtVCmpkYXl1dG91TG84em16cFlRcG5y
|
||||
WTBKM1VuWmV3dUlpcE1ka093aHh6REEKLS0tIC91OHF0TnhDUjlqVWcvMjl1czlm
|
||||
YVRXZS9PRVpwNmFaY3pNT0JZNzB3R2MKHClUpTySdpU8AFNYoqT37KWkJbPgmd2+
|
||||
UhtufEWWgSL6j/npU0yxHNcsmU5gfd45TnTxp4sSOupJUDM0B4FKlQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1yvrl4y0r6yzcxzzkgfwshlrtsjt8uuya6rfwks09pnft7esfcyvqmrtm5q
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBObkt4a25UcGo4MnoxOVJQ
|
||||
WkF6elVWODYvSWw1QWtPYTJKS1gxUXRDVjNJCndNcU5GUHhMZW5uTzNpV2NtYUVh
|
||||
K0dYNGlmRzd5ZkZVaGd3cjJFVEFSMXMKLS0tIEVRQWtaY0d3TERsV0ZNcVc0Vyty
|
||||
WnZxTGxOY0NROU4vYTl1WWREemptaDAKhzzRPyr370b7ccTM5DE+jOczmXDqZBt5
|
||||
fYQ04+yLjcULNhqlu52mJRH1X5Se2pXbCzEG6JFiKCEra0wiYhoo5Q==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age164tyqklwhdm57tfm5u863mdt2xrzrrzac4py8a0j9y6kzqcjy9zsp073t6
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzbjRpMWZ6eXZubjVUUlNL
|
||||
Z0N3ZkhoeVoxVzVwMHJzQzhJVjZ5MFhTU3dFCllwVWVWbm1KMTlUcEd0empxS1J2
|
||||
NzRSbkE5cEJLMmZCcjZBMTF0TUF2SEUKLS0tIFN6TVNEMU4rVVl1OEdzWGJSRmdl
|
||||
cndmbU16NkRmMHo5ZlJYMUFBUmlIZDQKNVXn3/twQKZC+74tRlpG2wx0hLEZuuka
|
||||
DKtNg6nnhd/UsVNF6/MSTwjnwXeilNemV7ffAbSE4tixcfBV3niILg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-06-09T13:04:33Z"
|
||||
mac: ENC[AES256_GCM,data:xKqvMTW+TTKPtuHh/pSGvxXXIpeKtzVWgwKPibGX9UTIpnDNzfylmkT6OouqQyI/HTQmiL67ch6gaFSMAbXfpw7JA9YpKif6p84rs3RelKzRLKinDpUtcvWhY1DEA2nsNWOdFHxu7EZhHRbXttRoB372kdV5063MJRvwuqslMpo=,iv:T4ff9w1AYGO9JIzuJz6VbPoS19OcIy9zFvOMLp3F2LE=,tag:x5Yk7tVSilKK68ZRhAnsIw==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
@@ -30,6 +30,7 @@ users:
|
||||
reonokiy: ENC[AES256_GCM,data:fPKdOPAKbXUvK5Jj08T0iSD23mhhkTXCexgB5q3v5JS4c6V4S+W14WOkS4UHrMQls/rHslw0NyMzS5G27A+5vN+EN+xJZfuRGg==,iv:tSdNOgs61tyt7/hUKt8bfKvpq9qOQU14ligdxBs/ATs=,tag:6IoS/p2StKtFREIpxsWkdg==,type:str]
|
||||
#ENC[AES256_GCM,data:cZznknXjlWF6eoEaTA==,iv:tdw/54W2evO1o5sq1syz3k0DZrm/rjflxqJpB9LZgvg=,tag:d60Ctc5YeSmhZJUURUmeSg==,type:comment]
|
||||
zqq: ENC[AES256_GCM,data:iFtM0pxIvXPHBnLEfHdmYGVWXuroDLgUaAKF+DmuBdq1NY+pr33oXNJzckFZfWgpIOuCm4cNg5j5R6nsG+zk2VWdi2vuITT4jA==,iv:qfBC/D1gJYXOZ0Fy2DkAb+ImDgXZWU6R/Z50hbVDR98=,tag:eCr6lbSieWDCNaTYzoQ0qQ==,type:str]
|
||||
zgq: ENC[AES256_GCM,data:cHYFToQ5ulEcb741Gg3X4lKj8ZJy1zcLHpkVQjQXt5hRAQtPsiPlegi2a1nUIAUb6sI//4ffcytlXpdK2sXewFe3ZiIXy3UVjQ==,iv:fKaPxpfh5ssOwAbmEsAPaQ45KrNtkHZb96IzWc6pD9s=,tag:Vt91B77SjxYaZ/HvWVBufA==,type:str]
|
||||
telegram:
|
||||
token: ENC[AES256_GCM,data:zfMATU2E6cwoiyfszV35vkQG6JSk00y589wmGEf4wQNncPhNsvh+NcSfnTwHTQ==,iv:Q46mUquhUZLGQsCDYitk4IPu24MpVnYmi7aHyZL/b1E=,tag:QVbrwAA9mWK/ToJfGIs9ug==,type:str]
|
||||
user:
|
||||
@@ -37,6 +38,8 @@ telegram:
|
||||
hjp: ENC[AES256_GCM,data:ZXTQhax0gT4PKw==,iv:MerbaWWC4SLazEuuJrxAxf9e5aaX9xpq9St+h9aqvMQ=,tag:x9knShK90OKZPcn9fKzvMA==,type:str]
|
||||
nginx:
|
||||
maxmind-license: ENC[AES256_GCM,data:MtmNo6hHlU75N6PvzF7P5i6Q+myV4Keb1JRXVeHxTennNpKfAndsKg==,iv:DqM91JX+1WX8Zqzha2Tm3ztFaSzKYQg+b9NvUm+6jxY=,tag:XnDTBL9MA/B8XfPZqdk7Eg==,type:str]
|
||||
acme:
|
||||
token: ENC[AES256_GCM,data:DrNdcyf2tiZ5nmjYmsG13V63ZuZhNG1c/kkGM7eXQWvRvDbu37nKWA==,iv:xc4gtNvZ/BYG+KmT1XgFfG3Z17bBLURazG8tz4/laxE=,tag:khnYVQWjiiaQC9VsJyLV6A==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
@@ -174,7 +177,7 @@ sops:
|
||||
UnR5Y24rSTk3WUV1VUgvQUFCVUxPZUEKv/lTy02gZYn4jF1uGtm+LhJd0m59Xe99
|
||||
+unmqUDh0ZqAhJU8o0jrBiWs1lXOHU7CkIom7tGEMHGUxHkS+Z/6GQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-06-09T12:54:56Z"
|
||||
mac: ENC[AES256_GCM,data:pAJ1mr02yp41jTcvy56OCUvJZh0NJXqAj582F85eevOIVy/GKQyvBonSkT0vN85q8UXw6tsNBpSqLi5MEoP2QhSP6x6mMZ6fHHGtkhw2ROmuTcfGdHDIq0SMU6arukEVDFlVsoneNXUUmdvwDjxAGv4qf7sI4ynPwu0V9xurYiI=,iv:ZuCObomHvfEPEKnepRyTOiojOEh6mfWW+bF/ytsTqiU=,tag:k0WuI8eewWeCQkiXDisjZw==,type:str]
|
||||
lastmodified: "2025-07-11T01:54:15Z"
|
||||
mac: ENC[AES256_GCM,data:LTpoXloCTzNtcYOqwA8UXtaorMzFBmFKb6LdOH7mjMDLsqIGIoWeVClt7WPP76K1amsmqjFLYkrdraqqHabLJB2/XKoSObkgZzLoF0YsknMsgJhkqEb9IwCBILBfAJdgwhuZQKHrMKRs5pePqJYSX2ZlgL4MRkwc6U6GVChRLxY=,iv:MZky3t9fGPtNqEdGEG1SYxhuWqDppNutaFI4GitmoKY=,tag:YaTLM9PSH2rAdb5syDvK1g==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
|
||||
@@ -10,6 +10,7 @@ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGwUhEAFHjkbUfOf0ng8I80YbKisbSeY4lq/byinV7lh
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF5bg5cayOLfnfUBJz8LeyaYfP41s9pIqUgXn6w9xtvR lly
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBoDGk9HYphkngx2Ix/vef2ZntdVNK1kbS9pY8+TzI41 yxf
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJi6O1Sf1BBV1dYyH1jcHiws+ntwVfV29+6Paq1CQaET hss
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFlBxisj3sU9QC8UC5gX6sakf7G03ybbkmHtD2cybuZA qmx
|
||||
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCmJoiGO5YD3lbbIOJ99Al2xxm6QS9q+dTCTtlALjYI5f9ICGZJT8PEGlV9BBNCRQdgb3i2LBzQi90Tq1oG6/PcTV3Mto2TawLz5+2+ym29eIq1QIhVTLmZskK815FpawWqxY6+xpGU3vP1WjrFBbhGtl+CCaN+P2TWNkrR8FjG2144hdAlFfEEqfQC+TXbsyJCYoExuxGDJo8ae0JGbz9w1A1UbjnHwKnoxvirTFEbw9IHJIcTdUwuQKOrwydboCOqeaHt74+BnnCOZhpYqMDacrknHITN4GfFFzbs6FsE8NAwFk6yvkNXXzoe60iveNXtCIYuWjG517LQgHAC5BdaPgqzYNg+eqSul72e+jjRs+KDioNqvprw+TcBBO1lXZ2VQFyWyAdV2Foyaz3Wk5qYlOpX/9JLEp6H3cU0XCFR25FdXmjQ4oXN1QEe+2akV8MQ9cWhFhDcbY8Q1EiMWpBVC1xbt4FwE8VCTByZOZsQ0wPVe/vkjANOo+brS3tsR18= 00@xmuhpc
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxcIWDQxVyIRqCGR4uWtrh4tLc025+q6du2GVsox8IzmBFkjNY8Au5GIMP5BKRstxFdg3f/wam8krckUN9rv5+OHB9U8HGz77Xs0FktqRVNMaDPdptePZQJ9A9eW3kkFDfQnORJtiVcEWfUBS3pi0QFOHylnG27YyC/Vjx9tjvtJWKsQEVTFJbFHPdi+G7lHTpqIGx+/a2JN9O6uVujXXYvjSVXsd+CWB9VMZMvYCIz2Ecb6RqR3brj4FhRRl8zyCj+J4ACYFdGWL98fTab2uPHbpVeKrefFFA43JOD/4zwBx/uw7MAQAq0GunTV3FpBfIAQHWgftf2fSlbz20oPjCwdYn9ZuGJOBUroryex7AKZmnSYM3biLHcctQfZtxqVPEU3W/62MUsI/kZb9RcF24JRksMoS2XWTiv2HFf5ijQGLXXOjqiTlGncwiKf65DwkDBsSxzgbXk5Uo86viq6UITFXPx/RytU+SUiN4Wb7wcBTjt/+tyQd1uqc7+3DCDXk= 01@xmuhpc
|
||||
|
||||
@@ -4,7 +4,7 @@ inputs:
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
model.private = true;
|
||||
model = { type = "server"; private = true; };
|
||||
system =
|
||||
{
|
||||
fileSystems =
|
||||
@@ -25,7 +25,7 @@ inputs:
|
||||
services =
|
||||
{
|
||||
sshd = {};
|
||||
xray.client.dnsmasq.hosts."git.nas.chn.moe" = "127.0.0.1";
|
||||
xray = { client.dnsmasq.hosts."git.nas.chn.moe" = "127.0.0.1"; xmuServer = {}; };
|
||||
beesd."/".hashTableSizeMB = 10 * 128;
|
||||
nfs."/" = [(inputs.topInputs.self.config.dns."chn.moe".getAddress "wg1.pc")];
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
xray-client:
|
||||
uuid: ENC[AES256_GCM,data:97aX07G5FPumdWcDxnYOs6fRgljXWuwyNXGg1d7zdbUUfNnb,iv:+wAC/DZXsg+evYFA4DMfLw5Ut3ExQl1RgZ/2AsNQDpo=,tag:ebD77muITHof+FQMydWobg==,type:str]
|
||||
wireguard: ENC[AES256_GCM,data:JaOSq474mGOoQQcdJ/j9fYo2e1vjXMPxJ69TOd079FrSkbzbIteWww5f8Xo=,iv:uy/NC2+tibL61XJDZK/spKjV9u0oXK4YzjFjYmCAL0k=,tag:en+c8cHaPvDqJL+EpQjr0g==,type:str]
|
||||
xray-xmu-server: ENC[AES256_GCM,data:3O5rFi5szla70M/c62JV4nGWKPSOREImrOucjeVYf9bde6K8,iv:PGCqlmHtaNuWOtAAeJ6O+CWFpMszijozU1OpUFrftjs=,tag:iGTOoNvQhhZy2FL9jy1KIQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
@@ -21,7 +22,7 @@ sops:
|
||||
by9Rd0U0bzNiK21BQTNxN1RuQ09DQVkKJmSlzV5ppEkZFljsS17ZWmoI++fz4tJh
|
||||
kTdoAStG1zsKASHyZTsmdm3RBDO3qV1KhQC2gC7d4EiwNZngxOOZJg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-06-09T01:22:01Z"
|
||||
mac: ENC[AES256_GCM,data:OxRUW3e2SXTTdb7Iwvsf/UaHsTIVxohJwRIFExh5N/dJhU9Ui8omKBjkooiGaysrZEVEZNAWSp2zvTPXUdZrtW2fikyhF6Fsg7jUFFTqhV/sjYMy7gISbfkcGF9SuYGByuuySyXPqsfg+ESeBmMVZiqDSEPYJWu+q8OwThdhsAM=,iv:UnSfmuxcV+tr7wd59Xg0MG2QbP2uOshVhN5C++9ZSzA=,tag:cWiG85xv2OuiBOoAlvVBGw==,type:str]
|
||||
lastmodified: "2025-06-30T10:53:22Z"
|
||||
mac: ENC[AES256_GCM,data:XJIKLsszOcJfL9RDcFs7nTDfVIxUGtwhKZhkC7eCKni03b3M/sl2cIwAJ/L20Q+riP2HFcS1ljQA+SjlnY29KWr7DqJ1dM0qcqHjMSlWjurMWPgD4Lf8C7kx2J+6naYiQotQb6y7AfRF9XxAJUaHQe9DdlqHT/bmbtVW5VN1tzs=,iv:IhU7Wo19KOsqxdlSuZg3KtDc08E0dUq2Ahb1J09iLK4=,tag:N9TumoFTKEw/4DT51Lyjjg==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
|
||||
@@ -26,6 +26,7 @@ inputs:
|
||||
xray.client = {};
|
||||
beesd."/".hashTableSizeMB = 64;
|
||||
sshd = {};
|
||||
waydroid = {};
|
||||
};
|
||||
bugs = [ "xmunet" ];
|
||||
};
|
||||
|
||||
@@ -72,13 +72,17 @@ inputs:
|
||||
};
|
||||
};
|
||||
sshd = {};
|
||||
xray.client.dnsmasq.hosts = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(name: { inherit name; value = "144.34.225.59"; })
|
||||
[ "mirism.one" "beta.mirism.one" "ng01.mirism.one" "initrd.vps6.chn.moe" ])
|
||||
)
|
||||
// { "4006024680.com" = "192.168.199.1"; };
|
||||
xray =
|
||||
{
|
||||
client.dnsmasq.hosts = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(name: { inherit name; value = "144.34.225.59"; })
|
||||
[ "mirism.one" "beta.mirism.one" "ng01.mirism.one" "initrd.vps6.chn.moe" ])
|
||||
)
|
||||
// { "4006024680.com" = "192.168.199.1"; };
|
||||
xmuClient = {};
|
||||
};
|
||||
nix-serve = {};
|
||||
misskey.instances.misskey.hostname = "xn--qbtm095lrg0bfka60z.chn.moe";
|
||||
beesd."/" = { hashTableSizeMB = 4 * 128; threads = 4; };
|
||||
@@ -104,14 +108,14 @@ inputs:
|
||||
podman = {};
|
||||
ananicy = {};
|
||||
keyd = {};
|
||||
lumericalLicenseManager.macAddress = "745d22c7d297";
|
||||
lumericalLicenseManager.macAddress = "74:5d:22:c7:d2:97";
|
||||
searx = {};
|
||||
kvm.aarch64 = true;
|
||||
nspawn = [ "arch" "ubuntu-22.04" "fedora" ];
|
||||
nfs."/" = [ "192.168.84.0/24" ];
|
||||
};
|
||||
bugs = [ "xmunet" "backlight" "amdpstate" "iwlwifi" ];
|
||||
packages = { mathematica = {}; vasp = {}; lammps = {}; };
|
||||
packages = { mathematica = {}; vasp = {}; android-studio = {}; };
|
||||
};
|
||||
boot.loader.grub =
|
||||
{
|
||||
|
||||
@@ -13,11 +13,10 @@ nix:
|
||||
remote: ENC[AES256_GCM,data:uosYkxTCB0wiY+Uufk//OcBZFN3EzbZoQGZ95M9eZMjQ5AobAZqosi4laE+EMcZL1CqYqlWXaSoEUOB8biUaZPseo+1AX1TlmUgZ7QpkfOX0VKZu01C6C+lVyqVqMFq6z1BFyX/oeITMIfnd4a/2KwJCHLAZ4hMkJ5p+aJwByKGa3N/2m41HH/1S3z7pYQWj7YJxunTPPG6WNSiRncQki11rvmddwnXmsBF89+jW1Phge8U295haC57T5oIGPxR645IeTK4ZUlL8eVuZ+BhsnwbkYcaxvjSwe+DOIVPupR8GW+gis7KxwE89kqvnQhinamexcPUz4lGHlqO/Xn6jrJx6T/wXF+19epAzeHapYte3dTWNsdPwPLPJihT16YT5fwrLnH3zq8kexWz1crmnCGUoaBs4S2tHWHLgv2lTv0IHLx5F6ijpDBj/Avg9YILIURzdeea+rBxdycHasUDTVlJtYKRH5J+WbAKWI+oJ5qmXjIRUYL+O9xIUfOGO+1b3xs8MYxRWuvDV2P88N8vN,iv:yQQp5wjbSVn1oia5yL7d6GF9Vo704G0iOQRGMbzQHzg=,tag:bpBag5y5n+7ojOa8QOcDvA==,type:str]
|
||||
searx:
|
||||
secret-key: ENC[AES256_GCM,data:KhIP+Rz3rMfNgPEGTlKGvm6gl1/ZuPI=,iv:GcaLEJHKJO3n6IaeiFr9PaJ6eNx04/VjX3UgmBF429g=,tag:HkplyH9hTHUaEZ709TyitA==,type:str]
|
||||
xray-xmu-client:
|
||||
uuid: ENC[AES256_GCM,data:XiUkReTJLAxZNWFVeD6EiOtUX5tsyPLFi6QyDBdHyB4v5/mD,iv:QppdtP2CFDEVhlrmDJKYBGc1zYGJvpGYxLfsBAMxDSI=,tag:jzMSFRit+aBzWMkaa3+5hA==,type:str]
|
||||
cookie: ENC[AES256_GCM,data:fx/cqNNpI71FslngfeXFQA==,iv:xZEtOsKgS/8xNqF4B6NKI9+klrpNcraW17KKirMnEfM=,tag:YyczKED2Yo0D6I+RvMjJLg==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
@@ -37,8 +36,7 @@ sops:
|
||||
OUlxNjdQaXdXMkZ6bnV1ek4yZ2dpbkEKpKGOAxo5Eef2jtGrg4iSzmGCeg+vTgvu
|
||||
+K8b+O19MIkGMDBm6UbYUPtc/7eqoEZRiTUzNMTmfkLVS4ul5zou9A==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-05-24T11:27:02Z"
|
||||
mac: ENC[AES256_GCM,data:uNkThOX3NEUeiaJVavZ0rCpQRT+GbRXADiMuAwb/tg38fBrKQeUO9ohicl/UfiDFRTfCaiuH3T757jX2b51go2s0B6n7DOvPYYZ5EWGnM69RFxrdDfWfge8n8/SHmuKR9dPJb/eSa8HAs8uDnqBPoR5SqG5lnyZs3a7P/kjK2T4=,iv:snmnuYmcuyhGs4YrIGFLmDffFE9yecB/vsM0MvxBR4k=,tag:vbqA7jvVCFHvLoLmKbfO4g==,type:str]
|
||||
pgp: []
|
||||
lastmodified: "2025-06-30T11:24:37Z"
|
||||
mac: ENC[AES256_GCM,data:V6Gs9hCPIb42nW81Gmy1dz5LFLeX97UuzVbvst/rtuSJHdFzXKxYqIGjHNRK5mGWG/NdTXQ79ELlvpSOgKYAk6gn9ZMn9wCDDbe6spDoGBWL4Ky7mCiSPRcLZ++J+2nP0Q987kZ6IMdMWkFNJmOKWBX/nnp4/aicwyteqNHt4cI=,iv:1wWS0D4RJeWKERfqMQRB75Nh1oKSQzF+r5yOphMrg9Q=,tag:DBPZx1+X7nMLW9xsyEn62A==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
|
||||
@@ -60,8 +60,8 @@ inputs:
|
||||
];
|
||||
};
|
||||
};
|
||||
packages.vasp = {};
|
||||
user.users = [ "chn" "xll" "zem" "yjq" "gb" "wp" "hjp" "wm" "GROUPIII-1" "GROUPIII-2" "GROUPIII-3" ];
|
||||
packages = { vasp = {}; lumerical = {}; };
|
||||
user.users = [ "chn" "xll" "zem" "yjq" "gb" "wp" "hjp" "wm" "GROUPIII-1" "GROUPIII-2" "GROUPIII-3" "zgq" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ inputs:
|
||||
sshd.motd = true;
|
||||
xray.client.dnsmasq.extraInterfaces = [ "eno146" ];
|
||||
beesd."/" = { hashTableSizeMB = 128; threads = 4; };
|
||||
xrdp = { enable = true; hostname = [ "srv1.chn.moe" ]; };
|
||||
samba = { hostsAllowed = ""; shares = { home.path = "/home"; root.path = "/"; }; };
|
||||
};
|
||||
packages.packages._prebuildPackages =
|
||||
|
||||
@@ -7,18 +7,13 @@ inputs:
|
||||
model.type = "server";
|
||||
system =
|
||||
{
|
||||
fileSystems =
|
||||
fileSystems.mount = let inherit (inputs.config.nixos.model.cluster) clusterName nodeName; in
|
||||
{
|
||||
mount = let inherit (inputs.config.nixos.model.cluster) clusterName nodeName; in
|
||||
{
|
||||
vfat."/dev/disk/by-partlabel/${clusterName}-${nodeName}-boot" = "/boot";
|
||||
btrfs."/dev/disk/by-partlabel/${clusterName}-${nodeName}-root1" =
|
||||
{ "/nix" = "/nix"; "/nix/rootfs/current" = "/"; };
|
||||
nfs."${inputs.topInputs.self.config.dns."chn.moe".getAddress "wg1.pc"}:/" =
|
||||
{ mountPoint = "/nix/remote/pc"; hard = false; };
|
||||
};
|
||||
swap = [ "/nix/swap/swap" ];
|
||||
cluster.masterAddress = "2";
|
||||
vfat."/dev/disk/by-partlabel/${clusterName}-${nodeName}-boot" = "/boot";
|
||||
btrfs."/dev/disk/by-partlabel/${clusterName}-${nodeName}-root1" =
|
||||
{ "/nix" = "/nix"; "/nix/rootfs/current" = "/"; };
|
||||
nfs."${inputs.topInputs.self.config.dns."chn.moe".getAddress "wg1.pc"}:/" =
|
||||
{ mountPoint = "/nix/remote/pc"; hard = false; };
|
||||
};
|
||||
nixpkgs.cuda.capabilities =
|
||||
[
|
||||
@@ -39,7 +34,7 @@ inputs:
|
||||
slurm =
|
||||
{
|
||||
enable = true;
|
||||
master = "srv2-node1";
|
||||
master = "srv2-node0";
|
||||
node =
|
||||
{
|
||||
srv2-node0 =
|
||||
@@ -80,8 +75,8 @@ inputs:
|
||||
};
|
||||
};
|
||||
};
|
||||
packages = { vasp = {}; mumax = {}; lammps = {}; };
|
||||
user.users = [ "chn" "xll" "zem" "yjq" "gb" "wp" "hjp" "wm" "lly" "yxf" "hss" "zzn" "zqq" ];
|
||||
packages.vasp = {};
|
||||
user.users = [ "chn" "xll" "zem" "yjq" "gb" "wp" "hjp" "wm" "lly" "yxf" "hss" "zzn" "zqq" "qmx" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,22 +4,25 @@ inputs:
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
model.cluster.nodeType = "master";
|
||||
system =
|
||||
{
|
||||
nixpkgs.march = "skylake";
|
||||
network =
|
||||
{
|
||||
static.eno2 = { ip = "192.168.178.1"; mask = 24; gateway = "192.168.178.2"; dns = "192.168.178.2"; };
|
||||
wireless = [ "457的5G" ];
|
||||
static.eno2 = { ip = "192.168.178.1"; mask = 24; };
|
||||
wireless = [ "409" ];
|
||||
masquerade = [ "eno2" ];
|
||||
trust = [ "eno2" ];
|
||||
};
|
||||
nix.remote.slave = {};
|
||||
fileSystems.swap = [ "/dev/disk/by-partlabel/srv2-node0-swap" ];
|
||||
};
|
||||
services =
|
||||
{
|
||||
xray.client = { dnsmasq = { extraInterfaces = [ "eno2" ]; hosts."hpc.xmu.edu.cn" = "121.192.191.11"; }; };
|
||||
beesd."/" = { hashTableSizeMB = 16 * 128; loadAverage = 8; };
|
||||
xrdp = { enable = true; hostname = [ "srv2.chn.moe" ]; };
|
||||
samba = { hostsAllowed = ""; shares = { home.path = "/home"; root.path = "/"; }; };
|
||||
groupshare = {};
|
||||
hpcstat = {};
|
||||
|
||||
@@ -6,13 +6,9 @@ mariadb:
|
||||
hpcstat:
|
||||
key: ENC[AES256_GCM,data:+Z7MRDkLLdUqDwMrkafFKkBjeCkw+zgRoAoiVEwrr+LY0uMeW8nNYoaYrfz6Ig8CMCDgX3n/DMb0ibUeN32j3HShQIStbtUxRPGpQMyH+ealbvgskGriTFpST4VPyQxNACkUpq/e+sh2CmLbKkSxhamkjKOXwsfqrBlgVbEkp7u7HkWGuAaYL1oPGt0Q94fWXwH0UVhRYZYQ2iFA/S6SEZY8gxaTIGDKUdWU9+fOHzPQ5WfhxtKYU4p4ydyfYsAt6ffqnPSx/SI72GsUCOJ4981JX8TuvnEzx3gQLVFYheK6NibTWCy6eODbvguieVOTHSvCPTrHmoP12lHVWU2kKzLwv70Jl7sXyzKHYROG0D+/z/4DKlNeotKM/IA0q2cST08/lwSKN7WDDmrt+O6xXhvwby28ZYKEsSvvrfV+VIKzHPl84ZKbUEX5xv/GHc3THfznUvKKz5PzDiqrkjCkEt5PRMsVW9A6MU1+QEUr+sXLLtcUd2CCL87c8CpwNHJx1us6vJ4ji1gu0PGoT+60,iv:yU6j9W2Hs2D34uHMJqqPFbNy2pNEZY2kzXoNdhPMSmA=,tag:TNvEfMVrhu7HrNxY8qe5mg==,type:str]
|
||||
wireless:
|
||||
#ENC[AES256_GCM,data:xrg3Wxj/ghbWgg==,iv:6stu7voI5no2Y3YmnMrvTS8hev3eqjoWAyD5zTgyehc=,tag:cxkS7y7S1oM+/SJmlT10fw==,type:comment]
|
||||
457的5G: ENC[AES256_GCM,data:QjHlyGU4JIYymyh41T+c33T3EOpbqDOoD3U+v6/BzjlWLLeZQXU2hwPCVh4fi2bwn7yNkp4ygAYmFPVPZWoT1A==,iv:Tc6Guzsn5hkjWH6UWSb1KlfWCBXIi2OWdn/wttmCXnQ=,tag:FhyH6JmjSTuqSeFy+GyQhg==,type:str]
|
||||
#ENC[AES256_GCM,data:n9OPSJsB7yNk,iv:xQzKJxqPB7uT83m/B4UoOje6NQbPLhuHR7Hp93oNz8A=,tag:gtsTx6ALnS/7fIDd7VimOg==,type:comment]
|
||||
"409": ENC[AES256_GCM,data:XJ2apDx9E4RM7YzK6wYzxn4eBkVS3l6LIaMtUai2MZ/W0xkaixyV/g/s+cVQtgph2gEcNoLOWbsxr3h8CsrOTA==,iv:O643ytrgHKB4RM6lZKZcr0fLmS2icRnek9praw43jWc=,tag:6Pk7CmiJyvAeW/1V4mvRJQ==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
@@ -32,8 +28,7 @@ sops:
|
||||
M0xoL1dQR0kvMWpzN0RMNWVCTFQxNFUKj9LPjBo5NGOrGYNvu8qZ13PLYjLEWllU
|
||||
LARzEn4XgkeHckouwvxZYMCx7WxmAruRWaOvnxTIczzSNP7wIrqnkA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-04-10T10:44:43Z"
|
||||
mac: ENC[AES256_GCM,data:6EeWT8IiCGyRdR/9WDoTTM8bBuhzf2LtP1kahCgfvFpU6g5HB+qG5O0eXaL0DMKg7OQJKHIS/wZVaEierVwno0CnP1WR7y9l6Rlab2nVG4YCNkEkwqZgIWFOUi0aZrZQc7WC3rUk1gxiJK38nEa4ebk8oqAbyHyKHsFAeUcMbqA=,iv:oqRLvYsXct+OwcymXslEH4o03vLNeV2eU/4zK8R+gKs=,tag:0d1DYjCGRewUd4aHPIpFSw==,type:str]
|
||||
pgp: []
|
||||
lastmodified: "2025-07-10T10:08:37Z"
|
||||
mac: ENC[AES256_GCM,data:ELeHLFJuOUs8CFIuu08zqp56AijpxxLKlfUo6cWmqwURy/BC6CTFqkNwsD8NirCzSsNTRnwk3pAVXPjJCrk8rnnH4uqiA639h3qMdEpHJLsVhv2+ounGObW7+R/IYJQaSmBWHzZimQsAbp2eVufu3mnu3wjUOhXM6xs0ofuxLWM=,iv:M7PK2S4Okb0MhsJ6d/bJfkMUOoXUMwbWVsHiuxE6Nt4=,tag:4QwSM0dU0mY5Xs03RS1FUw==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.9.2
|
||||
version: 3.10.2
|
||||
|
||||
@@ -4,17 +4,16 @@ inputs:
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
model.cluster.nodeType = "master";
|
||||
system =
|
||||
{
|
||||
nixpkgs.march = "znver3";
|
||||
network =
|
||||
{
|
||||
static.enp58s0 = { ip = "192.168.178.2"; mask = 24; };
|
||||
static.enp58s0 =
|
||||
{ ip = "192.168.178.2"; mask = 24; gateway = "192.168.178.1"; dns = "192.168.178.1"; };
|
||||
trust = [ "enp58s0" ];
|
||||
wireless = [ "457的5G" ];
|
||||
masquerade = [ "enp58s0" ];
|
||||
};
|
||||
fileSystems.swap = [ "/nix/swap/swap" ];
|
||||
};
|
||||
services.beesd."/".hashTableSizeMB = 64;
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ inputs:
|
||||
matrix = { port = 8009; redisPort = 6380; };
|
||||
};
|
||||
vaultwarden = {};
|
||||
photoprism.enable = true;
|
||||
photoprism = {};
|
||||
nextcloud = {};
|
||||
freshrss = {};
|
||||
send = {};
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
config =
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
system =
|
||||
{
|
||||
fileSystems =
|
||||
{
|
||||
mount =
|
||||
{
|
||||
vfat."/dev/disk/by-partlabel/test-boot" = "/boot";
|
||||
btrfs."/dev/disk/by-partlabel/test-root1" = { "/nix" = "/nix"; "/nix/rootfs/current" = "/"; };
|
||||
};
|
||||
};
|
||||
nixpkgs.march = "znver4";
|
||||
network = {};
|
||||
};
|
||||
services.sshd = {};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
nixvirt:
|
||||
chn: ENC[AES256_GCM,data:0llBtdnPLl8=,iv:0w0huoNCvIiaL77Thj1iAwRY5edDlN7I4mMwiNKCzOc=,tag:Eh1b7dymn7jQtL5/rsxC1Q==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTcldLRERrOHdadVA4RXdQ
|
||||
dmsxL1o5aDdJTitqdXBzRWxqVmZKUzFtTlUwCnc2a1N4WUNEVUhsSlFuSExjR0Rl
|
||||
TlFnNjVpUkpmbWdxYW5oblk5dGQ0THMKLS0tIDFBa0FKQXBPYThFTUwvd2tIaU9p
|
||||
TERYVkp3dkUxU2ZaTnFRamRKclRRa1EKosUuvJXekUIxIHL8s/QuZf+hCXQS5dMC
|
||||
HqZ74f/jvIW8i/Etu29VtK3n8MD8W1EenhJjfxOvhpRpLpzQP2GImg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1vgqvdqqe3mn0gvh0hydvu9c5f9yn5vek08cagyvwjhyta6utpvuq00g9c2
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMK2F0R1JRR2t6NDhXVnVD
|
||||
Unh5QmxDaGJtWmhsb1ZDRkMzUlpSeU9GL3lNCkU0ZVYxaWs3MHZDQlNHS25WMTl3
|
||||
VVVtQUlxeXNQNVQrSTdSbWYzSmlPVGMKLS0tIDlyRm1tYlR3WU9ISjc2T3BSY2FP
|
||||
Z3h2QWh6eDB6L1krbU9SS050dUhEamMKHnvdCmLuhuIfeBRs3LJ6IEatqrlMJNnc
|
||||
vhPTVgfn+M8dGo+odTTwlvr5XGzE5cMSxGtdSE33JsbBFfVyaPCFjQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-05-16T05:29:11Z"
|
||||
mac: ENC[AES256_GCM,data:s1HBVQUDbYP63EntEXe/+9mqFj2zGEtx3ibFauBYmjJvtvw2hs44ODNebMxjasT8zTYICJWWZJxwMvpUs/CbcmSjPAXTV8379lzlOmG2wZLezF+9jWdJi3ZDvM9Y1D0/4GnaIRHof/+kPn/ykFE/gQhP5PQ4OtoV+VTR2fuwDaA=,iv:TUTM8tyZxiAjU3afazfmse+LL53hrSFSCIX4KIDyQq8=,tag:Vx4GsOPAXaZz0rEjsJS8sw==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
@@ -1,50 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
config =
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
system =
|
||||
{
|
||||
fileSystems =
|
||||
{
|
||||
mount =
|
||||
{
|
||||
vfat."/dev/disk/by-partlabel/test-boot" = "/boot";
|
||||
btrfs."/dev/disk/by-partlabel/test-root1" = { "/nix" = "/nix"; "/nix/rootfs/current" = "/"; };
|
||||
};
|
||||
};
|
||||
nixpkgs.march = "znver4";
|
||||
network = { dhcp = [ "nixvirt" ]; bridge.nixvirt.interfaces = [ "enp1s0" ]; };
|
||||
};
|
||||
services =
|
||||
{
|
||||
sshd = {};
|
||||
nixvirt =
|
||||
{
|
||||
subnet = 123;
|
||||
instance =
|
||||
{
|
||||
chn =
|
||||
{
|
||||
memory = { sizeMB = 2048; dedicated = true; };
|
||||
cpu = { count = 4; set = builtins.genList builtins.toString 4; };
|
||||
network =
|
||||
{
|
||||
bridge = true;
|
||||
vnc.port = 15901;
|
||||
};
|
||||
};
|
||||
chn2 =
|
||||
{
|
||||
owner = "chn";
|
||||
memory.sizeMB = 2048;
|
||||
cpu.count = 4;
|
||||
network = { address = 3; portForward.tcp = [{ host = 5694; guest = 22; }]; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
nixvirt:
|
||||
chn: ENC[AES256_GCM,data:0llBtdnPLl8=,iv:0w0huoNCvIiaL77Thj1iAwRY5edDlN7I4mMwiNKCzOc=,tag:Eh1b7dymn7jQtL5/rsxC1Q==,type:str]
|
||||
chn2: ENC[AES256_GCM,data:vlvFNwMfTMg=,iv:DKgX3DCvkfADF/Pj31bRTx/dfTiMxv/JaeN76Kppob8=,tag:SOioaCz/CvvLn2jB+08THQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2SGQ0R20zci9aU1l4d2Fs
|
||||
YkRZQ1FGUW1vSEd3S3FBdGlSTXB4dW54UVJJCk5MMEFZSzdYTFRQL1FRZUFWTXFh
|
||||
cC90bUx2dkdHUFVoMkhyNjR6U0w1QTAKLS0tIDZHZE4yNlV4cFBTVGN4c3VYZXZ5
|
||||
enZoU21MQ2VJbHlhSnhwUkNXZjV6OXcKzvdz1TNs/PDISx+QSi6cJ8vWNtZo4jfD
|
||||
qsrwpxvHou/wptLzYg5gXQuXB0izpOW/AtqA1XqLcTUbLzcRhqFvMg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age17a8y4yr2ckuek67rt786ujuf7705gvj3vv6ezktxxmgayea9zcyqet7hgc
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtWUJVZmdVbWxXck5EY0tR
|
||||
cFRwZTlWVVpObjFneE95bXNPSUxjNE1DTlg0ClNQRy8yVmF6QWxuY3RGLzdJVEE4
|
||||
WXEwb1NGVUlJWFRqeWlyN1J0eE15QnMKLS0tIENRQWJ0VXlzNHV6MXh0QUVRZlJu
|
||||
RFFteDMzeGltVER3QjlpdUllZVNJS3MKyOMAu5xYr1z0YlNDFvaE4l4bposMTPUJ
|
||||
K13yerfRBxDlOrMhG/lSovusBPkmS3HejDedGgYi1WMvgLuOkNWZ2A==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-05-18T01:55:44Z"
|
||||
mac: ENC[AES256_GCM,data:wGHagytOT30EgjPezkaLXrqml/tn8oMzplYgThb9JbnXJzpCMnZnXeAlnRW/zdXY+Vt+kRfGCm2W/3sif5wB+gu5DCIeGC6OZy9brMVIQLceQ6Wp7IwPTDjMIGYtqe+T3QX6LFAMPUVZOHNBL9eRdO27G2TGP1ojH69MwNt4aQo=,iv:Rn26bQ8crsVFbLAxPcvLeQWwRP484rS/UFnmg8xeTwc=,tag:zs4S6VPNKFUZU6xxC2rIuQ==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
@@ -1,27 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
config =
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
system =
|
||||
{
|
||||
fileSystems =
|
||||
{
|
||||
mount =
|
||||
{
|
||||
vfat."/dev/disk/by-partlabel/test-boot" = "/boot";
|
||||
btrfs."/dev/disk/by-partlabel/test-root1" = { "/nix" = "/nix"; "/nix/rootfs/current" = "/"; };
|
||||
};
|
||||
};
|
||||
nixpkgs.march = "haswell";
|
||||
network = {};
|
||||
};
|
||||
services =
|
||||
{
|
||||
sshd = {};
|
||||
nginx = { enable = true; applications.example = {}; };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
hello: ENC[AES256_GCM,data:y6Kl7kHqgft7T1eiFEeIppvosCACIcVWIQm6TzjS6RgUkJEg17GEZFRy2zTvVg==,iv:wChah8rTtEkkR8pRHO9NdhaGBwsTrrP+tPp7k2SOdn0=,tag:jRdYgJoKz+Q+/m8l/03JoQ==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
azure_kv: []
|
||||
hc_vault: []
|
||||
age:
|
||||
- recipient: age19ax6vm3pv8rph5tq3mmehd9sy9jk823tw8svsd790r0lkslycquqvlwz9m
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTcldLRERrOHdadVA4RXdQ
|
||||
dmsxL1o5aDdJTitqdXBzRWxqVmZKUzFtTlUwCnc2a1N4WUNEVUhsSlFuSExjR0Rl
|
||||
TlFnNjVpUkpmbWdxYW5oblk5dGQ0THMKLS0tIDFBa0FKQXBPYThFTUwvd2tIaU9p
|
||||
TERYVkp3dkUxU2ZaTnFRamRKclRRa1EKosUuvJXekUIxIHL8s/QuZf+hCXQS5dMC
|
||||
HqZ74f/jvIW8i/Etu29VtK3n8MD8W1EenhJjfxOvhpRpLpzQP2GImg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
- recipient: age1vgqvdqqe3mn0gvh0hydvu9c5f9yn5vek08cagyvwjhyta6utpvuq00g9c2
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMK2F0R1JRR2t6NDhXVnVD
|
||||
Unh5QmxDaGJtWmhsb1ZDRkMzUlpSeU9GL3lNCkU0ZVYxaWs3MHZDQlNHS25WMTl3
|
||||
VVVtQUlxeXNQNVQrSTdSbWYzSmlPVGMKLS0tIDlyRm1tYlR3WU9ISjc2T3BSY2FP
|
||||
Z3h2QWh6eDB6L1krbU9SS050dUhEamMKHnvdCmLuhuIfeBRs3LJ6IEatqrlMJNnc
|
||||
vhPTVgfn+M8dGo+odTTwlvr5XGzE5cMSxGtdSE33JsbBFfVyaPCFjQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-05-10T03:54:30Z"
|
||||
mac: ENC[AES256_GCM,data:JMr6ybbOk7tDZKUo11bd0xwUfLUuE4DIB5sYOCEVuaXLpDirgMgNSQgayqnnYDLOC7kGA7wDbbcxWhdaT8TcyYwdeha3SgA9mjkruPtOZ4R+ozfLDeqa59h2P+xronaOCDdl9G2JbhLA+k/S2ImBP43iPbcycJViSQs0RrntMxY=,iv:3ZILO4L01r4I2SJWOxe4pp9XLWo6KPPl3t/IbIf07+8=,tag:jhf73Y42fOYmeQS2oA0qSA==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.9.2
|
||||
@@ -46,7 +46,7 @@ inputs:
|
||||
element.instances."element.chn.moe" = {};
|
||||
synapse-admin.instances."synapse-admin.chn.moe" = {};
|
||||
catalog.enable = true;
|
||||
main.enable = true;
|
||||
main = {};
|
||||
nekomia.enable = true;
|
||||
blog = {};
|
||||
sticker = {};
|
||||
@@ -55,7 +55,7 @@ inputs:
|
||||
};
|
||||
coturn = {};
|
||||
httpua = {};
|
||||
mirism.enable = true;
|
||||
mirism = {};
|
||||
fail2ban = {};
|
||||
beesd."/" = {};
|
||||
};
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
# install nix
|
||||
|
||||
1. download [nix-portable](https://github.com/DavHau/nix-portable),
|
||||
move the executable file to `$PATH`, rename it to `nix-portable` and make it executable.
|
||||
2. create several symlinks (including `nix` `nix-store` etc.) to it.
|
||||
3. create file `~/.config/nix/nix.conf` with the following content: `ignored-acls = lustre.lov`
|
||||
4. run `nix --version`, wait for it to initialize and print the version.
|
||||
1. Build nix using `nix build github:NixOS/nixpkgs/nixos-24.11#nixStatic`, upload, create symlink `nix-store` `nix-build` etc. pointing to it.
|
||||
2. Upload `.config/nix/nix.conf`.
|
||||
|
||||
# install or update packages
|
||||
|
||||
1. run `nix build github:CHN-beta/nixos#xmuhk` elsewhere (on NixOS is better, to avoid impure from FHS envs)
|
||||
2. `nix-store --export $(nix-store -qR ./result) | xz -T0 | pv > xmuhk.nar.xz`
|
||||
3. copy `xmuhk.nar.xz` to hpc, import it with `cat xmuhk.nar.xz | nix-store --import`
|
||||
4. create gcroot symlink: `ln -s /nix/store/xxxx-xmuhk ~/.nix-portable/nix/var/nix/gcroots/current`
|
||||
5. optionally `nix gc`
|
||||
6. create `nix-exec` in `$PATH` with the following content, make it executable:
|
||||
```sh
|
||||
#!/usr/bin/env sh
|
||||
nix shell ~/.nix-portable/nix/var/nix/gcroots/current -c "$(basename "$0")" "$@"
|
||||
```
|
||||
7. make symlinks to `nix-exec` for needed commands, e.g. `ln -s singularity nix-exec`
|
||||
1. On nixos, make sure `/public/home/xmuhk/.nix` is mounted correctly.
|
||||
2. Build using `sudo nix build --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' .#xmuhk` .
|
||||
3. Diff store using `sudo nix-store --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' -qR ./result | grep -Fxv -f <(ssh xmuhk find .nix/store -maxdepth 1 -exec realpath '{}' '\;') | sudo xargs nix-store --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' --export | xz -T0 | pv > xmuhk.nar.xz` .
|
||||
4. Upload `xmuhk.nar.xz` to hpc.
|
||||
5. On hpc, `pv xmuhk.nar.xz | xz -d | nix-store --import` .
|
||||
6. Create gcroot using `nix build /xxx-xmuhk -o .nix/state/gcroots/current`, where `/xxx-xmuhk` is the last path printed by `nix-store --import` .
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# sudo nix build --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' .#xmuhk
|
||||
# sudo nix-store --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' -qR ./result | grep -Fxv -f <(ssh xmuhk find .nix/store -maxdepth 1 -exec realpath '{}' '\;') | sudo xargs nix-store --store 'local?store=/public/home/xmuhk/.nix/store&state=/public/home/xmuhk/.nix/state&log=/public/home/xmuhk/.nix/log' --export | xz -T0 | pv > xmuhk.nar.xz
|
||||
# cat data.nar | nix-store --import
|
||||
{ inputs, localLib }:
|
||||
let
|
||||
pkgs = import inputs.nixpkgs (localLib.buildNixpkgsConfig
|
||||
@@ -8,37 +5,28 @@ let
|
||||
inputs = { inherit (inputs.nixpkgs) lib; topInputs = inputs; };
|
||||
nixpkgs = { march = null; cuda = null; nixRoot = "/public/home/xmuhk/.nix"; };
|
||||
});
|
||||
# go = pkgs.go.overrideAttrs (prev:
|
||||
# {
|
||||
# buildInputs = builtins.filter (x: x != pkgs.glibc.static) prev.buildInputs;
|
||||
# });
|
||||
# buildGoModule = pkgs.buildGoModule.override { inherit go; };
|
||||
# singularity = (pkgs.singularity.override { inherit buildGoModule; }).overrideAttrs (prev:
|
||||
# {
|
||||
# configureFlags = builtins.filter (x: x != "--without-libsubid") prev.configureFlags;
|
||||
# buildInputs = prev.buildInputs ++ [ pkgs.shadow ];
|
||||
# # env.CGO_ENABLED = "1";
|
||||
# # autoPatchelfFlags = [ "--keep-libc" ];
|
||||
# });
|
||||
singularity = pkgs.singularity.overrideAttrs (prev:
|
||||
{
|
||||
configureFlags = builtins.filter (x: x != "--without-libsubid") prev.configureFlags;
|
||||
buildInputs = prev.buildInputs ++ [ pkgs.shadow ];
|
||||
# env.CGO_ENABLED = "1";
|
||||
# autoPatchelfFlags = [ "--keep-libc" ];
|
||||
});
|
||||
lumericalLicenseManager =
|
||||
let
|
||||
ip = "${pkgs.iproute2}/bin/ip";
|
||||
awk = "${pkgs.gawk}/bin/awk";
|
||||
sed = "${pkgs.gnused}/bin/sed";
|
||||
chmod = "${pkgs.coreutils}/bin/chmod";
|
||||
sing = "${singularity}/bin/singularity";
|
||||
sing = "/public/software/singularity/singularity-3.8.3/bin/singularity";
|
||||
in pkgs.writeShellScriptBin "lumericalLicenseManager"
|
||||
''
|
||||
echo "Cleaning up..."
|
||||
rm -rf /tmp/lumerical
|
||||
${sing} instance stop lumericalLicenseManager || true
|
||||
[ -d /tmp/lumerical ] && chmod -R u+w /tmp/lumerical && rm -rf /tmp/lumerical || true
|
||||
mkdir -p /tmp/lumerical
|
||||
while true; do
|
||||
if ! ss -tan | grep -q ".*TIME-WAIT .*:1084 "; then break; fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
echo "Extracting image..."
|
||||
${sing} build --sandbox /tmp/lumerical/lumericalLicenseManager \
|
||||
${inputs.self.src.lumerical.licenseManager.sifImageFile}
|
||||
mkdir /tmp/lumerical/lumericalLicenseManager/public
|
||||
|
||||
echo 'Searching for en* interface...'
|
||||
iface=$(${ip} -o link show | ${awk} -F': ' '/^[0-9]+: en/ {print $2; exit}')
|
||||
@@ -53,25 +41,29 @@ let
|
||||
fi
|
||||
|
||||
echo 'Creating license file...'
|
||||
cp ${inputs.self.src.lumerical.licenseManager.sifImageFile} /tmp/lumerical/license.txt
|
||||
${chmod} +w /tmp/lumerical/license.txt
|
||||
${sed} -i "s|xxxxxxxxxxxxx|$mac|" /tmp/lumerical/license.txt
|
||||
${sed} -i 's|2022.1231|2035.1231|g' /tmp/lumerical/license.txt
|
||||
${sed} -i "s|xxxxxxxxxxxxx|$mac|" \
|
||||
/tmp/lumerical/lumericalLicenseManager/home/ansys_inc/shared_files/licensing/license_files/ansyslmd.lic
|
||||
${sed} -i 's|2022.1231|2035.1231|g' \
|
||||
/tmp/lumerical/lumericalLicenseManager/home/ansys_inc/shared_files/licensing/license_files/ansyslmd.lic
|
||||
|
||||
echo "Starting license manager..."
|
||||
${sing} run --pwd /home/ansys_inc/shared_files/licensing --writable-tmpfs \
|
||||
--bind /tmp/lumerical/license.txt:/home/ansys_inc/shared_files/licensing/license_files/ansyslmd.lic \
|
||||
${inputs.self.src.lumerical.licenseManager.sifImageFile}
|
||||
${sing} instance start --writable /tmp/lumerical/lumericalLicenseManager lumericalLicenseManager
|
||||
${sing} exec instance://lumericalLicenseManager /bin/sh -c \
|
||||
"pushd /home/ansys_inc/shared_files/licensing; (./start_ansysli &); (./start_lmcenter &); tail -f /dev/null"
|
||||
|
||||
cleanup() {
|
||||
echo "Stopping license manager..."
|
||||
${sing} instance stop lumericalLicenseManager
|
||||
chmod -R u+w /tmp/lumerical && rm -rf /tmp/lumerical
|
||||
}
|
||||
trap cleanup SIGINT SIGTERM SIGHUP EXIT
|
||||
tail -f /dev/null
|
||||
'';
|
||||
lumericalFdtd = pkgs.writeShellScriptBin "lumericalFdtd"
|
||||
''
|
||||
exec ${pkgs.mpi}/bin/mpirun \
|
||||
${pkgs.localPackages.lumerical.lumerical.cmd}/opt/ansys_inc/v231/bin/fdtd-engine-ompi-lcl "$@"
|
||||
'';
|
||||
in pkgs.symlinkJoin
|
||||
{
|
||||
name = "xmuhk";
|
||||
paths = (with pkgs; [ hello btop htop iotop pv ]) ++ [ lumericalLicenseManager lumericalFdtd ];
|
||||
paths = (with pkgs; [ hello btop htop iotop pv localPackages.lumerical.lumerical.cmd ])
|
||||
++ [ lumericalLicenseManager ];
|
||||
postBuild = "echo ${inputs.self.rev or "dirty"} > $out/.version";
|
||||
passthru = { inherit pkgs singularity; };
|
||||
passthru = { inherit pkgs; };
|
||||
}
|
||||
|
||||
335
flake.lock
generated
335
flake.lock
generated
@@ -1,5 +1,27 @@
|
||||
{
|
||||
"nodes": {
|
||||
"aagl": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750597708,
|
||||
"narHash": "sha256-jpoh3tk4F4C0MZsXYqFt1fqm4qYOcyu3RtJlmpabpDo=",
|
||||
"owner": "ezKEa",
|
||||
"repo": "aagl-gtk-on-nix",
|
||||
"rev": "5e4851010e05030553f2265ced86b155dfe0bb93",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ezKEa",
|
||||
"ref": "release-25.05",
|
||||
"repo": "aagl-gtk-on-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"blog": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -127,6 +149,27 @@
|
||||
}
|
||||
},
|
||||
"devshell": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nur-linyinfeng",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741473158,
|
||||
"narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devshell_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nur-xddxdd",
|
||||
@@ -166,11 +209,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -180,6 +223,22 @@
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
@@ -195,7 +254,58 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_4": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_5": {
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"revCount": 57,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"nur-linyinfeng",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749398372,
|
||||
"narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
@@ -249,6 +359,42 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"flake-utils_4": {
|
||||
"inputs": {
|
||||
"systems": "systems_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -437,6 +583,21 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-flatpak": {
|
||||
"locked": {
|
||||
"lastModified": 1749394952,
|
||||
"narHash": "sha256-WbWkzIvB0gqAdBLghdmUpGveY7MlAS2iMj3VEJnJ9yE=",
|
||||
"owner": "gmodena",
|
||||
"repo": "nix-flatpak",
|
||||
"rev": "64c6e53a3999957c19ab95cda78bde466d8374cc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "gmodena",
|
||||
"repo": "nix-flatpak",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-index-database": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -500,6 +661,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1750646418,
|
||||
"narHash": "sha256-4UAN+W0Lp4xnUiHYXUXAPX18t+bn6c4Btry2RqM9JHY=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1f426f65ac4e6bf808923eb6f8b8c2bfba3d18c5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-wallpaper": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -520,11 +697,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749016257,
|
||||
"narHash": "sha256-Vi+QhXm6Kau233v7ijtdD5aNpE4RpnUjRUhXGwi7pxk=",
|
||||
"lastModified": 1751630609,
|
||||
"narHash": "sha256-mJ1XnKiLnNapGSUwyGdFD8tmQTzuJm8z3qaFC27guqE=",
|
||||
"owner": "CHN-beta",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5835771b10e3197408d3ac7d32558c8e2ae0ab8d",
|
||||
"rev": "b263408b62d74a1e7a298fc47135653a70c227aa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -665,18 +842,45 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur-xddxdd": {
|
||||
"nur-linyinfeng": {
|
||||
"inputs": {
|
||||
"devshell": "devshell",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"flake-parts": "flake-parts",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixos-stable": "nixos-stable",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nvfetcher": "nvfetcher",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1751049834,
|
||||
"narHash": "sha256-xgLH6/ZtQJKWsham0Cj0nKGY8hde2fY8vZgSM5JfRik=",
|
||||
"owner": "linyinfeng",
|
||||
"repo": "nur-packages",
|
||||
"rev": "d7a4ee64345bae20e75f40d6f35c705d22c216d4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "linyinfeng",
|
||||
"repo": "nur-packages",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur-xddxdd": {
|
||||
"inputs": {
|
||||
"devshell": "devshell_2",
|
||||
"flake-parts": "flake-parts_2",
|
||||
"nix-index-database": "nix-index-database_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-24_05": "nixpkgs-24_05",
|
||||
"nvfetcher": "nvfetcher",
|
||||
"nvfetcher": "nvfetcher_2",
|
||||
"pre-commit-hooks-nix": "pre-commit-hooks-nix",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748081225,
|
||||
@@ -694,8 +898,37 @@
|
||||
},
|
||||
"nvfetcher": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"flake-compat": [
|
||||
"nur-linyinfeng",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": [
|
||||
"nur-linyinfeng",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nur-linyinfeng",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1732501185,
|
||||
"narHash": "sha256-Z0BpHelaGQsE5VD9hBsBHsvMU9h+Xt0kfkDJyFivZOU=",
|
||||
"owner": "berberman",
|
||||
"repo": "nvfetcher",
|
||||
"rev": "bdb14eab6fe9cefc29efe01e60c3a3f616d6b62a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "berberman",
|
||||
"repo": "nvfetcher",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nvfetcher_2": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_3",
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": [
|
||||
"nur-xddxdd",
|
||||
"nixpkgs"
|
||||
@@ -789,7 +1022,7 @@
|
||||
},
|
||||
"pre-commit-hooks-nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_2",
|
||||
"flake-compat": "flake-compat_4",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nur-xddxdd",
|
||||
@@ -828,6 +1061,7 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"aagl": "aagl",
|
||||
"blog": "blog",
|
||||
"bscpkgs": "bscpkgs",
|
||||
"buildproxy": "buildproxy",
|
||||
@@ -846,6 +1080,7 @@
|
||||
"mumax": "mumax",
|
||||
"nameof": "nameof",
|
||||
"nc4nix": "nc4nix",
|
||||
"nix-flatpak": "nix-flatpak",
|
||||
"nix-index-database": "nix-index-database",
|
||||
"nix-vscode-extensions": "nix-vscode-extensions",
|
||||
"nixos-wallpaper": "nixos-wallpaper",
|
||||
@@ -856,6 +1091,7 @@
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"nixvirt": "nixvirt",
|
||||
"nu-scripts": "nu-scripts",
|
||||
"nur-linyinfeng": "nur-linyinfeng",
|
||||
"nur-xddxdd": "nur-xddxdd",
|
||||
"openxlsx": "openxlsx",
|
||||
"phono3py": "phono3py",
|
||||
@@ -872,6 +1108,7 @@
|
||||
"ufo": "ufo",
|
||||
"v-sim": "v-sim",
|
||||
"vaspberry": "vaspberry",
|
||||
"winapps": "winapps",
|
||||
"zpp-bits": "zpp-bits"
|
||||
}
|
||||
},
|
||||
@@ -1007,6 +1244,36 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_4": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tgbot-cpp": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@@ -1024,6 +1291,27 @@
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nur-linyinfeng",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750931469,
|
||||
"narHash": "sha256-0IEdQB1nS+uViQw4k3VGUXntjkDp7aAlqcxdewb/hAc=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "ac8e6f32e11e9c7f153823abc3ab007f2a65d3e1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nur-xddxdd",
|
||||
@@ -1095,6 +1383,29 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"winapps": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_5",
|
||||
"flake-utils": "flake-utils_4",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730460191,
|
||||
"narHash": "sha256-CWaNjs2kOpmsR8ieVwqcd7EAz5Kd3y8I5huZyYgGqlA=",
|
||||
"owner": "winapps-org",
|
||||
"repo": "winapps",
|
||||
"rev": "b18efc4497c0994182bbe482808583c11cc51a2e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "winapps-org",
|
||||
"ref": "feat-nix-packaging",
|
||||
"repo": "winapps",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zpp-bits": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
url = "github:pjones/plasma-manager";
|
||||
inputs = { nixpkgs.follows = "nixpkgs"; home-manager.follows = "home-manager"; };
|
||||
};
|
||||
nur-linyinfeng = { url = "github:linyinfeng/nur-packages"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
nix-flatpak.url = "github:gmodena/nix-flatpak";
|
||||
catppuccin = { url = "github:catppuccin/nix"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
bscpkgs = { url = "github:CHN-beta/bscpkgs"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
aagl = { url = "github:ezKEa/aagl-gtk-on-nix/release-25.05"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
winapps = { url = "github:winapps-org/winapps/feat-nix-packaging"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
nixvirt = { url = "github:CHN-beta/NixVirt"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
buildproxy = { url = "github:polygon/nix-buildproxy"; inputs.nixpkgs.follows = "nixpkgs"; };
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ let
|
||||
{
|
||||
autoroute = [ "api" "git" "grafana" "matrix" "peertube" "send" "synapse" "vikunja" "铜锣湾" ];
|
||||
nas = [ "initrd.nas" ];
|
||||
office = [ "srv2-node0" ];
|
||||
office = [ "srv2-node0" "xserverxmu" ];
|
||||
vps4 = [ "initrd.vps4" "xserver2.vps4" ];
|
||||
vps6 =
|
||||
[
|
||||
@@ -29,7 +29,7 @@ let
|
||||
nas = "192.168.1.2";
|
||||
pc = "192.168.1.3";
|
||||
one = "192.168.1.4";
|
||||
office = "210.34.16.60";
|
||||
office = "210.34.16.20";
|
||||
srv1-node0 = "59.77.36.250";
|
||||
vps4 = "104.234.37.61";
|
||||
vps6 = "144.34.225.59";
|
||||
|
||||
@@ -33,12 +33,14 @@ in platformConfig //
|
||||
inherit config;
|
||||
overlays =
|
||||
[
|
||||
inputs.topInputs.aagl.overlays.default
|
||||
inputs.topInputs.nur-xddxdd.overlays.inSubTree
|
||||
inputs.topInputs.nix-vscode-extensions.overlays.default
|
||||
inputs.topInputs.buildproxy.overlays.default
|
||||
(final: prev:
|
||||
{
|
||||
inherit (inputs.topInputs.nix-vscode-extensions.overlays.default final prev) nix-vscode-extensions;
|
||||
nur-linyinfeng = (inputs.topInputs.nur-linyinfeng.overlays.default final prev).linyinfeng;
|
||||
firefox-addons = (import "${inputs.topInputs.rycee}" { inherit (prev) pkgs; }).firefox-addons;
|
||||
})
|
||||
inputs.topInputs.self.overlays.default
|
||||
@@ -124,8 +126,18 @@ in platformConfig //
|
||||
rich = prev.rich.overridePythonAttrs (prev:
|
||||
{ disabledTests = prev.disabledTests or [] ++ [ "test_brokenpipeerror" ]; });
|
||||
}
|
||||
// (inputs.lib.optionalAttrs (nixpkgs.march != null && !prev.stdenv.hostPlatform.avx2Support)
|
||||
{
|
||||
numcodecs = prev.numcodecs.overridePythonAttrs (prev:
|
||||
{
|
||||
disabledTests = prev.disabledTests or []
|
||||
++ [ "test_encode_decode" "test_partial_decode" "test_blosc" ];
|
||||
});
|
||||
})
|
||||
))];
|
||||
inherit (final.pkgs-2411) intelPackages_2023;
|
||||
})
|
||||
// (inputs.lib.optionalAttrs (nixpkgs.march == "silvermont")
|
||||
{ c-blosc = prev.c-blosc.overrideAttrs { doCheck = false; }; })
|
||||
)];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
lib: rec
|
||||
{
|
||||
attrsToList = attrs: builtins.map (name: { inherit name; value = attrs.${name}; }) (builtins.attrNames attrs);
|
||||
inherit (lib) attrsToList;
|
||||
mkConditional = condition: trueResult: falseResult: let inherit (lib) mkMerge mkIf; in
|
||||
mkMerge [ ( mkIf condition trueResult ) ( mkIf (!condition) falseResult ) ];
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
{ inputs, localLib }: rec
|
||||
{
|
||||
pkgs = (import inputs.nixpkgs
|
||||
pkgs = import inputs.nixpkgs (localLib.buildNixpkgsConfig
|
||||
{
|
||||
system = "x86_64-linux";
|
||||
config.allowUnfree = true;
|
||||
overlays = [ inputs.self.overlays.default ];
|
||||
inputs = { inherit (inputs.nixpkgs) lib; topInputs = inputs; };
|
||||
nixpkgs = { march = null; cuda = null; nixRoot = null; };
|
||||
});
|
||||
hpcstat =
|
||||
let
|
||||
openssh = (pkgs.pkgsStatic.openssh.override { withLdns = false; etcDir = null; }).overrideAttrs
|
||||
(prev: { doCheck = false; patches = prev.patches ++ [ ../packages/hpcstat/openssh.patch ];});
|
||||
duc = pkgs.pkgsStatic.duc.override { enableCairo = false; cairo = null; pango = null; };
|
||||
glaze = pkgs.pkgsStatic.glaze.overrideAttrs
|
||||
glaze = pkgs.pkgs-2411.pkgsStatic.glaze.overrideAttrs
|
||||
(prev: { cmakeFlags = prev.cmakeFlags ++ [ "-Dglaze_ENABLE_FUZZING=OFF" ]; });
|
||||
# pkgsStatic.clangStdenv have a bug
|
||||
# https://github.com/NixOS/nixpkgs/issues/177129
|
||||
@@ -41,7 +40,7 @@
|
||||
dns-push = pkgs.callPackage ./dns
|
||||
{
|
||||
inherit localLib;
|
||||
tokenPath = inputs.self.nixosConfigurations.pc.config.sops.secrets."acme/token".path;
|
||||
tokenPath = inputs.self.nixosConfigurations.pc.config.nixos.system.sops.secrets."acme/token".path;
|
||||
octodns = pkgs.octodns.withProviders (_: with pkgs.octodns-providers; [ cloudflare ]);
|
||||
};
|
||||
archive =
|
||||
|
||||
@@ -12,8 +12,12 @@ let bugs =
|
||||
(attrs: { patches = attrs.patches ++ [ ./xmunet.patch ];}); };
|
||||
backlight.boot.kernelParams = [ "nvidia.NVreg_RegistryDwords=EnableBrightnessControl=1" ];
|
||||
amdpstate.boot.kernelParams = [ "amd_pstate=active" ];
|
||||
iwlwifi.nixos.system.kernel.modules.modprobeConfig =
|
||||
[ "options iwlwifi power_save=0" "options iwlmvm power_scheme=1" "options iwlwifi uapsd_disable=1" ];
|
||||
iwlwifi.boot.extraModprobeConfig =
|
||||
''
|
||||
options iwlwifi power_save=0
|
||||
options iwlmvm power_scheme=1
|
||||
options iwlwifi uapsd_disable=1
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
@@ -6,8 +6,12 @@ inputs: let inherit (inputs) topInputs; in
|
||||
topInputs.sops-nix.nixosModules.sops
|
||||
topInputs.nix-index-database.nixosModules.nix-index
|
||||
topInputs.impermanence.nixosModules.impermanence
|
||||
topInputs.nix-flatpak.nixosModules.nix-flatpak
|
||||
topInputs.catppuccin.nixosModules.catppuccin
|
||||
topInputs.aagl.nixosModules.default
|
||||
topInputs.nixvirt.nixosModules.default
|
||||
# TODO: Remove after next release
|
||||
"${topInputs.nixpkgs-unstable}/nixos/modules/services/hardware/lact.nix"
|
||||
(inputs:
|
||||
{
|
||||
config =
|
||||
|
||||
9
modules/packages/android-studio.nix
Normal file
9
modules/packages/android-studio.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.android-studio = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.packages) android-studio; in inputs.lib.mkIf (android-studio != null)
|
||||
{
|
||||
nixos.packages.packages._packages = with inputs.pkgs; [ androidStudioPackages.stable.full ];
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@ inputs:
|
||||
options.nixos.packages.chromium = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) chromium; in inputs.lib.mkIf (chromium != null)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ inputs:
|
||||
options.nixos.packages.desktop = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) desktop; in inputs.lib.mkIf (desktop != null)
|
||||
{
|
||||
@@ -15,7 +15,8 @@ inputs:
|
||||
[
|
||||
# system management
|
||||
# TODO: module should add yubikey-touch-detector into path
|
||||
gparted yubikey-touch-detector btrfs-assistant kdePackages.qtstyleplugin-kvantum cpu-x wl-mirror xpra
|
||||
gparted wayland-utils clinfo glxinfo vulkan-tools dracut yubikey-touch-detector btrfs-assistant snapper-gui
|
||||
kdePackages.qtstyleplugin-kvantum ventoy-full cpu-x wl-mirror geekbench xpra
|
||||
(
|
||||
writeShellScriptBin "xclip"
|
||||
''
|
||||
@@ -23,50 +24,77 @@ inputs:
|
||||
else exec ${wl-clipboard-x11}/bin/xclip "$@"; fi
|
||||
''
|
||||
)
|
||||
# color management
|
||||
argyllcms xcalib
|
||||
# networking
|
||||
remmina putty kdePackages.krdc
|
||||
remmina putty mtr-gui
|
||||
# media
|
||||
mpv nomacs simplescreenrecorder imagemagick gimp-with-plugins qcm waifu2x-converter-cpp blender paraview vlc
|
||||
obs-studio (inkscape-with-extensions.override { inkscapeExtensions = null; }) kdePackages.kcolorchooser
|
||||
kdePackages.kdenlive
|
||||
mpv nomacs simplescreenrecorder imagemagick gimp-with-plugins netease-cloud-music-gtk qcm
|
||||
waifu2x-converter-cpp blender paraview vlc whalebird spotify obs-studio
|
||||
(inkscape-with-extensions.override { inkscapeExtensions = null; })
|
||||
# terminal
|
||||
warp-terminal
|
||||
# development
|
||||
adb-sync scrcpy dbeaver-bin aircrack-ng fprettify waveterm
|
||||
adb-sync scrcpy dbeaver-bin cling aircrack-ng
|
||||
weston cage openbox krita fprettify # jetbrains.clion
|
||||
# desktop sharing
|
||||
rustdesk-flutter
|
||||
# password and key management
|
||||
yubikey-manager yubikey-manager-qt yubikey-personalization yubikey-personalization-gui bitwarden hashcat
|
||||
kdePackages.kleopatra
|
||||
electrum jabref john crunch
|
||||
# download
|
||||
qbittorrent wgetpaste rclone
|
||||
qbittorrent nur-xddxdd.baidupcs-go wgetpaste onedrive onedrivegui rclone
|
||||
# editor
|
||||
typora
|
||||
typora appflowy notion-app-enhanced joplin-desktop standardnotes logseq obsidian code-cursor
|
||||
# news
|
||||
fluent-reader newsflash follow
|
||||
fluent-reader rssguard newsflash newsboat follow
|
||||
# nix tools
|
||||
nixpkgs-fmt nixd nix-serve nix-prefetch-github prefetch-npm-deps nix-prefetch-docker
|
||||
# required by vscode nix tools
|
||||
nil
|
||||
nixpkgs-fmt appimage-run nixd nix-serve node2nix nix-prefetch-github prefetch-npm-deps nix-prefetch-docker
|
||||
nix-template nil bundix
|
||||
# instant messager
|
||||
element-desktop telegram-desktop discord zoom-us slack nheko
|
||||
element-desktop telegram-desktop discord zoom-us slack nheko hexchat halloy
|
||||
fluffychat signal-desktop qq nur-xddxdd.wechat-uos-sandboxed cinny-desktop
|
||||
# browser
|
||||
google-chrome tor-browser
|
||||
# office
|
||||
crow-translate zotero pandoc texliveFull poppler_utils pdftk pdfchain activitywatch
|
||||
ydict pspp libreoffice-qt6-fresh ocrmypdf typst kdePackages.kruler
|
||||
crow-translate zotero pandoc texliveFull poppler_utils pdftk pdfchain davinci-resolve
|
||||
ydict texstudio panoply pspp libreoffice-qt6-fresh ocrmypdf typst # paperwork
|
||||
# required by ltex-plus.vscode-ltex-plus
|
||||
ltex-ls ltex-ls-plus
|
||||
# matplot++ needs old gnuplot
|
||||
inputs.pkgs.pkgs-2311.gnuplot
|
||||
pkgs-2311.gnuplot
|
||||
# math, physics and chemistry
|
||||
octaveFull mpi geogebra6 qalculate-qt
|
||||
octaveFull ovito localPackages.vesta localPackages.v-sim jmol mpi geogebra6 localPackages.ufo
|
||||
(quantum-espresso.override
|
||||
{
|
||||
stdenv = gcc14Stdenv;
|
||||
gfortran = gfortran14;
|
||||
wannier90 = wannier90.overrideAttrs { buildFlags = [ "dynlib" ]; };
|
||||
})
|
||||
pkgs-2311.hdfview numbat qalculate-qt
|
||||
(if inputs.config.nixos.system.nixpkgs.cuda != null then localPackages.mumax else emptyDirectory)
|
||||
(if inputs.config.nixos.system.nixpkgs.cuda != null
|
||||
then (lammps.override { stdenv = cudaPackages.backendStdenv; }).overrideAttrs (prev:
|
||||
{
|
||||
cmakeFlags = prev.cmakeFlags ++
|
||||
[ "-DPKG_GPU=on" "-DGPU_API=cuda" "-DCMAKE_POLICY_DEFAULT_CMP0146=OLD" ];
|
||||
nativeBuildInputs = prev.nativeBuildInputs ++ [ cudaPackages.cudatoolkit ];
|
||||
buildInputs = prev.buildInputs ++ [ mpi ];
|
||||
})
|
||||
else lammps-mpi)
|
||||
# virtualization
|
||||
bottles wineWowPackages.stagingFull
|
||||
virt-viewer bottles wineWowPackages.stagingFull genymotion playonlinux
|
||||
# media
|
||||
nur-xddxdd.svp
|
||||
# for kdenlive auto subtitle
|
||||
openai-whisper
|
||||
];
|
||||
]
|
||||
++ (builtins.filter (p: !((p.meta.broken or false) || (builtins.elem p.pname or null [ "falkon" "kalzium" ])))
|
||||
(builtins.filter inputs.lib.isDerivation (builtins.attrValues kdePackages.kdeGear)));
|
||||
_pythonPackages = [(pythonPackages: with pythonPackages;
|
||||
[
|
||||
scipy scikit-learn jupyterlab autograd numpy
|
||||
phonopy scipy scikit-learn jupyterlab autograd inputs.pkgs.localPackages.phono3py
|
||||
tensorflow keras numpy
|
||||
])];
|
||||
};
|
||||
user.sharedModules =
|
||||
@@ -122,7 +150,17 @@ inputs:
|
||||
kdeconnect.enable = inputs.lib.mkIf (inputs.config.nixos.system.gui.implementation == "kde") true;
|
||||
kde-pim = inputs.lib.mkIf (inputs.config.nixos.system.gui.implementation == "kde")
|
||||
{ enable = true; kmail = true; };
|
||||
coolercontrol =
|
||||
{
|
||||
enable = true;
|
||||
nvidiaSupport = if inputs.config.nixos.hardware.gpu.type == null then false
|
||||
else inputs.lib.hasSuffix "nvidia" inputs.config.nixos.hardware.gpu.type;
|
||||
};
|
||||
anime-game-launcher = { enable = true; package = inputs.pkgs.anime-game-launcher; };
|
||||
honkers-railway-launcher = { enable = true; package = inputs.pkgs.honkers-railway-launcher; };
|
||||
sleepy-launcher = { enable = true; package = inputs.pkgs.sleepy-launcher; };
|
||||
alvr = { enable = true; openFirewall = true; };
|
||||
};
|
||||
services.pcscd.enable = true;
|
||||
services = { pcscd.enable = true; lact.enable = true; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ inputs:
|
||||
options.nixos.packages.firefox = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) firefox; in inputs.lib.mkIf (firefox != null)
|
||||
{
|
||||
|
||||
12
modules/packages/flatpak.nix
Normal file
12
modules/packages/flatpak.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.flatpak = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) flatpak; in inputs.lib.mkIf (flatpak != null)
|
||||
{
|
||||
services.flatpak = { enable = true; uninstallUnmanaged = true; };
|
||||
};
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.lammps = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.packages) lammps; in inputs.lib.mkIf (lammps != null)
|
||||
{
|
||||
nixos.packages =
|
||||
{
|
||||
molecule = {};
|
||||
packages._packages =
|
||||
let cuda = let inherit (inputs.config.nixos.system.nixpkgs) cuda; in cuda.capabilities or null != null;
|
||||
in
|
||||
if cuda then [((inputs.pkgs.lammps.override { stdenv = inputs.pkgs.cudaPackages.backendStdenv; })
|
||||
.overrideAttrs (prev:
|
||||
{
|
||||
cmakeFlags = prev.cmakeFlags ++ [ "-DPKG_GPU=on" "-DGPU_API=cuda" "-DCMAKE_POLICY_DEFAULT_CMP0146=OLD" ];
|
||||
nativeBuildInputs = prev.nativeBuildInputs ++ [ inputs.pkgs.cudaPackages.cudatoolkit ];
|
||||
buildInputs = prev.buildInputs ++ [ inputs.pkgs.mpi ];
|
||||
}))]
|
||||
else [ inputs.pkgs.lammps-mpi ];
|
||||
};
|
||||
};
|
||||
}
|
||||
13
modules/packages/lumerical.nix
Normal file
13
modules/packages/lumerical.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.lumerical = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.packages) lumerical; in inputs.lib.mkIf (lumerical != null)
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
packages.packages._packages = [ inputs.pkgs.localPackages.lumerical.lumerical.cmd ];
|
||||
services.lumericalLicenseManager = {};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -30,7 +30,8 @@ inputs:
|
||||
# encryption and authentication
|
||||
apacheHttpd openssl ssh-to-age gnupg age sops pam_u2f yubico-piv-tool libfido2
|
||||
# networking
|
||||
ipset iptables iproute2 dig nettools traceroute tcping-go whois tcpdump nmap inetutils wireguard-tools
|
||||
ipset iptables iproute2 dig nettools traceroute tcping-go whois tcpdump nmap inetutils wireguard-tools openvpn
|
||||
parted
|
||||
# nix tools
|
||||
nix-output-monitor nix-tree ssh-to-age nix-inspect
|
||||
# development
|
||||
@@ -44,6 +45,15 @@ inputs:
|
||||
++ (with inputs.config.boot.kernelPackages; [ cpupower usbip ])
|
||||
++ (inputs.lib.optionals (inputs.config.nixos.system.gui.implementation == "kde")
|
||||
[ inputs.topInputs.plasma-manager.packages.${inputs.pkgs.system}.rc2nix ]);
|
||||
_pythonPackages = [(pythonPackages: with pythonPackages;
|
||||
[
|
||||
openai python-telegram-bot fastapi-cli pypdf2 pandas matplotlib plotly gunicorn redis jinja2 certifi
|
||||
charset-normalizer idna orjson psycopg2 inquirerpy requests tqdm pydbus
|
||||
# allow pandas read odf
|
||||
odfpy
|
||||
# for vasp plot-workfunc.py
|
||||
ase
|
||||
])];
|
||||
};
|
||||
programs =
|
||||
{
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.molecule = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) molecule; in inputs.lib.mkIf (molecule != null)
|
||||
{
|
||||
nixos.packages.packages =
|
||||
{
|
||||
_packages = with inputs.pkgs;
|
||||
[ ovito localPackages.vesta localPackages.v-sim localPackages.ufo inputs.pkgs.pkgs-2311.hdfview ];
|
||||
_pythonPackages = [(pythonPackages: with pythonPackages;
|
||||
[
|
||||
phonopy inputs.pkgs.localPackages.phono3py
|
||||
])];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.mumax = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.packages) mumax; in inputs.lib.mkIf (mumax != null)
|
||||
{
|
||||
nixos.packages.packages._packages = [ inputs.pkgs.localPackages.mumax ];
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@ inputs:
|
||||
options.nixos.packages.steam = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) steam; in inputs.lib.mkIf (steam != null)
|
||||
{
|
||||
|
||||
@@ -4,20 +4,14 @@ inputs:
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.packages) vasp; in inputs.lib.mkIf (vasp != null)
|
||||
{
|
||||
nixos.packages =
|
||||
nixos.packages.packages = with inputs.pkgs;
|
||||
{
|
||||
molecule = {};
|
||||
packages = with inputs.pkgs;
|
||||
{
|
||||
_packages =
|
||||
(
|
||||
[ localPackages.vasp.intel localPackages.vasp.vtst localPackages.vaspkit wannier90 ]
|
||||
++ (inputs.lib.optional
|
||||
(let inherit (inputs.config.nixos.system.nixpkgs) cuda; in cuda.capabilities or null != null)
|
||||
localPackages.vasp.nvidia)
|
||||
);
|
||||
_pythonPackages = [(_: [ localPackages.py4vasp ])];
|
||||
};
|
||||
_packages =
|
||||
[
|
||||
localPackages.vasp.intel localPackages.vasp.vtst localPackages.vaspkit wannier90
|
||||
(if inputs.config.nixos.system.nixpkgs.cuda != null then localPackages.vasp.nvidia else emptyDirectory)
|
||||
];
|
||||
_pythonPackages = [(_: [ localPackages.py4vasp ])];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ inputs:
|
||||
options.nixos.packages.vscode = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if inputs.config.nixos.model.type == "desktop" then {} else null;
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) vscode; in inputs.lib.mkIf (vscode != null)
|
||||
{
|
||||
|
||||
47
modules/packages/winapps/default.nix
Normal file
47
modules/packages/winapps/default.nix
Normal file
@@ -0,0 +1,47 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.packages.winapps = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.packages) winapps; in inputs.lib.mkIf (winapps != null)
|
||||
{
|
||||
nixos.packages.packages._packages =
|
||||
[
|
||||
(inputs.pkgs.callPackage "${inputs.topInputs.winapps}/packages/winapps" {})
|
||||
(inputs.pkgs.runCommand "winapps-windows" {}
|
||||
''
|
||||
mkdir -p $out/share/applications
|
||||
cp ${inputs.pkgs.replaceVars ./windows.desktop { path = inputs.topInputs.winapps; }} \
|
||||
$out/share/applications/windows.desktop
|
||||
'')
|
||||
]
|
||||
++ builtins.map
|
||||
(p: inputs.pkgs.runCommand "winapps-${p}" {}
|
||||
''
|
||||
mkdir -p $out/share/applications
|
||||
source ${inputs.topInputs.winapps}/apps/${p}/info
|
||||
# replace \ with \\
|
||||
WIN_EXECUTABLE=$(echo $WIN_EXECUTABLE | sed 's/\\/\\\\/g')
|
||||
# replace space with \s
|
||||
WIN_EXECUTABLE=$(echo $WIN_EXECUTABLE | sed 's/ /\\s/g')
|
||||
cat > $out/share/applications/${p}.desktop << EOF
|
||||
[Desktop Entry]
|
||||
Name=$NAME
|
||||
Exec=winapps manual "$WIN_EXECUTABLE" %F
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=${inputs.topInputs.winapps}/apps/${p}/icon.svg
|
||||
StartupWMClass=$FULL_NAME
|
||||
Comment=$FULL_NAME
|
||||
Categories=$CATEGORIES
|
||||
MimeType=$MIME_TYPES
|
||||
EOF
|
||||
'')
|
||||
[
|
||||
"access-o365" "acrobat-x-pro" "cmd" "excel-o365" "explorer" "illustrator-cc" "powerpoint-o365"
|
||||
"visual-studio-comm" "word-o365"
|
||||
];
|
||||
};
|
||||
}
|
||||
9
modules/packages/winapps/windows.desktop
Normal file
9
modules/packages/winapps/windows.desktop
Normal file
@@ -0,0 +1,9 @@
|
||||
[Desktop Entry]
|
||||
Name=Windows
|
||||
Exec=winapps windows %F
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=@path@/icons/windows.svg
|
||||
StartupWMClass=Micorosoft Windows
|
||||
Comment=Micorosoft Windows
|
||||
Categories=Windows
|
||||
@@ -63,6 +63,7 @@ inputs:
|
||||
[[ ! -r "$P10K_INSTANT_PROMPT" ]] || source "$P10K_INSTANT_PROMPT"
|
||||
HYPHEN_INSENSITIVE="true"
|
||||
export PATH=~/bin:$PATH
|
||||
zstyle ':vcs_info:*' disable-patterns "/nix/remote/*"
|
||||
'';
|
||||
oh-my-zsh.theme = "";
|
||||
};
|
||||
|
||||
@@ -34,21 +34,21 @@ inputs:
|
||||
name = builtins.elemAt cert.value.domains 0;
|
||||
value =
|
||||
{
|
||||
credentialsFile = inputs.config.sops.templates."acme/cloudflare.ini".path;
|
||||
credentialsFile = inputs.config.nixos.system.sops.templates."acme/cloudflare.ini".path;
|
||||
extraDomainNames = builtins.tail cert.value.domains;
|
||||
group = inputs.lib.mkIf (cert.value.group != null) cert.value.group;
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList acme.cert));
|
||||
};
|
||||
sops =
|
||||
nixos.system.sops =
|
||||
{
|
||||
templates."acme/cloudflare.ini".content =
|
||||
''
|
||||
CLOUDFLARE_DNS_API_TOKEN=${inputs.config.sops.placeholder."acme/token"}
|
||||
CLOUDFLARE_DNS_API_TOKEN=${inputs.config.nixos.system.sops.placeholder."acme/token"}
|
||||
CLOUDFLARE_PROPAGATION_TIMEOUT=300
|
||||
'';
|
||||
secrets."acme/token".sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/acme.yaml";
|
||||
secrets."acme/token" = {};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ inputs:
|
||||
inherit (fs.value) hashTableSizeMB;
|
||||
extraOptions =
|
||||
[
|
||||
"--workaround-btrfs-send"
|
||||
"--thread-count" "${builtins.toString fs.value.threads}"
|
||||
"--loadavg-target" "${builtins.toString fs.value.loadAverage}"
|
||||
"--scan-mode" "3"
|
||||
|
||||
@@ -14,14 +14,17 @@ inputs:
|
||||
{
|
||||
enable = true;
|
||||
use-auth-secret = true;
|
||||
static-auth-secret-file = inputs.config.sops.secrets."coturn/auth-secret".path;
|
||||
static-auth-secret-file = inputs.config.nixos.system.sops.secrets."coturn/auth-secret".path;
|
||||
realm = coturn.hostname;
|
||||
cert = "${keydir}/full.pem";
|
||||
pkey = "${keydir}/key.pem";
|
||||
no-cli = true;
|
||||
};
|
||||
sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
|
||||
nixos.services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
|
||||
nixos =
|
||||
{
|
||||
system.sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
|
||||
services.acme.cert.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
|
||||
};
|
||||
networking.firewall = with inputs.config.services.coturn;
|
||||
{
|
||||
allowedUDPPorts = [ listening-port tls-listening-port ];
|
||||
|
||||
@@ -15,19 +15,18 @@ inputs:
|
||||
enable = true;
|
||||
baseUrl = "https://${freshrss.hostname}";
|
||||
defaultUser = "chn";
|
||||
passwordFile = inputs.config.sops.secrets."freshrss/chn".path;
|
||||
database = { type = "mysql"; passFile = inputs.config.sops.secrets."freshrss/db".path; };
|
||||
};
|
||||
sops.secrets =
|
||||
{
|
||||
"freshrss/chn".owner = inputs.config.users.users.freshrss.name;
|
||||
"freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; };
|
||||
passwordFile = inputs.config.nixos.system.sops.secrets."freshrss/chn".path;
|
||||
database = { type = "mysql"; passFile = inputs.config.nixos.system.sops.secrets."freshrss/db".path; };
|
||||
};
|
||||
systemd.services.freshrss-config.after = [ "mysql.service" ];
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
mariadb = { enable = true; instances.freshrss = {}; };
|
||||
nginx.https.${freshrss.hostname}.global.configName = "freshrss";
|
||||
services = { mariadb.instances.freshrss = {}; nginx.https.${freshrss.hostname}.global.configName = "freshrss"; };
|
||||
system.sops.secrets =
|
||||
{
|
||||
"freshrss/chn".owner = inputs.config.users.users.freshrss.name;
|
||||
"freshrss/db" = { owner = inputs.config.users.users.freshrss.name; key = "mariadb/freshrss"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ inputs:
|
||||
{
|
||||
enable = true;
|
||||
lfs.enable = true;
|
||||
mailerPasswordFile = inputs.config.sops.secrets."gitea/mail".path;
|
||||
mailerPasswordFile = inputs.config.nixos.system.sops.secrets."gitea/mail".path;
|
||||
database =
|
||||
{ createDatabase = false; type = "postgres"; passwordFile = inputs.config.sops.secrets."gitea/db".path; };
|
||||
{
|
||||
createDatabase = false;
|
||||
type = "postgres";
|
||||
passwordFile = inputs.config.nixos.system.sops.secrets."gitea/db".path;
|
||||
};
|
||||
settings =
|
||||
{
|
||||
session.COOKIE_SECURE = true;
|
||||
@@ -48,12 +52,17 @@ inputs:
|
||||
[ "DEFAULT" "MIGRATE" "MIRROR" "CLONE" "PULL" "GC" ]);
|
||||
};
|
||||
};
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
nginx =
|
||||
system.sops.secrets =
|
||||
{
|
||||
enable = true;
|
||||
https.${gitea.hostname}.location =
|
||||
"gitea/mail" = { owner = "gitea"; key = "mail/bot"; };
|
||||
"gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; };
|
||||
"mail/bot" = {};
|
||||
};
|
||||
services =
|
||||
{
|
||||
nginx.https.${gitea.hostname}.location =
|
||||
{
|
||||
"/".proxy.upstream = "http://127.0.0.1:3002";
|
||||
"/robots.txt".static.root =
|
||||
@@ -64,14 +73,8 @@ inputs:
|
||||
};
|
||||
in "${inputs.pkgs.runCommand "robots.txt" {} "mkdir -p $out; cp ${robotsFile} $out/robots.txt"}";
|
||||
};
|
||||
postgresql.instances.gitea = {};
|
||||
};
|
||||
postgresql.instances.gitea = {};
|
||||
};
|
||||
sops.secrets =
|
||||
{
|
||||
"gitea/mail" = { owner = "gitea"; key = "mail/bot"; };
|
||||
"gitea/db" = { owner = "gitea"; key = "postgresql/gitea"; };
|
||||
"mail/bot" = {};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ inputs:
|
||||
enabled = true;
|
||||
host = "mail.chn.moe";
|
||||
user = "bot@chn.moe";
|
||||
password = "$__file{${inputs.config.sops.secrets."grafana/mail".path}}";
|
||||
password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/mail".path}}";
|
||||
from_address = "bot@chn.moe";
|
||||
ehlo_identity = grafana.hostname;
|
||||
startTLS_policy = "MandatoryStartTLS";
|
||||
@@ -32,9 +32,9 @@ inputs:
|
||||
server = { root_url = "https://${grafana.hostname}"; http_port = 3001; enable_gzip = true; };
|
||||
security =
|
||||
{
|
||||
secret_key = "$__file{${inputs.config.sops.secrets."grafana/secret".path}}";
|
||||
secret_key = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/secret".path}}";
|
||||
admin_user = "chn";
|
||||
admin_password = "$__file{${inputs.config.sops.secrets."grafana/chn".path}}";
|
||||
admin_password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/chn".path}}";
|
||||
admin_email = "chn@chn.moe";
|
||||
};
|
||||
database =
|
||||
@@ -42,7 +42,7 @@ inputs:
|
||||
type = "postgres";
|
||||
host = "127.0.0.1:5432";
|
||||
user = "grafana";
|
||||
password = "$__file{${inputs.config.sops.secrets."grafana/db".path}}";
|
||||
password = "$__file{${inputs.config.nixos.system.sops.secrets."grafana/db".path}}";
|
||||
};
|
||||
};
|
||||
provision =
|
||||
@@ -78,23 +78,21 @@ inputs:
|
||||
extraFlags = [ "--storage.tsdb.max-block-chunk-segment-size=16MB" ];
|
||||
};
|
||||
};
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
nginx =
|
||||
services =
|
||||
{
|
||||
enable = true;
|
||||
https.${grafana.hostname}.location."/".proxy =
|
||||
{ upstream = "http://127.0.0.1:3001"; websocket = true; };
|
||||
nginx.https.${grafana.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3001"; websocket = true; };
|
||||
postgresql.instances.grafana = {};
|
||||
};
|
||||
system.sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in
|
||||
{
|
||||
"grafana/mail" = { owner = owner; key = "mail/bot"; };
|
||||
"grafana/secret".owner = owner;
|
||||
"grafana/chn".owner = owner;
|
||||
"grafana/db" = { owner = owner; key = "postgresql/grafana"; };
|
||||
"mail/bot" = {};
|
||||
};
|
||||
postgresql.instances.grafana = {};
|
||||
};
|
||||
sops.secrets = let owner = inputs.config.systemd.services.grafana.serviceConfig.User; in
|
||||
{
|
||||
"grafana/mail" = { owner = owner; key = "mail/bot"; };
|
||||
"grafana/secret".owner = owner;
|
||||
"grafana/chn".owner = owner;
|
||||
"grafana/db" = { owner = owner; key = "postgresql/grafana"; };
|
||||
"mail/bot" = {};
|
||||
};
|
||||
environment.persistence."/nix/nodatacow".directories =
|
||||
[{ directory = "/var/lib/prometheus2"; user = "prometheus"; group = "prometheus"; mode = "0700"; }];
|
||||
|
||||
@@ -15,13 +15,13 @@ inputs:
|
||||
grep = "${inputs.pkgs.gnugrep}/bin/grep";
|
||||
curl = "${inputs.pkgs.curl}/bin/curl";
|
||||
cat = "${inputs.pkgs.coreutils}/bin/cat";
|
||||
token = inputs.config.sops.secrets."telegram/token".path;
|
||||
chat = inputs.config.sops.secrets."telegram/user/chn".path;
|
||||
token = inputs.config.nixos.system.sops.secrets."telegram/token".path;
|
||||
chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path;
|
||||
date = "${inputs.pkgs.coreutils}/bin/date";
|
||||
hpcstat = "${inputs.pkgs.localPackages.hpcstat}/bin/hpcstat";
|
||||
ssh = "${inputs.pkgs.openssh}/bin/ssh -i ${key} -o StrictHostKeyChecking=no"
|
||||
+ " -o ForwardAgent=yes -o AddKeysToAgent=yes";
|
||||
key = inputs.config.sops.secrets."hpcstat/key".path;
|
||||
key = inputs.config.nixos.system.sops.secrets."hpcstat/key".path;
|
||||
jykang = "${inputs.topInputs.self}/devices/jykang.xmuhpc/files";
|
||||
ssh-agent = "${inputs.pkgs.openssh}/bin/ssh-agent";
|
||||
in
|
||||
@@ -105,10 +105,10 @@ inputs:
|
||||
(inputs.localLib.attrsToList calenders));
|
||||
tmpfiles.rules = [ "d /var/lib/hpcstat 0700 hpcstat hpcstat" ];
|
||||
};
|
||||
sops.secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in
|
||||
nixos.system.sops.secrets =
|
||||
{
|
||||
"telegram/token" = { group = "telegram"; mode = "0440"; inherit sopsFile; };
|
||||
"telegram/user/chn" = { group = "telegram"; mode = "0440"; inherit sopsFile; };
|
||||
"telegram/token" = { group = "telegram"; mode = "0440"; };
|
||||
"telegram/user/chn" = { group = "telegram"; mode = "0440"; };
|
||||
"hpcstat/key" = { owner = "hpcstat"; group = "hpcstat"; };
|
||||
};
|
||||
users =
|
||||
|
||||
@@ -10,35 +10,37 @@ inputs:
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) httpapi; in inputs.lib.mkIf (httpapi != null)
|
||||
{
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
phpfpm.instances.httpapi = {};
|
||||
nginx.https.${httpapi.hostname}.location =
|
||||
services =
|
||||
{
|
||||
"/files".static.root = "/srv/api";
|
||||
"/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; };
|
||||
"/notify.php".php =
|
||||
phpfpm.instances.httpapi = {};
|
||||
nginx.https.${httpapi.hostname}.location =
|
||||
{
|
||||
root = builtins.dirOf inputs.config.sops.templates."httpapi/notify.php".path;
|
||||
fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi;
|
||||
"/files".static.root = "/srv/api";
|
||||
"/led".static = { root = "/srv/api"; detectAuth.users = [ "led" ]; };
|
||||
"/notify.php".php =
|
||||
{
|
||||
root = builtins.dirOf inputs.config.nixos.system.sops.templates."httpapi/notify.php".path;
|
||||
fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpapi.fastcgi;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates."httpapi/notify.php" =
|
||||
system.sops =
|
||||
{
|
||||
owner = inputs.config.users.users.httpapi.name;
|
||||
group = inputs.config.users.users.httpapi.group;
|
||||
content =
|
||||
let
|
||||
placeholder = inputs.config.sops.placeholder;
|
||||
request = "https://api.telegram.org/bot${placeholder."telegram/token"}"
|
||||
+ "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text=";
|
||||
in ''<?php print file_get_contents("${request}".urlencode($_GET["message"])); ?>'';
|
||||
templates."httpapi/notify.php" =
|
||||
{
|
||||
owner = inputs.config.users.users.httpapi.name;
|
||||
group = inputs.config.users.users.httpapi.group;
|
||||
content =
|
||||
let
|
||||
inherit (inputs.config.sops) placeholder;
|
||||
request = "https://api.telegram.org/bot${placeholder."telegram/token"}"
|
||||
+ "/sendMessage?chat_id=${placeholder."telegram/user/chn"}&text=";
|
||||
in ''<?php print file_get_contents("${request}".urlencode($_GET["message"])); ?>'';
|
||||
};
|
||||
secrets = { "telegram/token" = {}; "telegram/user/chn" = {}; };
|
||||
};
|
||||
secrets = let sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml"; in
|
||||
{ "telegram/token" = { inherit sopsFile; }; "telegram/user/chn" = { inherit sopsFile; }; };
|
||||
};
|
||||
systemd.tmpfiles.rules = [ "d /srv/api 0700 nginx nginx" "Z /srv/api - nginx nginx" ];
|
||||
};
|
||||
|
||||
@@ -14,7 +14,10 @@ inputs:
|
||||
{
|
||||
phpfpm.instances.httpua = {};
|
||||
nginx.http.${httpua.hostname}.php =
|
||||
{ root = "${./.}"; fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpua.fastcgi; };
|
||||
{
|
||||
root = builtins.toString (inputs.pkgs.writeTextDir "index.php" "<?php echo $_SERVER['HTTP_USER_AGENT']; ?>");
|
||||
fastcgiPass = inputs.config.nixos.services.phpfpm.instances.httpua.fastcgi;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<?php echo $_SERVER['HTTP_USER_AGENT']; ?>
|
||||
@@ -15,43 +15,39 @@ inputs:
|
||||
image = "ghcr.io/huginn/huginn:latest";
|
||||
imageFile = inputs.topInputs.self.src.huginn;
|
||||
ports = [ "127.0.0.1:3000:3000/tcp" ];
|
||||
environmentFiles = [ inputs.config.sops.templates."huginn/env".path ];
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates."huginn/env".content = let placeholder = inputs.config.sops.placeholder; in
|
||||
''
|
||||
MYSQL_PORT_3306_TCP_ADDR=host.containers.internal
|
||||
HUGINN_DATABASE_NAME=huginn
|
||||
HUGINN_DATABASE_USERNAME=huginn
|
||||
HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"}
|
||||
DOMAIN=${huginn.hostname}
|
||||
RAILS_ENV=production
|
||||
FORCE_SSL=true
|
||||
INVITATION_CODE=${placeholder."huginn/invitationCode"}
|
||||
SMTP_DOMAIN=mail.chn.moe
|
||||
SMTP_USER_NAME=bot@chn.moe
|
||||
SMTP_PASSWORD="${placeholder."mail/bot"}"
|
||||
SMTP_SERVER=mail.chn.moe
|
||||
SMTP_SSL=true
|
||||
EMAIL_FROM_ADDRESS=bot@chn.moe
|
||||
TIMEZONE=Beijing
|
||||
DO_NOT_CREATE_DATABASE=true
|
||||
'';
|
||||
secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; };
|
||||
environmentFiles = [ inputs.config.nixos.system.sops.templates."huginn/env".path ];
|
||||
};
|
||||
nixos =
|
||||
{
|
||||
services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
https.${huginn.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3000"; websocket = true; };
|
||||
};
|
||||
nginx.https.${huginn.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:3000"; websocket = true; };
|
||||
mariadb.instances.huginn = {};
|
||||
podman = {};
|
||||
};
|
||||
system.sops =
|
||||
{
|
||||
templates."huginn/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
''
|
||||
MYSQL_PORT_3306_TCP_ADDR=host.containers.internal
|
||||
HUGINN_DATABASE_NAME=huginn
|
||||
HUGINN_DATABASE_USERNAME=huginn
|
||||
HUGINN_DATABASE_PASSWORD=${placeholder."mariadb/huginn"}
|
||||
DOMAIN=${huginn.hostname}
|
||||
RAILS_ENV=production
|
||||
FORCE_SSL=true
|
||||
INVITATION_CODE=${placeholder."huginn/invitationCode"}
|
||||
SMTP_DOMAIN=mail.chn.moe
|
||||
SMTP_USER_NAME=bot@chn.moe
|
||||
SMTP_PASSWORD="${placeholder."mail/bot"}"
|
||||
SMTP_SERVER=mail.chn.moe
|
||||
SMTP_SSL=true
|
||||
EMAIL_FROM_ADDRESS=bot@chn.moe
|
||||
TIMEZONE=Beijing
|
||||
DO_NOT_CREATE_DATABASE=true
|
||||
'';
|
||||
secrets = { "huginn/invitationCode" = {}; "mail/bot" = {}; };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ inputs:
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
macAddress = mkOption { type = types.str; };
|
||||
macAddress = mkOption
|
||||
{
|
||||
type = types.str;
|
||||
default = if inputs.config.nixos.system.network != null then "00:01:23:45:67:89" else null;
|
||||
};
|
||||
createFakeInterface = mkOption { type = types.bool; default = inputs.config.nixos.system.network != null; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
@@ -16,10 +21,17 @@ inputs:
|
||||
inherit (inputs.topInputs.self.src.lumerical.licenseManager) image imageFile;
|
||||
extraOptions = [ "--network=host" ];
|
||||
volumes =
|
||||
let license = inputs.pkgs.localPackages.lumerical.license.override
|
||||
{ inherit (lumericalLicenseManager) macAddress; };
|
||||
let
|
||||
macAddress = builtins.replaceStrings [ ":" ] [ "" ] lumericalLicenseManager.macAddress;
|
||||
license = inputs.pkgs.localPackages.lumerical.license.override { inherit macAddress; };
|
||||
in [ "${license}:/home/ansys_inc/shared_files/licensing/license_files/ansyslmd.lic" ];
|
||||
};
|
||||
nixos.services.podman = {};
|
||||
systemd.network = inputs.lib.mkIf lumericalLicenseManager.createFakeInterface
|
||||
{
|
||||
netdevs.ensFakeLumerical.netdevConfig = { Kind = "dummy"; Name = "ensFakeLumerical"; };
|
||||
networks."10-ensFakeLumerical" =
|
||||
{ matchConfig.Name = "ensFakeLumerical"; linkConfig.MACAddress = lumericalLicenseManager.macAddress; };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ inputs:
|
||||
let
|
||||
passwordFile =
|
||||
if db.value.passwordFile or null != null then db.value.passwordFile
|
||||
else inputs.config.sops.secrets."mariadb/${db.value.user}".path;
|
||||
else inputs.config.nixos.system.sops.secrets."mariadb/${db.value.user}".path;
|
||||
mysql = "${inputs.config.services.mysql.package}/bin/mysql";
|
||||
in
|
||||
# force user use password auth
|
||||
''echo "ALTER USER '${db.value.user}' IDENTIFIED BY '$(cat ${passwordFile})';" | ${mysql} -N'')
|
||||
(inputs.localLib.attrsToList mariadb.instances)));
|
||||
sops.secrets = builtins.listToAttrs (builtins.map
|
||||
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
|
||||
(db: { name = "mariadb/${db.value.user}"; value.owner = inputs.config.users.users.mysql.name; })
|
||||
(builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList mariadb.instances)));
|
||||
environment.persistence."/nix/nodatacow".directories =
|
||||
|
||||
@@ -1,75 +1,60 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.mirism = let inherit (inputs.lib) mkOption types; in
|
||||
options.nixos.services.mirism = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.services) mirism; in inputs.lib.mkIf (mirism != null)
|
||||
{
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
};
|
||||
config =
|
||||
let
|
||||
inherit (inputs.config.nixos.services) mirism;
|
||||
inherit (inputs.lib) mkIf;
|
||||
inherit (builtins) map listToAttrs toString concatLists;
|
||||
in mkIf mirism.enable
|
||||
users =
|
||||
{
|
||||
users =
|
||||
{
|
||||
users.mirism = { uid = inputs.config.nixos.user.uid.mirism; group = "mirism"; isSystemUser = true; };
|
||||
groups.mirism.gid = inputs.config.nixos.user.gid.mirism;
|
||||
};
|
||||
systemd =
|
||||
{
|
||||
services = listToAttrs (map
|
||||
(instance:
|
||||
{
|
||||
name = "mirism-${instance}";
|
||||
value =
|
||||
{
|
||||
description = "mirism ${instance}";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig =
|
||||
{
|
||||
User = inputs.config.users.users.mirism.name;
|
||||
Group = inputs.config.users.users.mirism.group;
|
||||
ExecStart = "${inputs.pkgs.localPackages.mirism-old}/bin/${instance}";
|
||||
RuntimeMaxSec = "1d";
|
||||
Restart = "always";
|
||||
};
|
||||
};
|
||||
})
|
||||
[ "ng01" "beta" ]);
|
||||
tmpfiles.rules = concatLists (map
|
||||
(dir: [ "d /srv/${dir}mirism 0700 nginx nginx" "Z /srv/${dir}mirism - nginx nginx" ])
|
||||
[ "" "entry." ]);
|
||||
};
|
||||
nixos.services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
transparentProxy.map = { "ng01.mirism.one" = 7411; "beta.mirism.one" = 9114; };
|
||||
https = listToAttrs (map
|
||||
(instance:
|
||||
{
|
||||
name = "${instance}mirism.one";
|
||||
value.location."/".static = { root = "/srv/${instance}mirism"; index = [ "index.html" ]; };
|
||||
})
|
||||
[ "entry." "" ]);
|
||||
};
|
||||
acme.cert = { "ng01.mirism.one".group = "mirism"; "beta.mirism.one".group = "mirism"; };
|
||||
};
|
||||
environment.etc = listToAttrs (concatLists (map
|
||||
(instance:
|
||||
[
|
||||
{
|
||||
name = "letsencrypt/live/${instance}.mirism.one/fullchain.pem";
|
||||
value.source = "${inputs.config.security.acme.certs."${instance}.mirism.one".directory}/fullchain.pem";
|
||||
}
|
||||
{
|
||||
name = "letsencrypt/live/${instance}.mirism.one/privkey.pem";
|
||||
value.source = "${inputs.config.security.acme.certs."${instance}.mirism.one".directory}/key.pem";
|
||||
}
|
||||
])
|
||||
[ "ng01" "beta" ]));
|
||||
users.mirism = { uid = inputs.config.nixos.user.uid.mirism; group = "mirism"; isSystemUser = true; };
|
||||
groups.mirism.gid = inputs.config.nixos.user.gid.mirism;
|
||||
};
|
||||
systemd =
|
||||
{
|
||||
services = builtins.listToAttrs (builtins.map
|
||||
(instance:
|
||||
{
|
||||
name = "mirism-${instance}";
|
||||
value =
|
||||
{
|
||||
description = "mirism ${instance}";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig =
|
||||
{
|
||||
User = inputs.config.users.users.mirism.name;
|
||||
Group = inputs.config.users.users.mirism.group;
|
||||
ExecStart = "${inputs.pkgs.localPackages.mirism-old}/bin/${instance}";
|
||||
RuntimeMaxSec = "1d";
|
||||
Restart = "always";
|
||||
};
|
||||
};
|
||||
})
|
||||
[ "ng01" "beta" ]);
|
||||
tmpfiles.rules = builtins.concatLists (builtins.map
|
||||
(dir: [ "d /srv/${dir}mirism 0700 nginx nginx" "Z /srv/${dir}mirism - nginx nginx" ])
|
||||
[ "" "entry." ]);
|
||||
};
|
||||
nixos.services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
transparentProxy.map = { "ng01.mirism.one" = 7411; "beta.mirism.one" = 9114; };
|
||||
https = builtins.listToAttrs (builtins.map
|
||||
(instance: inputs.lib.nameValuePair "${instance}mirism.one"
|
||||
{ location."/".static = { root = "/srv/${instance}mirism"; index = [ "index.html" ]; }; })
|
||||
[ "entry." "" ]);
|
||||
};
|
||||
acme.cert = { "ng01.mirism.one".group = "mirism"; "beta.mirism.one".group = "mirism"; };
|
||||
};
|
||||
environment.etc = builtins.listToAttrs (builtins.concatLists (builtins.map
|
||||
(instance:
|
||||
[
|
||||
(inputs.lib.nameValuePair "letsencrypt/live/${instance}.mirism.one/fullchain.pem"
|
||||
{ source = "${inputs.config.security.acme.certs."${instance}.mirism.one".directory}/fullchain.pem"; })
|
||||
(inputs.lib.nameValuePair "letsencrypt/live/${instance}.mirism.one/privkey.pem"
|
||||
{ source = "${inputs.config.security.acme.certs."${instance}.mirism.one".directory}/key.pem"; })
|
||||
])
|
||||
[ "ng01" "beta" ]));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ inputs:
|
||||
after = [ "network.target" "redis-misskey-${instance.name}.service" "postgresql.service" ];
|
||||
requires = after;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment.MISSKEY_CONFIG_YML = inputs.config.sops.templates."misskey/${instance.name}.yml".path;
|
||||
environment.MISSKEY_CONFIG_YML =
|
||||
inputs.config.nixos.system.sops.templates."misskey/${instance.name}.yml".path;
|
||||
serviceConfig = rec
|
||||
{
|
||||
User = "misskey-${instance.name}";
|
||||
@@ -53,50 +54,6 @@ inputs:
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
sops.templates = builtins.listToAttrs (builtins.map
|
||||
(instance:
|
||||
{
|
||||
name = "misskey/${instance.name}.yml";
|
||||
value =
|
||||
{
|
||||
content =
|
||||
let
|
||||
placeholder = inputs.config.sops.placeholder;
|
||||
redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}";
|
||||
in
|
||||
''
|
||||
url: https://${instance.value.hostname}/
|
||||
port: ${toString instance.value.port}
|
||||
db:
|
||||
host: 127.0.0.1
|
||||
port: 5432
|
||||
db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
|
||||
user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
|
||||
pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"}
|
||||
extra:
|
||||
statement_timeout: 600000
|
||||
dbReplications: false
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: ${builtins.toString redis.port}
|
||||
pass: ${placeholder."redis/misskey-${instance.name}"}
|
||||
id: 'aid'
|
||||
proxyBypassHosts:
|
||||
- api.deepl.com
|
||||
- api-free.deepl.com
|
||||
- www.recaptcha.net
|
||||
- hcaptcha.com
|
||||
- challenges.cloudflare.com
|
||||
proxyRemoteFiles: true
|
||||
signToActivityPubGet: true
|
||||
maxFileSize: 1073741824
|
||||
fulltextSearch:
|
||||
provider: sqlPgroonga
|
||||
'';
|
||||
owner = "misskey-${instance.name}";
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
users = inputs.lib.mkMerge (builtins.map
|
||||
(instance:
|
||||
{
|
||||
@@ -111,18 +68,17 @@ inputs:
|
||||
groups."misskey-${instance.name}".gid = inputs.config.nixos.user.gid."misskey-${instance.name}";
|
||||
})
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
redis.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; })
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
postgresql.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; })
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
nginx =
|
||||
services =
|
||||
{
|
||||
enable = inputs.lib.mkIf (misskey.instances != {}) true;
|
||||
https = builtins.listToAttrs (builtins.map
|
||||
redis.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "misskey-${instance.name}"; value.port = instance.value.redis.port; })
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
postgresql.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; value = {}; })
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
nginx.https = builtins.listToAttrs (builtins.map
|
||||
(instance: with instance.value;
|
||||
{
|
||||
name = hostname;
|
||||
@@ -130,6 +86,50 @@ inputs:
|
||||
})
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
};
|
||||
system.sops.templates = builtins.listToAttrs (builtins.map
|
||||
(instance:
|
||||
{
|
||||
name = "misskey/${instance.name}.yml";
|
||||
value =
|
||||
{
|
||||
content =
|
||||
let
|
||||
placeholder = inputs.config.nixos.system.sops.placeholder;
|
||||
redis = inputs.config.nixos.services.redis.instances."misskey-${instance.name}";
|
||||
in
|
||||
''
|
||||
url: https://${instance.value.hostname}/
|
||||
port: ${toString instance.value.port}
|
||||
db:
|
||||
host: 127.0.0.1
|
||||
port: 5432
|
||||
db: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
|
||||
user: misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}
|
||||
pass: ${placeholder."postgresql/misskey_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"}
|
||||
extra:
|
||||
statement_timeout: 600000
|
||||
dbReplications: false
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: ${builtins.toString redis.port}
|
||||
pass: ${placeholder."redis/misskey-${instance.name}"}
|
||||
id: 'aid'
|
||||
proxyBypassHosts:
|
||||
- api.deepl.com
|
||||
- api-free.deepl.com
|
||||
- www.recaptcha.net
|
||||
- hcaptcha.com
|
||||
- challenges.cloudflare.com
|
||||
proxyRemoteFiles: true
|
||||
signToActivityPubGet: true
|
||||
maxFileSize: 1073741824
|
||||
fulltextSearch:
|
||||
provider: sqlPgroonga
|
||||
'';
|
||||
owner = "misskey-${instance.name}";
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList misskey.instances));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ inputs:
|
||||
config =
|
||||
{
|
||||
dbtype = "pgsql";
|
||||
dbpassFile = inputs.config.sops.secrets."nextcloud/postgresql".path;
|
||||
dbpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/postgresql".path;
|
||||
adminuser = "admin";
|
||||
adminpassFile = inputs.config.sops.secrets."nextcloud/admin".path;
|
||||
adminpassFile = inputs.config.nixos.system.sops.secrets."nextcloud/admin".path;
|
||||
};
|
||||
configureRedis = true;
|
||||
settings =
|
||||
@@ -39,7 +39,7 @@ inputs:
|
||||
overwriteprotocol = "https";
|
||||
default_phone_region = "CN";
|
||||
};
|
||||
secretFile = inputs.config.sops.templates."nextcloud/secret".path;
|
||||
secretFile = inputs.config.nixos.system.sops.templates."nextcloud/secret".path;
|
||||
extraApps =
|
||||
let
|
||||
version = inputs.lib.versions.major inputs.config.services.nextcloud.package.version;
|
||||
@@ -59,27 +59,30 @@ inputs:
|
||||
(package: { name = package; value = inputs.pkgs.fetchNextcloudApp (getInfo package); })
|
||||
[ "phonetrack" "twofactor_webauthn" "calendar" ]);
|
||||
};
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
postgresql.instances.nextcloud = {};
|
||||
redis.instances.nextcloud.port = 3499;
|
||||
nginx = { enable = true; https.${nextcloud.hostname}.global.configName = nextcloud.hostname; };
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates."nextcloud/secret" =
|
||||
system.sops =
|
||||
{
|
||||
content = builtins.toJSON
|
||||
templates."nextcloud/secret" =
|
||||
{
|
||||
redis.password = inputs.config.sops.placeholder."redis/nextcloud";
|
||||
mail_smtppassword = inputs.config.sops.placeholder."mail/bot";
|
||||
content = builtins.toJSON
|
||||
{
|
||||
redis.password = inputs.config.nixos.system.sops.placeholder."redis/nextcloud";
|
||||
mail_smtppassword = inputs.config.nixos.system.sops.placeholder."mail/bot";
|
||||
};
|
||||
owner = inputs.config.users.users.nextcloud.name;
|
||||
};
|
||||
secrets =
|
||||
{
|
||||
"nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; };
|
||||
"nextcloud/admin".owner = inputs.config.users.users.nextcloud.name;
|
||||
};
|
||||
owner = inputs.config.users.users.nextcloud.name;
|
||||
};
|
||||
secrets =
|
||||
services =
|
||||
{
|
||||
"nextcloud/postgresql" = { key = "postgresql/nextcloud"; owner = inputs.config.users.users.nextcloud.name; };
|
||||
"nextcloud/admin".owner = inputs.config.users.users.nextcloud.name;
|
||||
postgresql.instances.nextcloud = {};
|
||||
redis.instances.nextcloud.port = 3499;
|
||||
nginx.https.${nextcloud.hostname}.global.configName = nextcloud.hostname;
|
||||
};
|
||||
};
|
||||
systemd.services.nextcloud-setup = rec { requires = [ "postgresql.service" ]; after = requires; };
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.nginx.applications.main = let inherit (inputs.lib) mkOption types; in
|
||||
options.nixos.services.nginx.applications.main = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.services.nginx.applications) main; in inputs.lib.mkIf (main != null)
|
||||
{
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
};
|
||||
config =
|
||||
let
|
||||
inherit (inputs.config.nixos.services.nginx.applications) main;
|
||||
inherit (inputs.lib) mkIf;
|
||||
in mkIf main.enable
|
||||
nixos.services.nginx.https."chn.moe".location =
|
||||
{
|
||||
nixos.services.nginx.https."chn.moe".location =
|
||||
{
|
||||
"/".return.return = "302 https://xn--s8w913fdga.chn.moe/@chn";
|
||||
"/.well-known/matrix/server".proxy =
|
||||
{
|
||||
setHeaders.Host = "matrix.chn.moe";
|
||||
upstream = "https://matrix.chn.moe";
|
||||
};
|
||||
};
|
||||
"/".return.return = "302 https://xn--s8w913fdga.chn.moe/@chn";
|
||||
"/.well-known/matrix/server".proxy = { setHeaders.Host = "matrix.chn.moe"; upstream = "https://matrix.chn.moe"; };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ inputs:
|
||||
imports = inputs.localLib.findModules ./.;
|
||||
options.nixos.services.nginx = let inherit (inputs.lib) mkOption types; in
|
||||
{
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
# transparentProxy -> https(with proxyProtocol) or transparentProxy -> streamProxy -> https(with proxyProtocol)
|
||||
# https without proxyProtocol listen on private ip, with proxyProtocol listen on all ip
|
||||
# streamProxy listen on private ip
|
||||
@@ -16,824 +15,99 @@ inputs:
|
||||
{
|
||||
httpsPort = 3065;
|
||||
httpsPortShift = { http2 = 1; proxyProtocol = 2; };
|
||||
httpsLocationTypes = [ "proxy" "static" "php" "return" "cgi" "alias" ];
|
||||
httpTypes = [ "rewriteHttps" "php" ];
|
||||
httpsLocationTypes = [ "proxy" "static" "php" "return" "alias" ];
|
||||
httpTypes = [ "rewriteHttps" "php" "proxy" ];
|
||||
streamPort = 5575;
|
||||
streamPortShift = { proxyProtocol = 1; };
|
||||
streamPortShift.proxyProtocol = 1;
|
||||
};
|
||||
};
|
||||
transparentProxy =
|
||||
{
|
||||
# only disable in some rare cases
|
||||
enable = mkOption { type = types.bool; default = true; };
|
||||
externalIp = mkOption { type = types.listOf types.nonEmptyStr; default = [ "0.0.0.0" ]; };
|
||||
# proxy to 127.0.0.1:${specified port}
|
||||
map = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.oneOf
|
||||
[
|
||||
# proxy to 127.0.0.1:${specified port}
|
||||
types.ints.unsigned
|
||||
# proxy to specified ip:port
|
||||
types.nonEmptyStr
|
||||
]);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
streamProxy =
|
||||
{
|
||||
map = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.oneOf
|
||||
[
|
||||
# proxy to specified ip:port without proxyProtocol
|
||||
types.nonEmptyStr
|
||||
(types.submodule { options =
|
||||
{
|
||||
upstream = mkOption
|
||||
{
|
||||
type = types.oneOf
|
||||
[
|
||||
# proxy to specified ip:port with or without proxyProtocol
|
||||
types.nonEmptyStr
|
||||
(types.submodule { options =
|
||||
{
|
||||
address = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
|
||||
# if port not specified, guess from proxyProtocol enabled or not, assume http2 enabled
|
||||
port = mkOption { type = types.nullOr types.ints.unsigned; default = null; };
|
||||
};})
|
||||
];
|
||||
default = {};
|
||||
};
|
||||
proxyProtocol = mkOption { type = types.bool; default = true; };
|
||||
addToTransparentProxy = mkOption { type = types.bool; default = true; };
|
||||
rewriteHttps = mkOption { type = types.bool; default = true; };
|
||||
};})
|
||||
]);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
https = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule (siteSubmoduleInputs: { options =
|
||||
{
|
||||
global =
|
||||
{
|
||||
configName = mkOption
|
||||
{
|
||||
type = types.nonEmptyStr;
|
||||
default = "https:${siteSubmoduleInputs.config._module.args.name}";
|
||||
};
|
||||
root = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
index = mkOption
|
||||
{
|
||||
type = types.nullOr (types.oneOf [ (types.enum [ "auto" ]) (types.nonEmptyListOf types.nonEmptyStr) ]);
|
||||
default = null;
|
||||
};
|
||||
charset = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
detectAuth = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
text = mkOption { type = types.nonEmptyStr; default = "Restricted Content"; };
|
||||
users = mkOption { type = types.nonEmptyListOf types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
rewriteHttps = mkOption { type = types.bool; default = true; };
|
||||
tlsCert = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
};
|
||||
listen = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule { options =
|
||||
{
|
||||
http2 = mkOption { type = types.bool; default = true; };
|
||||
proxyProtocol = mkOption { type = types.bool; default = true; };
|
||||
# if proxyProtocol not enabled, add to transparentProxy only
|
||||
# if proxyProtocol enabled, add to transparentProxy and streamProxy
|
||||
addToTransparentProxy = mkOption { type = types.bool; default = true; };
|
||||
};});
|
||||
default.main = {};
|
||||
};
|
||||
location = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule { options =
|
||||
let
|
||||
genericOptions =
|
||||
{
|
||||
# should be set to non null value if global root is null
|
||||
root = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
detectAuth = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
text = mkOption { type = types.nonEmptyStr; default = "Restricted Content"; };
|
||||
users = mkOption { type = types.nonEmptyListOf types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
# only one should be specified
|
||||
proxy = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
inherit (genericOptions) detectAuth;
|
||||
upstream = mkOption { type = types.nonEmptyStr; };
|
||||
websocket = mkOption { type = types.bool; default = false; };
|
||||
setHeaders = mkOption
|
||||
{
|
||||
type = types.attrsOf types.str;
|
||||
default.Host = siteSubmoduleInputs.config._module.args.name;
|
||||
};
|
||||
# echo -n "username:password" | base64
|
||||
addAuth = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
static = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
inherit (genericOptions) detectAuth root;
|
||||
index = mkOption
|
||||
{
|
||||
type = types.nullOr
|
||||
(types.oneOf [ (types.enum [ "auto" ]) (types.nonEmptyListOf types.nonEmptyStr) ]);
|
||||
default = null;
|
||||
};
|
||||
charset = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
tryFiles = mkOption { type = types.nullOr (types.nonEmptyListOf types.nonEmptyStr); default = null; };
|
||||
webdav = mkOption { type = types.bool; default = false; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
php = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{ inherit (genericOptions) detectAuth root; fastcgiPass = mkOption { type = types.nonEmptyStr; };};});
|
||||
default = null;
|
||||
};
|
||||
return = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{ return = mkOption { type = types.nonEmptyStr; }; };});
|
||||
default = null;
|
||||
};
|
||||
cgi = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options = { inherit (genericOptions) detectAuth root; };});
|
||||
default = null;
|
||||
};
|
||||
alias = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
path = mkOption { type = types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};});
|
||||
default = {};
|
||||
};
|
||||
};}));
|
||||
default = {};
|
||||
};
|
||||
http = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule (submoduleInputs: { options =
|
||||
{
|
||||
rewriteHttps = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
hostname = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
php = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{ root = mkOption { type = types.nonEmptyStr; }; fastcgiPass = mkOption { type = types.nonEmptyStr; };};});
|
||||
default = null;
|
||||
};
|
||||
proxy = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
upstream = mkOption { type = types.nonEmptyStr; };
|
||||
websocket = mkOption { type = types.bool; default = false; };
|
||||
setHeaders = mkOption
|
||||
{
|
||||
type = types.attrsOf types.str;
|
||||
default.Host = submoduleInputs.config._module.args.name;
|
||||
};
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};}));
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config =
|
||||
let
|
||||
inherit (inputs.localLib) attrsToList;
|
||||
inherit (inputs.config.nixos.services) nginx;
|
||||
inherit (builtins) map listToAttrs concatStringsSep toString filter attrValues concatLists;
|
||||
concatAttrs = list: listToAttrs (concatLists (map (attrs: attrsToList attrs) list));
|
||||
in inputs.lib.mkIf nginx.enable (inputs.lib.mkMerge
|
||||
[
|
||||
# generic config
|
||||
config = let inherit (inputs.config.nixos.services) nginx; in inputs.lib.mkIf
|
||||
(nginx.http != {} || nginx.https != {} || nginx.streamProxy.map != {} || nginx.transparentProxy.map != {})
|
||||
{
|
||||
services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
enableReload = true;
|
||||
eventsConfig =
|
||||
''
|
||||
worker_connections 524288;
|
||||
use epoll;
|
||||
'';
|
||||
commonHttpConfig =
|
||||
''
|
||||
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
|
||||
$geoip2_data_country_code country iso_code;
|
||||
}
|
||||
log_format http '[$time_local] $remote_addr-$geoip2_data_country_code "$host"'
|
||||
' $request_length $bytes_sent $status "$request" referer: "$http_referer" ua: "$http_user_agent"';
|
||||
access_log syslog:server=unix:/dev/log http;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_session_reuse off;
|
||||
send_timeout 1d;
|
||||
# nginx will try to redirect https://blog.chn.moe/docs to https://blog.chn.moe:3068/docs/ in default
|
||||
# this make it redirect to /docs/ without hostname
|
||||
absolute_redirect off;
|
||||
# allow realip module to set ip
|
||||
set_real_ip_from 0.0.0.0/0;
|
||||
real_ip_header proxy_protocol;
|
||||
'';
|
||||
proxyTimeout = "1d";
|
||||
recommendedZstdSettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedBrotliSettings = true;
|
||||
clientMaxBodySize = "0";
|
||||
package =
|
||||
let
|
||||
nginx-geoip2 =
|
||||
{
|
||||
name = "ngx_http_geoip2_module";
|
||||
src = inputs.pkgs.fetchFromGitHub
|
||||
{
|
||||
owner = "leev";
|
||||
repo = "ngx_http_geoip2_module";
|
||||
rev = "a607a41a8115fecfc05b5c283c81532a3d605425";
|
||||
hash = "sha256-CkmaeEa1iEAabJEDu3FhBUR7QF38koGYlyx+pyKZV9Y=";
|
||||
};
|
||||
meta.license = [];
|
||||
};
|
||||
in
|
||||
(inputs.pkgs.nginxMainline.override (prev: { modules = prev.modules ++ [ nginx-geoip2 ]; }))
|
||||
.overrideAttrs (prev: { buildInputs = prev.buildInputs ++ [ inputs.pkgs.libmaxminddb ]; });
|
||||
streamConfig =
|
||||
''
|
||||
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
|
||||
$geoip2_data_country_code country iso_code;
|
||||
}
|
||||
resolver 8.8.8.8;
|
||||
'';
|
||||
# todo: use host dns
|
||||
resolver.addresses = [ "8.8.8.8" ];
|
||||
};
|
||||
geoipupdate =
|
||||
{
|
||||
enable = true;
|
||||
settings =
|
||||
{
|
||||
AccountID = 901296;
|
||||
LicenseKey = inputs.config.sops.secrets."nginx/maxmind-license".path;
|
||||
EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
sops.secrets."nginx/maxmind-license" =
|
||||
{
|
||||
owner = inputs.config.users.users.nginx.name;
|
||||
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
|
||||
};
|
||||
systemd.services.nginx.serviceConfig =
|
||||
{
|
||||
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
||||
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
};
|
||||
}
|
||||
# transparentProxy
|
||||
(inputs.lib.mkIf nginx.transparentProxy.enable
|
||||
{
|
||||
services.nginx.streamConfig =
|
||||
enable = true;
|
||||
enableReload = true;
|
||||
eventsConfig =
|
||||
''
|
||||
log_format transparent_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
|
||||
'"$ssl_preread_server_name"->$transparent_proxy_backend $bytes_sent $bytes_received';
|
||||
map $ssl_preread_server_name $transparent_proxy_backend {
|
||||
${concatStringsSep "\n " (builtins.map
|
||||
(x:
|
||||
let upstrem = if builtins.isInt x.value then "127.0.0.1:${builtins.toString x.value}" else x.value;
|
||||
in ''"${x.name}" ${upstrem};'')
|
||||
(attrsToList nginx.transparentProxy.map))}
|
||||
default 127.0.0.1:${toString (with nginx.global; (httpsPort + httpsPortShift.http2))};
|
||||
}
|
||||
server {
|
||||
${concatStringsSep "\n " (map (ip: "listen ${ip}:443;") nginx.transparentProxy.externalIp)}
|
||||
ssl_preread on;
|
||||
proxy_bind $remote_addr transparent;
|
||||
proxy_pass $transparent_proxy_backend;
|
||||
proxy_connect_timeout 1s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log transparent_proxy;
|
||||
}
|
||||
worker_connections 524288;
|
||||
use epoll;
|
||||
'';
|
||||
# TODO: use existing options
|
||||
systemd.services.nginx-proxy =
|
||||
let
|
||||
ip = "${inputs.pkgs.iproute2}/bin/ip";
|
||||
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
|
||||
''
|
||||
${ip} rule add fwmark 2/2 table 200
|
||||
${ip} route add local 0.0.0.0/0 dev lo table 200
|
||||
'';
|
||||
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop"
|
||||
''
|
||||
${ip} rule del fwmark 2/2 table 200
|
||||
${ip} route del local 0.0.0.0/0 dev lo table 200
|
||||
'';
|
||||
in
|
||||
{
|
||||
description = "nginx transparent proxy";
|
||||
after = [ "network.target" ];
|
||||
serviceConfig =
|
||||
{
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = start;
|
||||
ExecStop = stop;
|
||||
};
|
||||
wants = [ "network.target" ];
|
||||
wantedBy= [ "multi-user.target" ];
|
||||
};
|
||||
networking.nftables.tables.nginx =
|
||||
{
|
||||
family = "inet";
|
||||
content =
|
||||
''
|
||||
chain output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
# 由本机发出、gid 为 nginx、但源地址不是本地监听的地址,说明是透明代理的第一个包,将这个流标记
|
||||
# 但这个包本身不需要处理,正常路由即可。
|
||||
meta skgid ${builtins.toString inputs.config.users.groups.nginx.gid} fib saddr type != local \
|
||||
ct state new counter ct mark set ct mark | 2 return
|
||||
# 由本机发出、作为透明代理的回复,它不能按照通常的路由,它需要被打上标记并被路由到本地
|
||||
# 这对应于透明代理到本地的服务的情况
|
||||
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
|
||||
return
|
||||
}
|
||||
# 还需要处理透明代理到其它机器的情况,它们的回复需要在 prerouting 中标记
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
|
||||
return
|
||||
}
|
||||
'';
|
||||
};
|
||||
})
|
||||
# streamProxy
|
||||
{
|
||||
services.nginx.streamConfig =
|
||||
commonHttpConfig =
|
||||
''
|
||||
log_format stream_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
|
||||
'"$ssl_preread_server_name"->$stream_proxy_backend $bytes_sent $bytes_received';
|
||||
map $ssl_preread_server_name $stream_proxy_backend {
|
||||
${concatStringsSep "\n " (map
|
||||
(x:
|
||||
let
|
||||
upstream =
|
||||
if (builtins.typeOf x.value.upstream == "string") then
|
||||
x.value.upstream
|
||||
else
|
||||
let
|
||||
port = with nginx.global;
|
||||
if x.value.upstream.port == null then
|
||||
httpsPort + httpsPortShift.http2
|
||||
+ (if x.value.proxyProtocol then httpsPortShift.proxyProtocol else 0)
|
||||
else x.value.upstream.port;
|
||||
in "${x.value.upstream.address}:${toString port}";
|
||||
in ''"${x.name}" "${upstream}";'')
|
||||
(attrsToList nginx.streamProxy.map))}
|
||||
}
|
||||
server {
|
||||
listen 127.0.0.1:${toString nginx.global.streamPort};
|
||||
ssl_preread on;
|
||||
proxy_pass $stream_proxy_backend;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log stream_proxy;
|
||||
}
|
||||
server {
|
||||
listen 127.0.0.1:${toString (with nginx.global; (streamPort + streamPortShift.proxyProtocol))};
|
||||
proxy_protocol on;
|
||||
ssl_preread on;
|
||||
proxy_pass $stream_proxy_backend;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log stream_proxy;
|
||||
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
|
||||
$geoip2_data_country_code country iso_code;
|
||||
}
|
||||
log_format http '[$time_local] $remote_addr-$geoip2_data_country_code "$host"'
|
||||
' $request_length $bytes_sent $status "$request" referer: "$http_referer" ua: "$http_user_agent"';
|
||||
access_log syslog:server=unix:/dev/log http;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_session_reuse off;
|
||||
send_timeout 1d;
|
||||
# nginx will try to redirect https://blog.chn.moe/docs to https://blog.chn.moe:3068/docs/ in default
|
||||
# this make it redirect to /docs/ without hostname
|
||||
absolute_redirect off;
|
||||
# allow realip module to set ip
|
||||
set_real_ip_from 0.0.0.0/0;
|
||||
real_ip_header proxy_protocol;
|
||||
'';
|
||||
nixos.services.nginx =
|
||||
{
|
||||
transparentProxy.map = listToAttrs
|
||||
(
|
||||
(map
|
||||
(site: { inherit (site) name; value = nginx.global.streamPort; })
|
||||
(filter
|
||||
(site: (!(site.value.proxyProtocol or false) && (site.value.addToTransparentProxy or true)))
|
||||
(attrsToList nginx.streamProxy.map)))
|
||||
++ (map
|
||||
(site: { inherit (site) name; value = with nginx.global; streamPort + streamPortShift.proxyProtocol; })
|
||||
(filter
|
||||
(site: ((site.value.proxyProtocol or false) && (site.value.addToTransparentProxy or true)))
|
||||
(attrsToList nginx.streamProxy.map)))
|
||||
);
|
||||
http = listToAttrs (map
|
||||
(site: { inherit (site) name; value.rewriteHttps = {}; })
|
||||
(filter (site: site.value.rewriteHttps or false) (attrsToList nginx.streamProxy.map)));
|
||||
};
|
||||
}
|
||||
# https assertions
|
||||
{
|
||||
# only one type should be specified in each location
|
||||
assertions =
|
||||
(
|
||||
(map
|
||||
(location:
|
||||
{
|
||||
assertion = (inputs.lib.count
|
||||
(x: x != null)
|
||||
(map (type: location.value.${type}) nginx.global.httpsLocationTypes)) <= 1;
|
||||
message = "Only one type shuold be specified in ${location.name}";
|
||||
})
|
||||
(concatLists (map
|
||||
(site: (map
|
||||
(location: { inherit (location) value; name = "${site.name} ${location.name}"; })
|
||||
(attrsToList site.value.location)))
|
||||
(attrsToList nginx.https))))
|
||||
# root should be specified either in global or in each location
|
||||
++ (map
|
||||
(location:
|
||||
{
|
||||
assertion = (location.value.root or "") != null;
|
||||
message = "Root should be specified in ${location.name}";
|
||||
})
|
||||
(concatLists (map
|
||||
(site: (map
|
||||
(location: { inherit (location) value; name = "${site.name} ${location.name}"; })
|
||||
(attrsToList site.value.location)))
|
||||
(filter (site: site.value.global.root == null) (attrsToList nginx.https)))))
|
||||
);
|
||||
}
|
||||
# https
|
||||
(
|
||||
let
|
||||
# merge different types of locations
|
||||
sites = map
|
||||
(site:
|
||||
{
|
||||
inherit (site) name;
|
||||
value =
|
||||
{
|
||||
inherit (site.value) global;
|
||||
listens = attrValues site.value.listen;
|
||||
locations = map
|
||||
(location:
|
||||
{
|
||||
inherit (location) name;
|
||||
value =
|
||||
let _ = builtins.head (filter (type: type.value != null) (attrsToList location.value));
|
||||
in _.value // { type = _.name; };
|
||||
})
|
||||
(attrsToList site.value.location);
|
||||
};
|
||||
})
|
||||
(attrsToList nginx.https);
|
||||
in
|
||||
{
|
||||
services =
|
||||
proxyTimeout = "1d";
|
||||
recommendedZstdSettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
# do not set Host header
|
||||
recommendedProxySettings = false;
|
||||
recommendedProxySettingsNoHost = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedBrotliSettings = true;
|
||||
clientMaxBodySize = "0";
|
||||
package =
|
||||
let nginx-geoip2 =
|
||||
{
|
||||
nginx.virtualHosts = listToAttrs (map
|
||||
(site:
|
||||
{
|
||||
name = site.value.global.configName;
|
||||
value =
|
||||
{
|
||||
serverName = site.name;
|
||||
root = inputs.lib.mkIf (site.value.global.root != null) site.value.global.root;
|
||||
basicAuthFile = inputs.lib.mkIf (site.value.global.detectAuth != null)
|
||||
(
|
||||
let secret = "nginx/templates/detectAuth/${inputs.lib.strings.escapeURL site.name}-global";
|
||||
in inputs.config.sops.templates.${secret}.path
|
||||
);
|
||||
extraConfig = concatStringsSep "\n"
|
||||
(
|
||||
(
|
||||
let inherit (site.value.global) index; in
|
||||
if (builtins.typeOf index == "list") then [ "index ${concatStringsSep " " index};" ]
|
||||
else if (index == "auto") then [ "autoindex on;" ]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
let inherit (site.value.global) detectAuth; in
|
||||
if (detectAuth != null) then [ ''auth_basic "${detectAuth.text}"'' ] else []
|
||||
)
|
||||
++ (
|
||||
let inherit (site.value.global) charset; in
|
||||
if (charset != null) then [ "charset ${charset};" ] else []
|
||||
)
|
||||
);
|
||||
listen = map
|
||||
(listen:
|
||||
{
|
||||
addr = if listen.proxyProtocol then "0.0.0.0" else "127.0.0.1";
|
||||
port = with nginx.global; httpsPort
|
||||
+ (if listen.http2 then httpsPortShift.http2 else 0)
|
||||
+ (if listen.proxyProtocol then httpsPortShift.proxyProtocol else 0);
|
||||
ssl = true;
|
||||
proxyProtocol = listen.proxyProtocol;
|
||||
extraParameters = inputs.lib.mkIf listen.http2 [ "http2" ];
|
||||
})
|
||||
site.value.listens;
|
||||
# do not automatically add http2 listen
|
||||
http2 = false;
|
||||
onlySSL = true;
|
||||
useACMEHost = inputs.lib.mkIf (site.value.global.tlsCert == null) site.name;
|
||||
sslCertificate = inputs.lib.mkIf (site.value.global.tlsCert != null)
|
||||
"${site.value.global.tlsCert}/fullchain.pem";
|
||||
sslCertificateKey = inputs.lib.mkIf (site.value.global.tlsCert != null)
|
||||
"${site.value.global.tlsCert}/privkey.pem";
|
||||
locations = listToAttrs (map
|
||||
(location:
|
||||
{
|
||||
inherit (location) name;
|
||||
value =
|
||||
{
|
||||
basicAuthFile = inputs.lib.mkIf (location.value.detectAuth or null != null)
|
||||
(
|
||||
let
|
||||
inherit (inputs.lib.strings) escapeURL;
|
||||
secret = "nginx/templates/detectAuth/${escapeURL site.name}/${escapeURL location.name}";
|
||||
in inputs.config.sops.templates.${secret}.path
|
||||
);
|
||||
root = inputs.lib.mkIf (location.value.root or null != null) location.value.root;
|
||||
}
|
||||
// {
|
||||
proxy =
|
||||
{
|
||||
proxyPass = location.value.upstream;
|
||||
proxyWebsockets = location.value.websocket;
|
||||
recommendedProxySettings = false;
|
||||
recommendedProxySettingsNoHost = true;
|
||||
extraConfig = concatStringsSep "\n"
|
||||
(
|
||||
(map
|
||||
(header: ''proxy_set_header ${header.name} "${header.value}";'')
|
||||
(attrsToList location.value.setHeaders))
|
||||
++ (
|
||||
if location.value.detectAuth != null || site.value.global.detectAuth != null
|
||||
then [ "proxy_hide_header Authorization;" ]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if location.value.addAuth != null then
|
||||
let authFile = "nginx/templates/addAuth/${location.value.addAuth}";
|
||||
in [ "include ${inputs.config.sops.templates.${authFile}.path};" ]
|
||||
else [])
|
||||
);
|
||||
};
|
||||
static =
|
||||
{
|
||||
index = inputs.lib.mkIf (builtins.typeOf location.value.index == "list")
|
||||
(concatStringsSep " " location.value.index);
|
||||
tryFiles = inputs.lib.mkIf (location.value.tryFiles != null)
|
||||
(concatStringsSep " " location.value.tryFiles);
|
||||
extraConfig = inputs.lib.mkMerge
|
||||
[
|
||||
(inputs.lib.mkIf (location.value.index == "auto") "autoindex on;")
|
||||
(inputs.lib.mkIf (location.value.charset != null) "charset ${location.value.charset};")
|
||||
(inputs.lib.mkIf location.value.webdav
|
||||
''
|
||||
dav_access user:rw group:rw;
|
||||
dav_methods PUT DELETE MKCOL COPY MOVE;
|
||||
dav_ext_methods PROPFIND OPTIONS;
|
||||
create_full_put_path on;
|
||||
'')
|
||||
];
|
||||
};
|
||||
php.extraConfig =
|
||||
''
|
||||
fastcgi_pass ${location.value.fastcgiPass};
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
include ${inputs.config.services.nginx.package}/conf/fastcgi.conf;
|
||||
'';
|
||||
return.return = location.value.return;
|
||||
cgi.extraConfig =
|
||||
''
|
||||
include ${inputs.config.services.nginx.package}/conf/fastcgi.conf;
|
||||
fastcgi_pass unix:${inputs.config.services.fcgiwrap.socketAddress};
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
'';
|
||||
alias.alias = location.value.path;
|
||||
}.${location.value.type};
|
||||
})
|
||||
site.value.locations);
|
||||
};
|
||||
})
|
||||
sites);
|
||||
fcgiwrap = inputs.lib.mkIf
|
||||
(
|
||||
filter (site: site != []) (map
|
||||
(site: filter (location: location.value.type == "cgi") site.value.locations)
|
||||
sites)
|
||||
!= []
|
||||
)
|
||||
(with inputs.config.users.users.nginx; { enable = true; user = name; inherit group; });
|
||||
};
|
||||
nixos.services =
|
||||
{
|
||||
nginx =
|
||||
let
|
||||
# { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; }
|
||||
listens = filter
|
||||
(listen: listen.value.addToTransparentProxy)
|
||||
(concatLists (map
|
||||
(site: map (listen: { inherit (site) name; value = listen; }) site.value.listens)
|
||||
sites));
|
||||
in
|
||||
{
|
||||
transparentProxy.map = listToAttrs (map
|
||||
(site:
|
||||
{
|
||||
inherit (site) name;
|
||||
value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0);
|
||||
})
|
||||
(filter (listen: !listen.value.proxyProtocol) listens));
|
||||
streamProxy.map = listToAttrs (map
|
||||
(site:
|
||||
{
|
||||
inherit (site) name;
|
||||
value =
|
||||
{
|
||||
upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol
|
||||
+ (if site.value.http2 then httpsPortShift.http2 else 0);
|
||||
proxyProtocol = true;
|
||||
rewriteHttps = inputs.lib.mkDefault false;
|
||||
};
|
||||
})
|
||||
(filter (listen: listen.value.proxyProtocol) listens));
|
||||
http = listToAttrs (map
|
||||
(site: { inherit (site) name; value.rewriteHttps = {}; })
|
||||
(filter (site: site.value.global.rewriteHttps) sites));
|
||||
};
|
||||
acme.cert = listToAttrs (map
|
||||
(site: { inherit (site) name; value.group = inputs.config.services.nginx.group; })
|
||||
sites);
|
||||
};
|
||||
sops =
|
||||
let
|
||||
inherit (inputs.lib.strings) escapeURL;
|
||||
detectAuthUsers = concatLists (map
|
||||
(site:
|
||||
(
|
||||
(map
|
||||
(location:
|
||||
{
|
||||
name = "${escapeURL site.name}/${escapeURL location.name}";
|
||||
value = location.value.detectAuth.users;
|
||||
})
|
||||
(filter (location: location.value.detectAuth or null != null) site.value.locations))
|
||||
++ (if site.value.global.detectAuth != null then
|
||||
[ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ]
|
||||
else [])
|
||||
))
|
||||
sites);
|
||||
addAuth = concatLists (map
|
||||
(site: map
|
||||
(location:
|
||||
{
|
||||
name = "${escapeURL site.name}/${escapeURL location.name}";
|
||||
value = location.value.addAuth;
|
||||
})
|
||||
(filter (location: location.value.addAuth or null != null) site.value.locations)
|
||||
)
|
||||
sites);
|
||||
in
|
||||
name = "ngx_http_geoip2_module";
|
||||
src = inputs.pkgs.fetchFromGitHub
|
||||
{
|
||||
templates = listToAttrs
|
||||
(
|
||||
(map
|
||||
(detectAuth:
|
||||
{
|
||||
name = "nginx/templates/detectAuth/${detectAuth.name}";
|
||||
value =
|
||||
{
|
||||
owner = inputs.config.users.users.nginx.name;
|
||||
content = concatStringsSep "\n" (map
|
||||
(user: "${user}:{PLAIN}${inputs.config.sops.placeholder."nginx/detectAuth/${user}"}")
|
||||
detectAuth.value);
|
||||
};
|
||||
})
|
||||
detectAuthUsers)
|
||||
++ (map
|
||||
(addAuth:
|
||||
{
|
||||
name = "nginx/templates/addAuth/${addAuth.name}";
|
||||
value =
|
||||
{
|
||||
owner = inputs.config.users.users.nginx.name;
|
||||
content =
|
||||
let placeholder = inputs.config.sops.placeholder."nginx/addAuth/${addAuth.value}";
|
||||
in ''proxy_set_header Authorization "Basic ${placeholder}";'';
|
||||
};
|
||||
})
|
||||
addAuth)
|
||||
);
|
||||
secrets = listToAttrs
|
||||
(
|
||||
(map
|
||||
(secret: { name = "nginx/detectAuth/${secret}"; value = {}; })
|
||||
(inputs.lib.unique (concatLists (map (detectAuth: detectAuth.value) detectAuthUsers))))
|
||||
++ (map
|
||||
(secret: { name = "nginx/addAuth/${secret}"; value = {}; })
|
||||
(inputs.lib.unique (map (addAuth: addAuth.value) addAuth)))
|
||||
);
|
||||
owner = "leev";
|
||||
repo = "ngx_http_geoip2_module";
|
||||
rev = "a607a41a8115fecfc05b5c283c81532a3d605425";
|
||||
hash = "sha256-CkmaeEa1iEAabJEDu3FhBUR7QF38koGYlyx+pyKZV9Y=";
|
||||
};
|
||||
}
|
||||
)
|
||||
# http
|
||||
meta.license = [];
|
||||
};
|
||||
in (inputs.pkgs.nginxMainline.override (prev: { modules = prev.modules ++ [ nginx-geoip2 ]; }))
|
||||
.overrideAttrs (prev: { buildInputs = prev.buildInputs ++ [ inputs.pkgs.libmaxminddb ]; });
|
||||
streamConfig =
|
||||
''
|
||||
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
|
||||
$geoip2_data_country_code country iso_code;
|
||||
}
|
||||
resolver 8.8.8.8;
|
||||
'';
|
||||
# anyway to use host dns?
|
||||
resolver.addresses = [ "8.8.8.8" ];
|
||||
};
|
||||
geoipupdate =
|
||||
{
|
||||
assertions = map
|
||||
(site:
|
||||
{
|
||||
assertion = (inputs.lib.count (x: x != null) (map (type: site.value.${type}) nginx.global.httpTypes)) <= 1;
|
||||
message = "Only one type shuold be specified in ${site.name}";
|
||||
})
|
||||
(attrsToList nginx.http);
|
||||
services.nginx.virtualHosts = listToAttrs (map
|
||||
(site:
|
||||
{
|
||||
name = "http.${site.name}";
|
||||
value = { serverName = site.name; listen = [ { addr = "0.0.0.0"; port = 80; } ]; }
|
||||
// (if site.value.rewriteHttps != null then
|
||||
{ locations."/".return = "301 https://${site.value.rewriteHttps.hostname}$request_uri"; }
|
||||
else {})
|
||||
// (if site.value.php != null then
|
||||
{
|
||||
extraConfig = "index index.php;";
|
||||
root = site.value.php.root;
|
||||
locations."~ ^.+?.php(/.*)?$".extraConfig =
|
||||
''
|
||||
fastcgi_pass ${site.value.php.fastcgiPass};
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
include ${inputs.config.services.nginx.package}/conf/fastcgi.conf;
|
||||
'';
|
||||
}
|
||||
else {})
|
||||
// (if site.value.proxy != null then
|
||||
{
|
||||
locations."/" =
|
||||
{
|
||||
proxyPass = site.value.proxy.upstream;
|
||||
proxyWebsockets = site.value.proxy.websocket;
|
||||
recommendedProxySettings = false;
|
||||
recommendedProxySettingsNoHost = true;
|
||||
extraConfig = builtins.concatStringsSep "\n" (builtins.map
|
||||
(header: ''proxy_set_header ${header.name} "${header.value}";'')
|
||||
(inputs.localLib.attrsToList site.value.proxy.setHeaders));
|
||||
};
|
||||
}
|
||||
else {});
|
||||
})
|
||||
(attrsToList nginx.http));
|
||||
}
|
||||
]);
|
||||
enable = true;
|
||||
settings =
|
||||
{
|
||||
AccountID = 901296;
|
||||
LicenseKey = inputs.config.nixos.system.sops.secrets."nginx/maxmind-license".path;
|
||||
EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
nixos.system.sops.secrets."nginx/maxmind-license".owner = inputs.config.users.users.nginx.name;
|
||||
systemd.services.nginx.serviceConfig =
|
||||
{
|
||||
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
||||
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
77
modules/services/nginx/http.nix
Normal file
77
modules/services/nginx/http.nix
Normal file
@@ -0,0 +1,77 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.nginx.http = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule (submoduleInputs: { options =
|
||||
{
|
||||
rewriteHttps = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
hostname = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
php = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{ root = mkOption { type = types.nonEmptyStr; }; fastcgiPass = mkOption { type = types.nonEmptyStr; };};});
|
||||
default = null;
|
||||
};
|
||||
proxy = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
upstream = mkOption { type = types.nonEmptyStr; };
|
||||
websocket = mkOption { type = types.bool; default = false; };
|
||||
setHeaders = mkOption
|
||||
{ type = types.attrsOf types.str; default.Host = submoduleInputs.config._module.args.name; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};}));
|
||||
default = {};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) nginx; in inputs.lib.mkIf (nginx.http != {})
|
||||
{
|
||||
assertions = inputs.lib.mapAttrsToList
|
||||
(n: v:
|
||||
{
|
||||
assertion = (inputs.lib.count (x: x != null) (builtins.map (type: v.${type}) nginx.global.httpTypes)) <= 1;
|
||||
message = "Only one type shuold be specified in ${n}";
|
||||
})
|
||||
nginx.http;
|
||||
services.nginx.virtualHosts = inputs.lib.mapAttrs'
|
||||
(n: v:
|
||||
{
|
||||
name = "http.${n}";
|
||||
value = { serverName = n; listen = [ { addr = "0.0.0.0"; port = 80; } ]; }
|
||||
// (inputs.lib.optionalAttrs (v.rewriteHttps != null)
|
||||
{ locations."/".return = "301 https://${v.rewriteHttps.hostname}$request_uri"; })
|
||||
// (inputs.lib.optionalAttrs (v.php != null)
|
||||
{
|
||||
extraConfig = "index index.php;";
|
||||
root = v.php.root;
|
||||
locations."~ ^.+?.php(/.*)?$".extraConfig =
|
||||
''
|
||||
fastcgi_pass ${v.php.fastcgiPass};
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
include ${inputs.config.services.nginx.package}/conf/fastcgi.conf;
|
||||
'';
|
||||
})
|
||||
// (inputs.lib.optionalAttrs (v.proxy != null)
|
||||
{
|
||||
locations."/" =
|
||||
{
|
||||
proxyPass = v.proxy.upstream;
|
||||
proxyWebsockets = v.proxy.websocket;
|
||||
extraConfig = builtins.concatStringsSep "\n" (inputs.lib.mapAttrsToList
|
||||
(n: v: ''proxy_set_header ${n} "${v}";'')
|
||||
v.proxy.setHeaders);
|
||||
};
|
||||
});
|
||||
})
|
||||
nginx.http;
|
||||
};
|
||||
}
|
||||
393
modules/services/nginx/https.nix
Normal file
393
modules/services/nginx/https.nix
Normal file
@@ -0,0 +1,393 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.nginx.https = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule (siteSubmoduleInputs: { options =
|
||||
{
|
||||
global =
|
||||
{
|
||||
configName = mkOption
|
||||
{ type = types.nonEmptyStr; default = "https:${siteSubmoduleInputs.config._module.args.name}"; };
|
||||
root = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
index = mkOption
|
||||
{
|
||||
type = types.nullOr (types.oneOf [ (types.enum [ "auto" ]) (types.nonEmptyListOf types.nonEmptyStr) ]);
|
||||
default = null;
|
||||
};
|
||||
charset = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
detectAuth = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
text = mkOption { type = types.nonEmptyStr; default = "Restricted Content"; };
|
||||
users = mkOption { type = types.nonEmptyListOf types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
rewriteHttps = mkOption { type = types.bool; default = true; };
|
||||
tlsCert = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
};
|
||||
listen = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule { options =
|
||||
{
|
||||
http2 = mkOption { type = types.bool; default = true; };
|
||||
proxyProtocol = mkOption { type = types.bool; default = true; };
|
||||
# if proxyProtocol not enabled, add to transparentProxy only
|
||||
# if proxyProtocol enabled, add to transparentProxy and streamProxy
|
||||
addToTransparentProxy = mkOption { type = types.bool; default = true; };
|
||||
};});
|
||||
default.main = {};
|
||||
};
|
||||
location = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.submodule { options =
|
||||
let genericOptions =
|
||||
{
|
||||
# should be set to non null value if global root is null
|
||||
root = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
detectAuth = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
text = mkOption { type = types.nonEmptyStr; default = "Restricted Content"; };
|
||||
users = mkOption { type = types.nonEmptyListOf types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
# only one should be specified
|
||||
proxy = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
inherit (genericOptions) detectAuth;
|
||||
upstream = mkOption { type = types.nonEmptyStr; };
|
||||
websocket = mkOption { type = types.bool; default = false; };
|
||||
grpc = mkOption { type = types.bool; default = false; };
|
||||
setHeaders = mkOption
|
||||
{ type = types.attrsOf types.str; default.Host = siteSubmoduleInputs.config._module.args.name; };
|
||||
# echo -n "username:password" | base64
|
||||
addAuth = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
static = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
inherit (genericOptions) detectAuth root;
|
||||
index = mkOption
|
||||
{
|
||||
type = types.nullOr
|
||||
(types.oneOf [ (types.enum [ "auto" ]) (types.nonEmptyListOf types.nonEmptyStr) ]);
|
||||
default = null;
|
||||
};
|
||||
charset = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
||||
tryFiles = mkOption { type = types.nullOr (types.nonEmptyListOf types.nonEmptyStr); default = null; };
|
||||
webdav = mkOption { type = types.bool; default = false; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
php = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{ inherit (genericOptions) detectAuth root; fastcgiPass = mkOption { type = types.nonEmptyStr; };};});
|
||||
default = null;
|
||||
};
|
||||
return = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options = { return = mkOption { type = types.nonEmptyStr; }; };});
|
||||
default = null;
|
||||
};
|
||||
alias = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
path = mkOption { type = types.nonEmptyStr; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};});
|
||||
default = {};
|
||||
};
|
||||
};}));
|
||||
default = {};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) nginx; in inputs.lib.mkIf (nginx.https != {}) (inputs.lib.mkMerge
|
||||
[
|
||||
# https assertions
|
||||
{
|
||||
# only one type should be specified in each location
|
||||
assertions =
|
||||
(
|
||||
(builtins.map
|
||||
(location:
|
||||
{
|
||||
assertion = 1 >= (inputs.lib.count (x: x != null)
|
||||
(builtins.map (type: location.value.${type}) nginx.global.httpsLocationTypes));
|
||||
message = "Only one type shuold be specified in ${location.name}";
|
||||
})
|
||||
(builtins.concatLists (inputs.lib.mapAttrsToList
|
||||
(sn: sv: (inputs.lib.mapAttrsToList (ln: lv: inputs.lib.nameValuePair "${sn} ${ln}" lv) sv.location))
|
||||
nginx.https)))
|
||||
# root should be specified either in global or in each location
|
||||
++ (builtins.map
|
||||
(location:
|
||||
{
|
||||
assertion = (location.value.root or "") != null;
|
||||
message = "Root should be specified in ${location.name}";
|
||||
})
|
||||
(builtins.concatLists (builtins.map
|
||||
(site: (inputs.lib.mapAttrsToList
|
||||
(n: v: inputs.lib.nameValuePair "${site.name} ${n}" v)
|
||||
site.value.location))
|
||||
(builtins.filter (site: site.value.global.root == null) (inputs.localLib.attrsToList nginx.https)))))
|
||||
);
|
||||
}
|
||||
# https
|
||||
(
|
||||
# merge different types of locations
|
||||
let sites = inputs.lib.mapAttrsToList
|
||||
(sn: sv: inputs.lib.nameValuePair sn
|
||||
{
|
||||
inherit (sv) global;
|
||||
listens = builtins.attrValues sv.listen;
|
||||
locations = inputs.lib.mapAttrsToList
|
||||
(ln: lv: inputs.lib.nameValuePair ln
|
||||
(
|
||||
let _ = builtins.head (builtins.filter (type: type.value != null) (inputs.localLib.attrsToList lv));
|
||||
in _.value // { type = _.name; }
|
||||
))
|
||||
sv.location;
|
||||
})
|
||||
nginx.https;
|
||||
in
|
||||
{
|
||||
services.nginx.virtualHosts = builtins.listToAttrs (builtins.map
|
||||
(site:
|
||||
{
|
||||
name = site.value.global.configName;
|
||||
value =
|
||||
{
|
||||
serverName = site.name;
|
||||
root = inputs.lib.mkIf (site.value.global.root != null) site.value.global.root;
|
||||
basicAuthFile = inputs.lib.mkIf (site.value.global.detectAuth != null)
|
||||
(
|
||||
let secret = "nginx/templates/detectAuth/${inputs.lib.strings.escapeURL site.name}-global";
|
||||
in inputs.config.nixos.system.sops.templates.${secret}.path
|
||||
);
|
||||
extraConfig = builtins.concatStringsSep "\n"
|
||||
(
|
||||
(
|
||||
let inherit (site.value.global) index; in
|
||||
if (builtins.typeOf index == "list") then [ "index ${builtins.concatStringsSep " " index};" ]
|
||||
else if (index == "auto") then [ "autoindex on;" ]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
let inherit (site.value.global) detectAuth;
|
||||
in inputs.lib.optionals (detectAuth != null) [ ''auth_basic "${detectAuth.text}"'' ]
|
||||
)
|
||||
++ (
|
||||
let inherit (site.value.global) charset;
|
||||
in inputs.lib.optionals (charset != null) [ "charset ${charset};" ]
|
||||
)
|
||||
);
|
||||
listen = builtins.map
|
||||
(listen:
|
||||
{
|
||||
addr = if listen.proxyProtocol then "0.0.0.0" else "127.0.0.1";
|
||||
port = with nginx.global; httpsPort
|
||||
+ (if listen.http2 then httpsPortShift.http2 else 0)
|
||||
+ (if listen.proxyProtocol then httpsPortShift.proxyProtocol else 0);
|
||||
ssl = true;
|
||||
proxyProtocol = listen.proxyProtocol;
|
||||
extraParameters = inputs.lib.mkIf listen.http2 [ "http2" ];
|
||||
})
|
||||
site.value.listens;
|
||||
# do not automatically add http2 listen
|
||||
http2 = false;
|
||||
onlySSL = true;
|
||||
useACMEHost = inputs.lib.mkIf (site.value.global.tlsCert == null) site.name;
|
||||
sslCertificate = inputs.lib.mkIf (site.value.global.tlsCert != null)
|
||||
"${site.value.global.tlsCert}/fullchain.pem";
|
||||
sslCertificateKey = inputs.lib.mkIf (site.value.global.tlsCert != null)
|
||||
"${site.value.global.tlsCert}/privkey.pem";
|
||||
locations = builtins.listToAttrs (builtins.map
|
||||
(location:
|
||||
{
|
||||
inherit (location) name;
|
||||
value =
|
||||
{
|
||||
basicAuthFile = inputs.lib.mkIf (location.value.detectAuth or null != null)
|
||||
(
|
||||
let
|
||||
inherit (inputs.lib.strings) escapeURL;
|
||||
secret = "nginx/templates/detectAuth/${escapeURL site.name}/${escapeURL location.name}";
|
||||
in inputs.config.nixos.system.sops.templates.${secret}.path
|
||||
);
|
||||
root = inputs.lib.mkIf (location.value.root or null != null) location.value.root;
|
||||
}
|
||||
// {
|
||||
proxy =
|
||||
{
|
||||
proxyWebsockets = location.value.websocket;
|
||||
extraConfig = builtins.concatStringsSep "\n"
|
||||
(
|
||||
[ "${if location.value.grpc then "grpc" else "proxy"}_pass ${location.value.upstream};" ]
|
||||
++ (inputs.lib.mapAttrsToList (n: v: ''proxy_set_header ${n} "${v}";'')
|
||||
location.value.setHeaders)
|
||||
++ (inputs.lib.optionals
|
||||
(location.value.detectAuth != null || site.value.global.detectAuth != null)
|
||||
[ "proxy_hide_header Authorization;" ]
|
||||
)
|
||||
++ (inputs.lib.optionals (location.value.addAuth != null)
|
||||
(
|
||||
let authFile = "nginx/templates/addAuth/${location.value.addAuth}";
|
||||
in [ "include ${inputs.config.nixos.system.sops.templates.${authFile}.path};" ]
|
||||
))
|
||||
);
|
||||
};
|
||||
static =
|
||||
{
|
||||
index = inputs.lib.mkIf (builtins.typeOf location.value.index == "list")
|
||||
(builtins.concatStringsSep " " location.value.index);
|
||||
tryFiles = inputs.lib.mkIf (location.value.tryFiles != null)
|
||||
(builtins.concatStringsSep " " location.value.tryFiles);
|
||||
extraConfig = inputs.lib.mkMerge
|
||||
[
|
||||
(inputs.lib.mkIf (location.value.index == "auto") "autoindex on;")
|
||||
(inputs.lib.mkIf (location.value.charset != null) "charset ${location.value.charset};")
|
||||
(inputs.lib.mkIf location.value.webdav
|
||||
''
|
||||
dav_access user:rw group:rw;
|
||||
dav_methods PUT DELETE MKCOL COPY MOVE;
|
||||
dav_ext_methods PROPFIND OPTIONS;
|
||||
create_full_put_path on;
|
||||
'')
|
||||
];
|
||||
};
|
||||
php.extraConfig =
|
||||
''
|
||||
fastcgi_pass ${location.value.fastcgiPass};
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
include ${inputs.config.services.nginx.package}/conf/fastcgi.conf;
|
||||
'';
|
||||
return.return = location.value.return;
|
||||
alias.alias = location.value.path;
|
||||
}.${location.value.type};
|
||||
})
|
||||
site.value.locations);
|
||||
};
|
||||
})
|
||||
sites);
|
||||
nixos =
|
||||
{
|
||||
services =
|
||||
{
|
||||
nginx =
|
||||
# { name = domain; value = listen = { http2 = xxx, proxyProtocol = xxx }; }
|
||||
let listens = builtins.filter
|
||||
(listen: listen.value.addToTransparentProxy)
|
||||
(builtins.concatLists (builtins.map
|
||||
(site: builtins.map (listen: { inherit (site) name; value = listen; }) site.value.listens)
|
||||
sites));
|
||||
in
|
||||
{
|
||||
transparentProxy.map = builtins.listToAttrs (builtins.map
|
||||
(site:
|
||||
{
|
||||
inherit (site) name;
|
||||
value = with nginx.global; httpsPort + (if site.value.http2 then httpsPortShift.http2 else 0);
|
||||
})
|
||||
(builtins.filter (listen: !listen.value.proxyProtocol) listens));
|
||||
streamProxy.map = builtins.listToAttrs (builtins.map
|
||||
(site:
|
||||
{
|
||||
inherit (site) name;
|
||||
value =
|
||||
{
|
||||
upstream.port = with nginx.global; httpsPort + httpsPortShift.proxyProtocol
|
||||
+ (if site.value.http2 then httpsPortShift.http2 else 0);
|
||||
proxyProtocol = true;
|
||||
rewriteHttps = inputs.lib.mkDefault false;
|
||||
};
|
||||
})
|
||||
(builtins.filter (listen: listen.value.proxyProtocol) listens));
|
||||
http = builtins.listToAttrs (builtins.map
|
||||
(site: { inherit (site) name; value.rewriteHttps = {}; })
|
||||
(builtins.filter (site: site.value.global.rewriteHttps) sites));
|
||||
};
|
||||
acme.cert = builtins.listToAttrs (builtins.map
|
||||
(site: { inherit (site) name; value.group = inputs.config.services.nginx.group; })
|
||||
sites);
|
||||
};
|
||||
system.sops =
|
||||
let
|
||||
inherit (inputs.lib.strings) escapeURL;
|
||||
detectAuthUsers = builtins.concatLists (builtins.map
|
||||
(site:
|
||||
(
|
||||
(builtins.map
|
||||
(location:
|
||||
{
|
||||
name = "${escapeURL site.name}/${escapeURL location.name}";
|
||||
value = location.value.detectAuth.users;
|
||||
})
|
||||
(builtins.filter (location: location.value.detectAuth or null != null) site.value.locations))
|
||||
++ (inputs.lib.optionals (site.value.global.detectAuth != null)
|
||||
[ { name = "${escapeURL site.name}-global"; value = site.value.global.detectAuth.users; } ])
|
||||
))
|
||||
sites);
|
||||
addAuth = builtins.concatLists (builtins.map
|
||||
(site: builtins.map
|
||||
(location:
|
||||
{
|
||||
name = "${escapeURL site.name}/${escapeURL location.name}";
|
||||
value = location.value.addAuth;
|
||||
})
|
||||
(builtins.filter (location: location.value.addAuth or null != null) site.value.locations)
|
||||
)
|
||||
sites);
|
||||
in
|
||||
{
|
||||
templates = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(detectAuth: inputs.lib.nameValuePair "nginx/templates/detectAuth/${detectAuth.name}"
|
||||
{
|
||||
owner = inputs.config.users.users.nginx.name;
|
||||
content = builtins.concatStringsSep "\n" (builtins.map
|
||||
(user: "${user}:{PLAIN}${placeholder."nginx/detectAuth/${user}"}")
|
||||
detectAuth.value);
|
||||
})
|
||||
detectAuthUsers)
|
||||
++ (builtins.map
|
||||
(addAuth: inputs.lib.nameValuePair "nginx/templates/addAuth/${addAuth.name}"
|
||||
{
|
||||
owner = inputs.config.users.users.nginx.name;
|
||||
content =
|
||||
''proxy_set_header Authorization "Basic ${placeholder."nginx/addAuth/${addAuth.value}"}";'';
|
||||
})
|
||||
addAuth)
|
||||
);
|
||||
secrets = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(secret: { name = "nginx/detectAuth/${secret}"; value = {}; })
|
||||
(inputs.lib.unique (builtins.concatLists (builtins.map (detectAuth: detectAuth.value)
|
||||
detectAuthUsers))))
|
||||
++ (builtins.map
|
||||
(secret: { name = "nginx/addAuth/${secret}"; value = {}; })
|
||||
(inputs.lib.unique (builtins.map (addAuth: addAuth.value) addAuth)))
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
]);
|
||||
}
|
||||
97
modules/services/nginx/streamProxy.nix
Normal file
97
modules/services/nginx/streamProxy.nix
Normal file
@@ -0,0 +1,97 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.nginx.streamProxy = let inherit (inputs.lib) mkOption types; in
|
||||
{
|
||||
map = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.oneOf
|
||||
[
|
||||
# proxy to specified ip:port without proxyProtocol
|
||||
types.nonEmptyStr
|
||||
(types.submodule { options =
|
||||
{
|
||||
upstream = mkOption
|
||||
{
|
||||
type = types.oneOf
|
||||
[
|
||||
# proxy to specified ip:port with or without proxyProtocol
|
||||
types.nonEmptyStr
|
||||
(types.submodule { options =
|
||||
{
|
||||
address = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
|
||||
# if port not specified, guess from proxyProtocol enabled or not, assume http2 enabled
|
||||
port = mkOption { type = types.nullOr types.ints.unsigned; default = null; };
|
||||
};})
|
||||
];
|
||||
default = {};
|
||||
};
|
||||
proxyProtocol = mkOption { type = types.bool; default = true; };
|
||||
addToTransparentProxy = mkOption { type = types.bool; default = true; };
|
||||
rewriteHttps = mkOption { type = types.bool; default = true; };
|
||||
};})
|
||||
]);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) nginx; in inputs.lib.mkIf (nginx.streamProxy.map != {})
|
||||
{
|
||||
services.nginx.streamConfig =
|
||||
''
|
||||
log_format stream_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
|
||||
'"$ssl_preread_server_name"->$stream_proxy_backend $bytes_sent $bytes_received';
|
||||
map $ssl_preread_server_name $stream_proxy_backend {
|
||||
${builtins.concatStringsSep "\n " (inputs.lib.mapAttrsToList
|
||||
(n: v:
|
||||
let
|
||||
upstream =
|
||||
if (builtins.typeOf v.upstream == "string") then v.upstream
|
||||
else
|
||||
let port = with nginx.global;
|
||||
if v.upstream.port == null then
|
||||
httpsPort + httpsPortShift.http2 + (if v.proxyProtocol then httpsPortShift.proxyProtocol else 0)
|
||||
else v.upstream.port;
|
||||
in "${v.upstream.address}:${builtins.toString port}";
|
||||
in ''"${n}" "${upstream}";'')
|
||||
nginx.streamProxy.map)}
|
||||
}
|
||||
server {
|
||||
listen 127.0.0.1:${toString nginx.global.streamPort};
|
||||
ssl_preread on;
|
||||
proxy_pass $stream_proxy_backend;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log stream_proxy;
|
||||
}
|
||||
server {
|
||||
listen 127.0.0.1:${builtins.toString (with nginx.global; (streamPort + streamPortShift.proxyProtocol))};
|
||||
proxy_protocol on;
|
||||
ssl_preread on;
|
||||
proxy_pass $stream_proxy_backend;
|
||||
proxy_connect_timeout 10s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log stream_proxy;
|
||||
}
|
||||
'';
|
||||
nixos.services.nginx =
|
||||
{
|
||||
transparentProxy.map = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(site: { inherit (site) name; value = nginx.global.streamPort; })
|
||||
(builtins.filter
|
||||
(site: (!(site.value.proxyProtocol or false) && (site.value.addToTransparentProxy or true)))
|
||||
(inputs.localLib.attrsToList nginx.streamProxy.map)))
|
||||
++ (builtins.map
|
||||
(site: { inherit (site) name; value = with nginx.global; streamPort + streamPortShift.proxyProtocol; })
|
||||
(builtins.filter
|
||||
(site: ((site.value.proxyProtocol or false) && (site.value.addToTransparentProxy or true)))
|
||||
(inputs.localLib.attrsToList nginx.streamProxy.map)))
|
||||
);
|
||||
http = builtins.listToAttrs (builtins.map
|
||||
(site: { inherit (site) name; value.rewriteHttps = {}; })
|
||||
(builtins.filter (site: site.value.rewriteHttps or false) (inputs.localLib.attrsToList nginx.streamProxy.map)));
|
||||
};
|
||||
};
|
||||
}
|
||||
94
modules/services/nginx/transparentProxy.nix
Normal file
94
modules/services/nginx/transparentProxy.nix
Normal file
@@ -0,0 +1,94 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.nginx.transparentProxy = let inherit (inputs.lib) mkOption types; in
|
||||
{
|
||||
# proxy to 127.0.0.1:${specified port}
|
||||
map = mkOption
|
||||
{
|
||||
type = types.attrsOf (types.oneOf
|
||||
[
|
||||
# proxy to 127.0.0.1:${specified port}
|
||||
types.ints.unsigned
|
||||
# proxy to specified ip:port
|
||||
types.nonEmptyStr
|
||||
]);
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) nginx; in inputs.lib.mkIf (nginx.transparentProxy.map != {})
|
||||
{
|
||||
services.nginx.streamConfig =
|
||||
''
|
||||
log_format transparent_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
|
||||
'"$ssl_preread_server_name"->$transparent_proxy_backend $bytes_sent $bytes_received';
|
||||
map $ssl_preread_server_name $transparent_proxy_backend {
|
||||
${builtins.concatStringsSep "\n " (inputs.lib.mapAttrsToList
|
||||
(n: v: ''"${n}" ${if builtins.isInt v then "127.0.0.1:${builtins.toString v}" else v};'')
|
||||
nginx.transparentProxy.map)}
|
||||
default 127.0.0.1:${toString (with nginx.global; (httpsPort + httpsPortShift.http2))};
|
||||
}
|
||||
server {
|
||||
listen 0.0.0.0:443;
|
||||
ssl_preread on;
|
||||
proxy_bind $remote_addr transparent;
|
||||
proxy_pass $transparent_proxy_backend;
|
||||
proxy_connect_timeout 1s;
|
||||
proxy_socket_keepalive on;
|
||||
proxy_buffer_size 128k;
|
||||
access_log syslog:server=unix:/dev/log transparent_proxy;
|
||||
}
|
||||
'';
|
||||
# TODO: use existing options
|
||||
systemd.services.nginx-proxy =
|
||||
let
|
||||
ip = "${inputs.pkgs.iproute2}/bin/ip";
|
||||
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
|
||||
''
|
||||
${ip} rule add fwmark 2/2 table 200
|
||||
${ip} route add local 0.0.0.0/0 dev lo table 200
|
||||
'';
|
||||
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop"
|
||||
''
|
||||
${ip} rule del fwmark 2/2 table 200
|
||||
${ip} route del local 0.0.0.0/0 dev lo table 200
|
||||
'';
|
||||
in
|
||||
{
|
||||
description = "nginx transparent proxy";
|
||||
after = [ "network.target" ];
|
||||
serviceConfig =
|
||||
{
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = start;
|
||||
ExecStop = stop;
|
||||
};
|
||||
wants = [ "network.target" ];
|
||||
wantedBy= [ "multi-user.target" ];
|
||||
};
|
||||
networking.nftables.tables.nginx =
|
||||
{
|
||||
family = "inet";
|
||||
content =
|
||||
''
|
||||
chain output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
# 由本机发出、gid 为 nginx、但源地址不是本地监听的地址,说明是透明代理的第一个包,将这个流标记
|
||||
# 但这个包本身不需要处理,正常路由即可。
|
||||
meta skgid ${builtins.toString inputs.config.users.groups.nginx.gid} fib saddr type != local \
|
||||
ct state new counter ct mark set ct mark | 2 return
|
||||
# 由本机发出、作为透明代理的回复,它不能按照通常的路由,它需要被打上标记并被路由到本地
|
||||
# 这对应于透明代理到本地的服务的情况
|
||||
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
|
||||
return
|
||||
}
|
||||
# 还需要处理透明代理到其它机器的情况,它们的回复需要在 prerouting 中标记
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
|
||||
return
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -13,11 +13,17 @@ inputs:
|
||||
services.nix-serve =
|
||||
{
|
||||
enable = true;
|
||||
package = inputs.pkgs.nix-serve-ng;
|
||||
openFirewall = true;
|
||||
secretKeyFile = inputs.config.sops.secrets."store/signingKey".path;
|
||||
secretKeyFile = inputs.config.nixos.system.sops.secrets."store/signingKey".path;
|
||||
# curl -L cache.nixos.org/nix-cache-info
|
||||
# use this cache after official one
|
||||
extraParams = "--priority 50";
|
||||
};
|
||||
nixos =
|
||||
{
|
||||
system.sops.secrets."store/signingKey" = {};
|
||||
services.nginx.https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000";
|
||||
};
|
||||
sops.secrets."store/signingKey" = {};
|
||||
nixos.services.nginx =
|
||||
{ enable = true; https.${nix-serve.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5000"; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ inputs:
|
||||
domains = builtins.map
|
||||
(vm:
|
||||
{
|
||||
definition = inputs.config.sops.templates."nixvirt/${vm.name}.xml".path;
|
||||
definition = inputs.config.nixos.system.sops.templates."nixvirt/${vm.name}.xml".path;
|
||||
active = true;
|
||||
restart = false;
|
||||
})
|
||||
@@ -122,147 +122,142 @@ inputs:
|
||||
vnc_listen = "0.0.0.0"
|
||||
'';
|
||||
};
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
nginx =
|
||||
let hosts = builtins.concatLists (builtins.map
|
||||
(vm: builtins.map
|
||||
(domain:
|
||||
{
|
||||
inherit domain;
|
||||
ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}";
|
||||
})
|
||||
vm.network.portForward.web)
|
||||
(builtins.attrValues nixvirt.instance));
|
||||
in
|
||||
{
|
||||
enable = inputs.lib.mkIf (hosts != []) true;
|
||||
transparentProxy.map = builtins.listToAttrs (builtins.map
|
||||
(host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts);
|
||||
http = builtins.listToAttrs (builtins.map
|
||||
(host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts);
|
||||
};
|
||||
kvm = {};
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates = builtins.listToAttrs (builtins.map
|
||||
(vm:
|
||||
{
|
||||
name = "nixvirt/${vm.name}.xml";
|
||||
value.content = inputs.topInputs.nixvirt.lib.domain.getXML
|
||||
# port from 8bcc23e27a62297254d0e9c87281e650ff777132
|
||||
system.sops =
|
||||
{
|
||||
templates = inputs.lib.mapAttrs'
|
||||
(n: v: inputs.lib.nameValuePair "nixvirt/${n}.xml"
|
||||
{
|
||||
inherit (vm) name;
|
||||
inherit (vm.value) uuid;
|
||||
type = "kvm";
|
||||
vcpu = { placement = "static"; count = vm.value.cpu.count; };
|
||||
cputune = inputs.lib.optionalAttrs (vm.value.cpu.set != null)
|
||||
content = inputs.topInputs.nixvirt.lib.domain.getXML
|
||||
# port from 8bcc23e27a62297254d0e9c87281e650ff777132
|
||||
{
|
||||
vcpupin = builtins.genList
|
||||
(cpu: { vcpu = cpu; cpuset = builtins.elemAt vm.value.cpu.set cpu; })
|
||||
vm.value.cpu.count;
|
||||
};
|
||||
memory =
|
||||
{
|
||||
count = vm.value.memory.sizeMB;
|
||||
unit = "MiB";
|
||||
nosharepages = vm.value.memory.dedicated;
|
||||
locked = vm.value.memory.dedicated;
|
||||
};
|
||||
os =
|
||||
{
|
||||
type = "hvm";
|
||||
arch = "x86_64";
|
||||
machine = "q35";
|
||||
bootmenu = { enable = true; timeout = 15000; };
|
||||
loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; };
|
||||
nvram =
|
||||
name = n;
|
||||
inherit (v) uuid;
|
||||
type = "kvm";
|
||||
vcpu = { placement = "static"; count = v.cpu.count; };
|
||||
cputune = inputs.lib.optionalAttrs (v.cpu.set != null)
|
||||
{
|
||||
template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd";
|
||||
path = "/var/lib/libvirt/qemu/nvram/${vm.name}_VARS.fd";
|
||||
templateFormat = "raw";
|
||||
format = "raw";
|
||||
vcpupin = builtins.genList (cpu: { vcpu = cpu; cpuset = builtins.elemAt v.cpu.set cpu; }) v.cpu.count;
|
||||
};
|
||||
};
|
||||
features = { acpi = {}; apic = {}; };
|
||||
cpu =
|
||||
{
|
||||
mode = "host-passthrough";
|
||||
topology =
|
||||
memory =
|
||||
{
|
||||
sockets = 1;
|
||||
dies = 1;
|
||||
cores = if vm.value.cpu.hyprthread then vm.value.cpu.count / 2 else vm.value.cpu.count;
|
||||
threads = if vm.value.cpu.hyprthread then 2 else 1;
|
||||
count = v.memory.sizeMB;
|
||||
unit = "MiB";
|
||||
nosharepages = v.memory.dedicated;
|
||||
locked = v.memory.dedicated;
|
||||
};
|
||||
};
|
||||
clock =
|
||||
{
|
||||
offset = "utc";
|
||||
timer =
|
||||
[
|
||||
{ name = "rtc"; tickpolicy = "catchup"; }
|
||||
{ name = "pit"; tickpolicy = "delay"; }
|
||||
{ name = "hpet"; present = false; }
|
||||
];
|
||||
};
|
||||
devices =
|
||||
{
|
||||
emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64";
|
||||
disk =
|
||||
[
|
||||
os =
|
||||
{
|
||||
type = "hvm";
|
||||
arch = "x86_64";
|
||||
machine = "q35";
|
||||
bootmenu = { enable = true; timeout = 15000; };
|
||||
loader = { readonly = true; type = "pflash"; path = "/run/libvirt/nix-ovmf/OVMF_CODE.fd"; };
|
||||
nvram =
|
||||
{
|
||||
type = "file";
|
||||
device = "disk";
|
||||
driver = { name = "qemu"; type = "raw"; cache = "none"; discard = "unmap"; };
|
||||
source.file = "${if vm.value.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/"
|
||||
+ "${vm.value.storage.name}.img";
|
||||
target = { dev = "vda"; bus = "virtio"; };
|
||||
boot.order = 1;
|
||||
}
|
||||
template = "/run/libvirt/nix-ovmf/OVMF_VARS.fd";
|
||||
path = "/var/lib/libvirt/qemu/nvram/${n}_VARS.fd";
|
||||
templateFormat = "raw";
|
||||
format = "raw";
|
||||
};
|
||||
};
|
||||
features = { acpi = {}; apic = {}; };
|
||||
cpu =
|
||||
{
|
||||
mode = "host-passthrough";
|
||||
topology =
|
||||
{
|
||||
type = "file";
|
||||
device = "cdrom";
|
||||
driver = { name = "qemu"; type = "raw"; };
|
||||
source.file = "${inputs.topInputs.self.src.iso.netboot}";
|
||||
target = { dev = "sdc"; bus = "sata"; };
|
||||
readonly = true;
|
||||
boot.order = 10;
|
||||
}
|
||||
];
|
||||
interface =
|
||||
{
|
||||
type = "bridge";
|
||||
model.type = "virtio";
|
||||
mac.address = vm.value.network.mac;
|
||||
source.bridge = if vm.value.network.bridge then "nixvirt" else "virbr0";
|
||||
sockets = 1;
|
||||
dies = 1;
|
||||
cores = if v.cpu.hyprthread then v.cpu.count / 2 else v.cpu.count;
|
||||
threads = if v.cpu.hyprthread then 2 else 1;
|
||||
};
|
||||
};
|
||||
input =
|
||||
[
|
||||
{ type = "tablet"; bus = "usb"; }
|
||||
{ type = "mouse"; bus = "ps2"; }
|
||||
{ type = "keyboard"; bus = "ps2"; }
|
||||
];
|
||||
graphics =
|
||||
clock =
|
||||
{
|
||||
type = "vnc";
|
||||
autoport = false;
|
||||
port = vm.value.network.vnc.port;
|
||||
listen.type = "address";
|
||||
passwd = inputs.config.sops.placeholder."nixvirt/${vm.name}";
|
||||
offset = "utc";
|
||||
timer =
|
||||
[
|
||||
{ name = "rtc"; tickpolicy = "catchup"; }
|
||||
{ name = "pit"; tickpolicy = "delay"; }
|
||||
{ name = "hpet"; present = false; }
|
||||
];
|
||||
};
|
||||
devices =
|
||||
{
|
||||
emulator = "${inputs.config.virtualisation.libvirtd.qemu.package}/bin/qemu-system-x86_64";
|
||||
disk =
|
||||
[
|
||||
{
|
||||
type = "file";
|
||||
device = "disk";
|
||||
driver = { name = "qemu"; type = "raw"; cache = "writeback"; discard = "unmap"; };
|
||||
source.file = "${if v.storage.nodatacow then "/nix/nodatacow" else ""}/var/lib/libvirt/images/"
|
||||
+ "${v.storage.name}.img";
|
||||
target = { dev = "vda"; bus = "virtio"; };
|
||||
boot.order = 1;
|
||||
}
|
||||
{
|
||||
type = "file";
|
||||
device = "cdrom";
|
||||
driver = { name = "qemu"; type = "raw"; };
|
||||
source.file = "${inputs.topInputs.self.src.iso.netboot}";
|
||||
target = { dev = "sdc"; bus = "sata"; };
|
||||
readonly = true;
|
||||
boot.order = 10;
|
||||
}
|
||||
];
|
||||
interface =
|
||||
{
|
||||
type = "bridge";
|
||||
model.type = "virtio";
|
||||
mac.address = v.network.mac;
|
||||
source.bridge = if v.network.bridge then "nixvirt" else "virbr0";
|
||||
};
|
||||
input =
|
||||
[
|
||||
{ type = "tablet"; bus = "usb"; }
|
||||
{ type = "mouse"; bus = "ps2"; }
|
||||
{ type = "keyboard"; bus = "ps2"; }
|
||||
];
|
||||
graphics =
|
||||
{
|
||||
type = "vnc";
|
||||
autoport = false;
|
||||
port = v.network.vnc.port;
|
||||
listen.type = "address";
|
||||
passwd = inputs.config.sops.placeholder."nixvirt/${n}";
|
||||
};
|
||||
video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; };
|
||||
rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; };
|
||||
};
|
||||
video.model = { type = "qxl"; ram = 65536; vram = 65536; vgamem = 16384; heads = 1; primary = true; };
|
||||
rng = { model = "virtio"; backend = { model = "random"; source = /dev/urandom; }; };
|
||||
};
|
||||
})
|
||||
nixvirt.instance;
|
||||
secrets = inputs.lib.mapAttrs' (n: _: inputs.lib.nameValuePair "nixvirt/${n}" {}) nixvirt.instance;
|
||||
};
|
||||
services =
|
||||
{
|
||||
nginx =
|
||||
let hosts = builtins.concatLists (builtins.map
|
||||
(vm: builtins.map
|
||||
(domain:
|
||||
{
|
||||
inherit domain;
|
||||
ip = "192.168.${builtins.toString nixvirt.subnet}.${builtins.toString vm.network.address}";
|
||||
})
|
||||
vm.network.portForward.web)
|
||||
(builtins.attrValues nixvirt.instance));
|
||||
in
|
||||
{
|
||||
transparentProxy.map = builtins.listToAttrs (builtins.map
|
||||
(host: { name = host.domain; value = "${host.ip}" + ":443"; }) hosts);
|
||||
http = builtins.listToAttrs (builtins.map
|
||||
(host: { name = host.domain; value.proxy.upstream = "http://${host.ip}" + ":80"; }) hosts);
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList nixvirt.instance));
|
||||
secrets = builtins.listToAttrs (builtins.map
|
||||
(vm: { name = "nixvirt/${vm}"; value = {}; }) (builtins.attrNames nixvirt.instance));
|
||||
placeholder = builtins.listToAttrs (builtins.map
|
||||
(vm: { name = "nixvirt/${vm}"; value = builtins.hashString "sha256" "nixvirt/${vm}"; })
|
||||
(builtins.attrNames nixvirt.instance));
|
||||
kvm = {};
|
||||
};
|
||||
};
|
||||
security.wrappers.vm =
|
||||
{
|
||||
|
||||
@@ -28,22 +28,22 @@ inputs:
|
||||
ENABLE_IMAGE_GENERATION = "True";
|
||||
IMAGES_OPENAI_API_BASE_URL = "https://oa.api2d.net/v1";
|
||||
};
|
||||
environmentFile = inputs.config.sops.templates."open-webui.env".path;
|
||||
environmentFile = inputs.config.nixos.system.sops.templates."open-webui.env".path;
|
||||
};
|
||||
sops =
|
||||
nixos =
|
||||
{
|
||||
templates."open-webui.env".content = let inherit (inputs.config.sops) placeholder; in
|
||||
''
|
||||
OPENAI_API_KEY=${placeholder."open-webui/openai"}
|
||||
WEBUI_SECRET_KEY=${placeholder."open-webui/webui"}
|
||||
IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"}
|
||||
'';
|
||||
secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; };
|
||||
};
|
||||
nixos.services.nginx =
|
||||
{
|
||||
enable = true;
|
||||
https."${open-webui.hostname}".location."/".proxy = { upstream = "http://127.0.0.1:8080"; websocket = true; };
|
||||
system.sops =
|
||||
{
|
||||
templates."open-webui.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
''
|
||||
OPENAI_API_KEY=${placeholder."open-webui/openai"}
|
||||
WEBUI_SECRET_KEY=${placeholder."open-webui/webui"}
|
||||
IMAGES_OPENAI_API_KEY=${placeholder."open-webui/openai"}
|
||||
'';
|
||||
secrets = { "open-webui/openai" = {}; "open-webui/webui" = {}; };
|
||||
};
|
||||
services.nginx.https."${open-webui.hostname}".location."/".proxy =
|
||||
{ upstream = "http://127.0.0.1:8080"; websocket = true; };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,48 +17,46 @@ inputs:
|
||||
listenHttp = 5046;
|
||||
listenWeb = 443;
|
||||
enableWebHttps = true;
|
||||
serviceEnvironmentFile = inputs.config.sops.templates."peertube/env".path;
|
||||
secrets.secretsFile = inputs.config.sops.secrets."peertube/secrets".path;
|
||||
serviceEnvironmentFile = inputs.config.nixos.system.sops.templates."peertube/env".path;
|
||||
secrets.secretsFile = inputs.config.nixos.system.sops.secrets."peertube/secrets".path;
|
||||
configureNginx = true;
|
||||
database =
|
||||
{
|
||||
createLocally = true;
|
||||
host = "127.0.0.1";
|
||||
passwordFile = inputs.config.sops.secrets."peertube/postgresql".path;
|
||||
passwordFile = inputs.config.nixos.system.sops.secrets."peertube/postgresql".path;
|
||||
};
|
||||
redis =
|
||||
{
|
||||
host = "127.0.0.1";
|
||||
port = 7599;
|
||||
passwordFile = inputs.config.sops.secrets."redis/peertube".path;
|
||||
};
|
||||
smtp.passwordFile = inputs.config.sops.secrets."peertube/smtp".path;
|
||||
settings.smtp =
|
||||
{
|
||||
host = "mail.chn.moe";
|
||||
username = "bot@chn.moe";
|
||||
from_address = "bot@chn.moe";
|
||||
passwordFile = inputs.config.nixos.system.sops.secrets."redis/peertube".path;
|
||||
};
|
||||
smtp.passwordFile = inputs.config.nixos.system.sops.secrets."peertube/smtp".path;
|
||||
settings.smtp = { host = "mail.chn.moe"; username = "bot@chn.moe"; from_address = "bot@chn.moe"; };
|
||||
};
|
||||
sops =
|
||||
nixos =
|
||||
{
|
||||
templates."peertube/env".content =
|
||||
''
|
||||
PT_INITIAL_ROOT_PASSWORD=${inputs.config.sops.placeholder."peertube/password"}
|
||||
'';
|
||||
secrets =
|
||||
system.sops =
|
||||
{
|
||||
"peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; };
|
||||
"peertube/password" = {};
|
||||
"peertube/secrets".owner = inputs.config.services.peertube.user;
|
||||
"peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; };
|
||||
templates."peertube/env".content =
|
||||
''
|
||||
PT_INITIAL_ROOT_PASSWORD=${inputs.config.nixos.system.sops.placeholder."peertube/password"}
|
||||
'';
|
||||
secrets =
|
||||
{
|
||||
"peertube/postgresql" = { owner = inputs.config.services.peertube.user; key = "postgresql/peertube"; };
|
||||
"peertube/password" = {};
|
||||
"peertube/secrets".owner = inputs.config.services.peertube.user;
|
||||
"peertube/smtp" = { owner = inputs.config.services.peertube.user; key = "mail/bot"; };
|
||||
};
|
||||
};
|
||||
services =
|
||||
{
|
||||
nginx.https.${peertube.hostname}.global.configName = peertube.hostname;
|
||||
postgresql.instances.peertube = {};
|
||||
redis.instances.peertube.port = 7599;
|
||||
};
|
||||
};
|
||||
nixos.services =
|
||||
{
|
||||
nginx = { enable = true; https.${peertube.hostname}.global.configName = peertube.hostname; };
|
||||
postgresql.instances.peertube = {};
|
||||
redis.instances.peertube.port = 7599;
|
||||
};
|
||||
systemd.services.peertube.after = [ "redis-peertube.service" ];
|
||||
};
|
||||
|
||||
@@ -1,56 +1,46 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.photoprism = let inherit (inputs.lib) mkOption types; in
|
||||
options.nixos.services.photoprism = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.services) photoprism; in inputs.lib.mkIf (photoprism != null)
|
||||
{
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
hostname = mkOption { type = types.nonEmptyStr; default = "photoprism.chn.moe"; };
|
||||
port = mkOption { type = types.ints.unsigned; default = 2342; };
|
||||
};
|
||||
config =
|
||||
let
|
||||
inherit (inputs.lib) mkIf;
|
||||
inherit (inputs.config.nixos.services) photoprism;
|
||||
in mkIf photoprism.enable
|
||||
services.photoprism =
|
||||
{
|
||||
services.photoprism =
|
||||
enable = true;
|
||||
originalsPath = inputs.config.services.photoprism.storagePath + "/originals";
|
||||
settings =
|
||||
{
|
||||
enable = true;
|
||||
originalsPath = inputs.config.services.photoprism.storagePath + "/originals";
|
||||
settings =
|
||||
{
|
||||
PHOTOPRISM_SITE_URL = "https://${photoprism.hostname}";
|
||||
PHOTOPRISM_HTTP_PORT = "${toString photoprism.port}";
|
||||
PHOTOPRISM_DISABLE_TLS = "true";
|
||||
PHOTOPRISM_DETECT_NSFW = "true";
|
||||
PHOTOPRISM_UPLOAD_NSFW = "true";
|
||||
PHOTOPRISM_DATABASE_DRIVER = "mysql";
|
||||
PHOTOPRISM_DATABASE_SERVER = "127.0.0.1:3306";
|
||||
};
|
||||
PHOTOPRISM_SITE_URL = "https://photoprism.chn.moe";
|
||||
PHOTOPRISM_HTTP_PORT = "2342";
|
||||
PHOTOPRISM_DISABLE_TLS = "true";
|
||||
PHOTOPRISM_DETECT_NSFW = "true";
|
||||
PHOTOPRISM_UPLOAD_NSFW = "true";
|
||||
PHOTOPRISM_DATABASE_DRIVER = "mysql";
|
||||
PHOTOPRISM_DATABASE_SERVER = "127.0.0.1:3306";
|
||||
};
|
||||
systemd.services.photoprism =
|
||||
};
|
||||
systemd.services.photoprism =
|
||||
{
|
||||
after = [ "mariadb.service" ];
|
||||
requires = [ "mariadb.service" ];
|
||||
serviceConfig.EnvironmentFile = inputs.config.nixos.system.sops.templates."photoprism/env".path;
|
||||
};
|
||||
nixos =
|
||||
{
|
||||
system.sops =
|
||||
{
|
||||
after = [ "mariadb.service" ];
|
||||
requires = [ "mariadb.service" ];
|
||||
serviceConfig.EnvironmentFile = inputs.config.sops.templates."photoprism/env".path;
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates."photoprism/env".content = let placeholder = inputs.config.sops.placeholder; in
|
||||
templates."photoprism/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
''
|
||||
PHOTOPRISM_ADMIN_PASSWORD=${placeholder."photoprism/adminPassword"}
|
||||
PHOTOPRISM_DATABASE_PASSWORD=${placeholder."mariadb/photoprism"}
|
||||
'';
|
||||
secrets."photoprism/adminPassword" = {};
|
||||
};
|
||||
nixos.services =
|
||||
services =
|
||||
{
|
||||
mariadb = { enable = true; instances.photoprism = {}; };
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
https.${photoprism.hostname}.location."/".proxy =
|
||||
{ upstream = "http://127.0.0.1:${toString photoprism.port}"; websocket = true; };
|
||||
};
|
||||
mariadb.instances.photoprism = {};
|
||||
nginx.https."photoprism.chn.moe".location."/".proxy = { upstream = "http://127.0.0.1:2342"; websocket = true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ inputs:
|
||||
let
|
||||
passwordFile =
|
||||
if db.value.passwordFile or null != null then db.value.passwordFile
|
||||
else inputs.config.sops.secrets."postgresql/${db.value.user}".path;
|
||||
else inputs.config.nixos.system.sops.secrets."postgresql/${db.value.user}".path;
|
||||
initializeFlag =
|
||||
if db.value.initializeFlags != {} then
|
||||
" WITH "
|
||||
@@ -85,7 +85,7 @@ inputs:
|
||||
+ " | grep -E '^${db.value.user}$' -q"
|
||||
+ " || $PSQL -tAc \"ALTER DATABASE ${db.value.database} OWNER TO ${db.value.user}\"")
|
||||
(inputs.localLib.attrsToList postgresql.instances)));
|
||||
sops.secrets = builtins.listToAttrs (builtins.map
|
||||
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
|
||||
(db: { name = "postgresql/${db.value.user}"; value.owner = inputs.config.users.users.postgres.name; })
|
||||
(builtins.filter (db: db.value.passwordFile == null) (inputs.localLib.attrsToList postgresql.instances)));
|
||||
environment.persistence."/nix/nodatacow".directories = inputs.lib.mkIf postgresql.nodatacow
|
||||
|
||||
@@ -28,12 +28,13 @@ inputs:
|
||||
# unixSocket = null; # bug
|
||||
unixSocketPerm = 600;
|
||||
requirePassFile =
|
||||
if server.value.passwordFile == null then inputs.config.sops.secrets."redis/${server.name}".path
|
||||
if server.value.passwordFile == null
|
||||
then inputs.config.nixos.system.sops.secrets."redis/${server.name}".path
|
||||
else server.value.passwordFile;
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList redis.instances));
|
||||
sops.secrets = builtins.listToAttrs (builtins.map
|
||||
nixos.system.sops.secrets = builtins.listToAttrs (builtins.map
|
||||
(server: { name = "redis/${server.name}"; value.owner = inputs.config.users.users.${server.value.user}.name; })
|
||||
(builtins.filter (server: server.value.passwordFile == null) (inputs.localLib.attrsToList redis.instances)));
|
||||
systemd.services = builtins.listToAttrs (builtins.map
|
||||
|
||||
@@ -15,35 +15,37 @@ inputs:
|
||||
image = "rsshub:latest";
|
||||
imageFile = inputs.topInputs.self.src.rsshub;
|
||||
ports = [ "127.0.0.1:5221:5221/tcp" ];
|
||||
environmentFiles = [ inputs.config.sops.templates."rsshub/env".path ];
|
||||
environmentFiles = [ inputs.config.nixos.system.sops.templates."rsshub/env".path ];
|
||||
};
|
||||
sops =
|
||||
nixos =
|
||||
{
|
||||
templates."rsshub/env".content = let placeholder = inputs.config.sops.placeholder; in
|
||||
''
|
||||
PORT=5221
|
||||
CACHE_TYPE=memory
|
||||
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
|
||||
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
|
||||
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
|
||||
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
|
||||
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
|
||||
TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}'
|
||||
ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}'
|
||||
XDG_CONFIG_HOME='/var/cache/rsshub/chromium'
|
||||
XDG_CACHE_HOME='/var/cache/rsshub/chromium'
|
||||
BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}'
|
||||
'';
|
||||
secrets = (builtins.listToAttrs (builtins.map (secret: { name = "rsshub/${secret}"; value = {}; })
|
||||
[
|
||||
"pixiv-refreshtoken"
|
||||
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
|
||||
"twitter-auth-token"
|
||||
"bilibili-cookie"
|
||||
"zhihu-cookies"
|
||||
]));
|
||||
system.sops =
|
||||
{
|
||||
templates."rsshub/env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
''
|
||||
PORT=5221
|
||||
CACHE_TYPE=memory
|
||||
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
|
||||
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
|
||||
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
|
||||
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
|
||||
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
|
||||
TWITTER_AUTH_TOKEN='${placeholder."rsshub/twitter-auth-token"}'
|
||||
ZHIHU_COOKIES='${placeholder."rsshub/zhihu-cookies"}'
|
||||
XDG_CONFIG_HOME='/var/cache/rsshub/chromium'
|
||||
XDG_CACHE_HOME='/var/cache/rsshub/chromium'
|
||||
BILIBILI_COOKIE_data0='${placeholder."rsshub/bilibili-cookie"}'
|
||||
'';
|
||||
secrets = (builtins.listToAttrs (builtins.map (secret: inputs.lib.nameValuePair "rsshub/${secret}" {})
|
||||
[
|
||||
"pixiv-refreshtoken"
|
||||
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
|
||||
"twitter-auth-token"
|
||||
"bilibili-cookie"
|
||||
"zhihu-cookies"
|
||||
]));
|
||||
};
|
||||
services.nginx.https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221";
|
||||
};
|
||||
nixos.services.nginx =
|
||||
{ enable = true; https.${rsshub.hostname}.location."/".proxy.upstream = "http://127.0.0.1:5221"; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,17 +14,19 @@ inputs:
|
||||
{
|
||||
enable = true;
|
||||
settings.server = { port = 8081; bind_address = "127.0.0.1"; secret_key = "@SEARX_SECRET_KEY@"; };
|
||||
environmentFile = inputs.config.sops.templates."searx.env".path;
|
||||
environmentFile = inputs.config.nixos.system.sops.templates."searx.env".path;
|
||||
};
|
||||
sops =
|
||||
nixos =
|
||||
{
|
||||
templates."searx.env".content = let inherit (inputs.config.sops) placeholder; in
|
||||
''
|
||||
SEARX_SECRET_KEY=${placeholder."searx/secret-key"}
|
||||
'';
|
||||
secrets."searx/secret-key" = {};
|
||||
system.sops =
|
||||
{
|
||||
templates."searx.env".content = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
''
|
||||
SEARX_SECRET_KEY=${placeholder."searx/secret-key"}
|
||||
'';
|
||||
secrets."searx/secret-key" = {};
|
||||
};
|
||||
services.nginx.https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081";
|
||||
};
|
||||
nixos.services.nginx =
|
||||
{ enable = true; https.${searx.hostname}.location."/".proxy.upstream = "http://127.0.0.1:8081"; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,17 +20,13 @@ inputs:
|
||||
createLocally = false;
|
||||
host = "127.0.0.1";
|
||||
port = 9184;
|
||||
passwordFile = inputs.config.sops.secrets."redis/send".path;
|
||||
passwordFile = inputs.config.nixos.system.sops.secrets."redis/send".path;
|
||||
};
|
||||
};
|
||||
systemd.services.send.after = [ "redis-send.service" ];
|
||||
nixos.services =
|
||||
{
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
https.${send.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:1443"; websocket = true; };
|
||||
};
|
||||
nginx.https.${send.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:1443"; websocket = true; };
|
||||
redis.instances.send = { user = "root"; port = 9184; };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -177,7 +177,7 @@ inputs:
|
||||
# ConstrainDevices=yes
|
||||
'';
|
||||
};
|
||||
munge = { enable = true; password = inputs.config.sops.secrets."munge.key".path; };
|
||||
munge = { enable = true; password = inputs.config.nixos.system.sops.secrets."munge.key".path; };
|
||||
};
|
||||
systemd.services.slurmd.environment =
|
||||
let gpus = slurm.node.${inputs.config.nixos.model.hostname}.gpus or null;
|
||||
@@ -186,12 +186,16 @@ inputs:
|
||||
CUDA_PATH = "${inputs.pkgs.cudatoolkit}";
|
||||
LD_LIBRARY_PATH = "${inputs.config.hardware.nvidia.package}/lib";
|
||||
};
|
||||
sops.secrets."munge.key" =
|
||||
nixos.system.sops.secrets."munge.key" =
|
||||
{
|
||||
format = "binary";
|
||||
sopsFile = inputs.localLib.mkConditional (inputs.config.nixos.model.cluster == null)
|
||||
"${builtins.dirOf inputs.config.sops.defaultSopsFile}/munge.key"
|
||||
"${inputs.config.nixos.system.sops.clusterSopsDir}/munge.key";
|
||||
sopsFile =
|
||||
let
|
||||
devicePath = "${inputs.topInputs.self}/devices";
|
||||
inherit (inputs.config.nixos) model;
|
||||
in inputs.localLib.mkConditional (model.cluster == null)
|
||||
"${devicePath}/${model.hostname}/secrets/munge.key"
|
||||
"${devicePath}/${model.cluster.clusterName}/secrets/munge.key";
|
||||
owner = inputs.config.systemd.services.munged.serviceConfig.User;
|
||||
};
|
||||
environment.sessionVariables = { SLURM_UNBUFFEREDIO = "1"; SLURM_CPU_BIND = "v"; };
|
||||
@@ -206,7 +210,7 @@ inputs:
|
||||
{
|
||||
enable = true;
|
||||
dbdHost = "localhost";
|
||||
storagePassFile = inputs.config.sops.secrets."slurm/db".path;
|
||||
storagePassFile = inputs.config.nixos.system.sops.secrets."slurm/db".path;
|
||||
extraConfig =
|
||||
''
|
||||
StorageHost=*
|
||||
@@ -224,24 +228,20 @@ inputs:
|
||||
services.slurmctld = { after = [ "suid-sgid-wrappers.service" ]; serviceConfig.MemorySwapMax = "0"; };
|
||||
tmpfiles.rules = [ "d /var/log/slurmctld 700 slurm slurm" ];
|
||||
};
|
||||
sops =
|
||||
nixos.system.sops =
|
||||
{
|
||||
secrets = { "slurm/db" = { owner = "slurm"; key = "mariadb/slurm"; }; }
|
||||
// builtins.listToAttrs (builtins.map
|
||||
(n:
|
||||
{
|
||||
name = "telegram/${n}";
|
||||
value.sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
|
||||
})
|
||||
(n: inputs.lib.nameValuePair "telegram/${n}" {})
|
||||
[ "token" "user/chn" "user/hjp" ]);
|
||||
templates."info.yaml" =
|
||||
{
|
||||
owner = "slurm";
|
||||
content = let inherit (inputs.config.sops) placeholder; in builtins.toJSON
|
||||
content = let inherit (inputs.config.nixos.system.sops) placeholder; in builtins.toJSON
|
||||
{
|
||||
token = placeholder."telegram/token";
|
||||
user = builtins.listToAttrs (builtins.map (n: { name = n; value = placeholder."telegram/user/${n}"; })
|
||||
[ "chn" "hjp" ]);
|
||||
user = builtins.listToAttrs (builtins.map
|
||||
(n: inputs.lib.nameValuePair n placeholder."telegram/user/${n}") [ "chn" "hjp" ]);
|
||||
slurmConf = "${inputs.config.services.slurm.etcSlurm}/slurm.conf";
|
||||
};
|
||||
};
|
||||
@@ -252,7 +252,7 @@ inputs:
|
||||
let info = inputs.pkgs.localPackages.info.override
|
||||
{
|
||||
slurm = inputs.config.services.slurm.package;
|
||||
configFile = inputs.config.sops.templates."info.yaml".path;
|
||||
configFile = inputs.config.nixos.system.sops.templates."info.yaml".path;
|
||||
};
|
||||
in "${info}/bin/info";
|
||||
program = "slurm-info";
|
||||
|
||||
@@ -43,7 +43,7 @@ inputs:
|
||||
let
|
||||
package = inputs.pkgs.matrix-synapse.override
|
||||
{ extras = [ "url-preview" "postgres" "redis" ]; plugins = []; };
|
||||
config = inputs.config.sops.templates."synapse/${instance.name}/config.yaml".path;
|
||||
config = inputs.config.nixos.system.sops.templates."synapse/${instance.name}/config.yaml".path;
|
||||
homeserver = "${package}/bin/synapse_homeserver";
|
||||
in
|
||||
{
|
||||
@@ -100,125 +100,123 @@ inputs:
|
||||
];
|
||||
})
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
sops = inputs.lib.mkMerge (builtins.map
|
||||
(instance:
|
||||
{
|
||||
templates."synapse/${instance.name}/config.yaml" =
|
||||
{
|
||||
owner = "synapse-${instance.name}";
|
||||
group = "synapse-${instance.name}";
|
||||
content =
|
||||
let
|
||||
inherit (inputs.config.sops) placeholder;
|
||||
in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml"
|
||||
{
|
||||
server_name = instance.value.matrixHostname;
|
||||
public_baseurl = "https://${instance.value.hostname}/";
|
||||
listeners =
|
||||
[{
|
||||
bind_addresses = [ "127.0.0.1" ];
|
||||
inherit (instance.value) port;
|
||||
resources = [{ names = [ "client" "federation" ]; compress = false; }];
|
||||
tls = false;
|
||||
type = "http";
|
||||
x_forwarded = true;
|
||||
}];
|
||||
database =
|
||||
{
|
||||
name = "psycopg2";
|
||||
args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in
|
||||
{
|
||||
user = name;
|
||||
password = placeholder."postgresql/${name}";
|
||||
database = name;
|
||||
host = "127.0.0.1";
|
||||
port = "5432";
|
||||
};
|
||||
allow_unsafe_locale = true;
|
||||
};
|
||||
redis =
|
||||
{
|
||||
enabled = true;
|
||||
port = instance.value.redisPort;
|
||||
password = placeholder."redis/synapse-${instance.name}";
|
||||
};
|
||||
turn_shared_secret = placeholder."synapse/${instance.name}/coturn";
|
||||
registration_shared_secret = placeholder."synapse/${instance.name}/registration";
|
||||
macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon";
|
||||
form_secret = placeholder."synapse/${instance.name}/form";
|
||||
signing_key_path = inputs.config.sops.secrets."synapse/${instance.name}/signing-key".path;
|
||||
email =
|
||||
{
|
||||
smtp_host = "mail.chn.moe";
|
||||
smtp_port = 25;
|
||||
smtp_user = "bot@chn.moe";
|
||||
smtp_pass = placeholder."mail/bot";
|
||||
require_transport_security = true;
|
||||
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
|
||||
app_name = "Haonan Chen's synapse";
|
||||
};
|
||||
admin_contact = "mailto:chn@chn.moe";
|
||||
enable_registration = true;
|
||||
registrations_require_3pid = [ "email" ];
|
||||
registration_requires_token = true;
|
||||
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
|
||||
max_upload_size = "1024M";
|
||||
web_client_location = "https://element.chn.moe/";
|
||||
report_stats = true;
|
||||
trusted_key_servers =
|
||||
[{
|
||||
server_name = "matrix.org";
|
||||
verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
|
||||
}];
|
||||
suppress_key_server_warning = true;
|
||||
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
|
||||
{
|
||||
version = 1;
|
||||
formatters.precise.format =
|
||||
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
|
||||
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
|
||||
root = { level = "INFO"; handlers = [ "console" ]; };
|
||||
disable_existing_loggers = true;
|
||||
};
|
||||
pid_file = "/run/synapse-${instance.name}.pid";
|
||||
media_store_path = "/var/lib/synapse/${instance.name}/media_store";
|
||||
presence.enabled = true;
|
||||
url_preview_enabled = true;
|
||||
url_preview_ip_range_blacklist =
|
||||
[
|
||||
"10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24"
|
||||
"192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32"
|
||||
"203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8"
|
||||
];
|
||||
max_image_pixels = "32M";
|
||||
dynamic_thumbnails = false;
|
||||
# this is required for displaying thumbnails in sticker widgets
|
||||
enable_authenticated_media = false;
|
||||
});
|
||||
};
|
||||
secrets = (builtins.listToAttrs (builtins.map
|
||||
(secret: { name = "synapse/${instance.name}/${secret}"; value = {}; })
|
||||
[ "coturn" "registration" "macaroon" "form" ]))
|
||||
// { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; }
|
||||
// { "mail/bot" = {}; };
|
||||
})
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
nixos.services =
|
||||
nixos =
|
||||
{
|
||||
postgresql.instances = builtins.listToAttrs (builtins.map
|
||||
system.sops = inputs.lib.mkMerge (builtins.map
|
||||
(instance:
|
||||
{
|
||||
name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}";
|
||||
value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; };
|
||||
templates."synapse/${instance.name}/config.yaml" =
|
||||
{
|
||||
owner = "synapse-${instance.name}";
|
||||
content =
|
||||
let
|
||||
inherit (inputs.config.nixos.system.sops) placeholder;
|
||||
in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml"
|
||||
{
|
||||
server_name = instance.value.matrixHostname;
|
||||
public_baseurl = "https://${instance.value.hostname}/";
|
||||
listeners =
|
||||
[{
|
||||
bind_addresses = [ "127.0.0.1" ];
|
||||
inherit (instance.value) port;
|
||||
resources = [{ names = [ "client" "federation" ]; compress = false; }];
|
||||
tls = false;
|
||||
type = "http";
|
||||
x_forwarded = true;
|
||||
}];
|
||||
database =
|
||||
{
|
||||
name = "psycopg2";
|
||||
args = let name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}"; in
|
||||
{
|
||||
user = name;
|
||||
password = placeholder."postgresql/${name}";
|
||||
database = name;
|
||||
host = "127.0.0.1";
|
||||
port = "5432";
|
||||
};
|
||||
allow_unsafe_locale = true;
|
||||
};
|
||||
redis =
|
||||
{
|
||||
enabled = true;
|
||||
port = instance.value.redisPort;
|
||||
password = placeholder."redis/synapse-${instance.name}";
|
||||
};
|
||||
turn_shared_secret = placeholder."synapse/${instance.name}/coturn";
|
||||
registration_shared_secret = placeholder."synapse/${instance.name}/registration";
|
||||
macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon";
|
||||
form_secret = placeholder."synapse/${instance.name}/form";
|
||||
signing_key_path = inputs.config.nixos.system.sops.secrets."synapse/${instance.name}/signing-key".path;
|
||||
email =
|
||||
{
|
||||
smtp_host = "mail.chn.moe";
|
||||
smtp_port = 25;
|
||||
smtp_user = "bot@chn.moe";
|
||||
smtp_pass = placeholder."mail/bot";
|
||||
require_transport_security = true;
|
||||
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
|
||||
app_name = "Haonan Chen's synapse";
|
||||
};
|
||||
admin_contact = "mailto:chn@chn.moe";
|
||||
enable_registration = true;
|
||||
registrations_require_3pid = [ "email" ];
|
||||
registration_requires_token = true;
|
||||
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
|
||||
max_upload_size = "1024M";
|
||||
web_client_location = "https://element.chn.moe/";
|
||||
report_stats = true;
|
||||
trusted_key_servers =
|
||||
[{
|
||||
server_name = "matrix.org";
|
||||
verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
|
||||
}];
|
||||
suppress_key_server_warning = true;
|
||||
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
|
||||
{
|
||||
version = 1;
|
||||
formatters.precise.format =
|
||||
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
|
||||
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
|
||||
root = { level = "INFO"; handlers = [ "console" ]; };
|
||||
disable_existing_loggers = true;
|
||||
};
|
||||
pid_file = "/run/synapse-${instance.name}.pid";
|
||||
media_store_path = "/var/lib/synapse/${instance.name}/media_store";
|
||||
presence.enabled = true;
|
||||
url_preview_enabled = true;
|
||||
url_preview_ip_range_blacklist =
|
||||
[
|
||||
"10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24"
|
||||
"192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32"
|
||||
"203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8"
|
||||
];
|
||||
max_image_pixels = "32M";
|
||||
dynamic_thumbnails = false;
|
||||
# this is required for displaying thumbnails in sticker widgets
|
||||
enable_authenticated_media = false;
|
||||
});
|
||||
};
|
||||
secrets = (builtins.listToAttrs (builtins.map
|
||||
(secret: { name = "synapse/${instance.name}/${secret}"; value = {}; })
|
||||
[ "coturn" "registration" "macaroon" "form" ]))
|
||||
// { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; }
|
||||
// { "mail/bot" = {}; };
|
||||
})
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
redis.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; })
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
nginx =
|
||||
services =
|
||||
{
|
||||
enable = inputs.lib.mkIf (synapse.instances != {}) true;
|
||||
https = builtins.listToAttrs (builtins.map
|
||||
postgresql.instances = builtins.listToAttrs (builtins.map
|
||||
(instance:
|
||||
{
|
||||
name = "synapse_${builtins.replaceStrings [ "-" ] [ "_" ] instance.name}";
|
||||
value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; };
|
||||
})
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
redis.instances = builtins.listToAttrs (builtins.map
|
||||
(instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; })
|
||||
(inputs.localLib.attrsToList synapse.instances));
|
||||
nginx.https = builtins.listToAttrs (builtins.map
|
||||
(instance: with instance.value;
|
||||
{
|
||||
name = hostname;
|
||||
|
||||
@@ -25,32 +25,32 @@ inputs:
|
||||
SMTP_SECURITY = "force_tls";
|
||||
SMTP_USERNAME = "bot@chn.moe";
|
||||
};
|
||||
environmentFile = inputs.config.sops.templates."vaultwarden.env".path;
|
||||
environmentFile = inputs.config.nixos.system.sops.templates."vaultwarden.env".path;
|
||||
};
|
||||
sops =
|
||||
nixos =
|
||||
{
|
||||
templates."vaultwarden.env" = let placeholder = inputs.config.sops.placeholder; in
|
||||
system.sops =
|
||||
{
|
||||
owner = "vaultwarden";
|
||||
group = "vaultwarden";
|
||||
content =
|
||||
''
|
||||
DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden
|
||||
ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"}
|
||||
SMTP_PASSWORD=${placeholder."mail/bot"}
|
||||
'';
|
||||
templates."vaultwarden.env" = let inherit (inputs.config.nixos.system.sops) placeholder; in
|
||||
{
|
||||
owner = "vaultwarden";
|
||||
group = "vaultwarden";
|
||||
content =
|
||||
''
|
||||
DATABASE_URL=postgresql://vaultwarden:${placeholder."postgresql/vaultwarden"}@localhost/vaultwarden
|
||||
ADMIN_TOKEN=${placeholder."vaultwarden/admin_token"}
|
||||
SMTP_PASSWORD=${placeholder."mail/bot"}
|
||||
'';
|
||||
};
|
||||
secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; };
|
||||
};
|
||||
services =
|
||||
{
|
||||
postgresql.instances.vaultwarden = {};
|
||||
nginx.https.${vaultwarden.hostname}.location."/".proxy =
|
||||
{ upstream = "http://127.0.0.1:8000"; websocket = true; };
|
||||
};
|
||||
secrets = { "vaultwarden/admin_token" = {}; "mail/bot" = {}; };
|
||||
};
|
||||
systemd.services.vaultwarden.after = [ "postgresql.service" ];
|
||||
nixos.services =
|
||||
{
|
||||
postgresql.instances.vaultwarden = {};
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
https.${vaultwarden.hostname}.location."/".proxy = { upstream = "http://127.0.0.1:8222"; websocket = true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
19
modules/services/waydroid.nix
Normal file
19
modules/services/waydroid.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.waydroid = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
config = let inherit (inputs.config.nixos.services) waydroid; in inputs.lib.mkIf (waydroid != null)
|
||||
{
|
||||
nixos.packages.packages._packages = [ inputs.pkgs.waydroid-helper ];
|
||||
virtualisation.waydroid.enable = true;
|
||||
};
|
||||
}
|
||||
|
||||
# sudo waydroid shell wm set-fix-to-user-rotation enabled
|
||||
# /var/lib/waydroid/waydroid_base.prop
|
||||
# default:
|
||||
# ro.hardware.gralloc=gbm
|
||||
# ro.hardware.egl=mesa
|
||||
# nvidia:
|
||||
# ro.hardware.gralloc=default
|
||||
# ro.hardware.egl=swiftshader
|
||||
@@ -33,7 +33,7 @@ inputs:
|
||||
{
|
||||
inherit (wg.value) listenPort;
|
||||
ips = [ "${wg.value.ip}/${builtins.toString wg.value.netmask}" ];
|
||||
privateKeyFile = inputs.config.sops.secrets.wireguard.path;
|
||||
privateKeyFile = inputs.config.nixos.system.sops.secrets.wireguard.path;
|
||||
peers = builtins.map
|
||||
(peer:
|
||||
{
|
||||
@@ -45,6 +45,6 @@ inputs:
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList wireguard));
|
||||
sops.secrets.wireguard = {};
|
||||
nixos.system.sops.secrets.wireguard = {};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,540 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xray = let inherit (inputs.lib) mkOption types; in
|
||||
{
|
||||
client = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule (submoduleInputs: { options =
|
||||
{
|
||||
xray =
|
||||
{
|
||||
serverName = mkOption { type = types.nonEmptyStr; default = "xserver2.chn.moe"; };
|
||||
serverAddress = mkOption
|
||||
{
|
||||
type = types.nonEmptyStr;
|
||||
default = inputs.topInputs.self.config.dns."chn.moe".getAddress
|
||||
(inputs.lib.removeSuffix ".chn.moe" submoduleInputs.config.xray.serverName);
|
||||
};
|
||||
};
|
||||
dnsmasq =
|
||||
{
|
||||
extraInterfaces = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
||||
hosts = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
||||
};
|
||||
v2ray-forwarder.noproxyUsers = mkOption { type = types.listOf types.nonEmptyStr; default = [ "gb" "xll" ]; };
|
||||
};}));
|
||||
default = null;
|
||||
};
|
||||
server = mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
serverName = mkOption { type = types.nonEmptyStr; default = "xserver2.chn.moe"; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) xray; in inputs.lib.mkMerge
|
||||
[
|
||||
{
|
||||
assertions =
|
||||
[{
|
||||
assertion = !(xray.client != null && xray.server != null);
|
||||
message = "Currenty xray.client and xray.server could not be simutaniusly enabled.";
|
||||
}];
|
||||
}
|
||||
(
|
||||
inputs.lib.mkIf (xray.client != null)
|
||||
{
|
||||
services =
|
||||
{
|
||||
xray = { enable = true; settingsFile = inputs.config.sops.templates."xray-client.json".path; };
|
||||
dnsmasq =
|
||||
{
|
||||
enable = true;
|
||||
settings =
|
||||
{
|
||||
no-poll = true;
|
||||
log-queries = true;
|
||||
server = [ "127.0.0.1#10853" ];
|
||||
interface = xray.client.dnsmasq.extraInterfaces ++ [ "lo" ];
|
||||
bind-dynamic = true;
|
||||
address = builtins.map (host: "/${host.name}/${host.value}")
|
||||
(inputs.localLib.attrsToList xray.client.dnsmasq.hosts);
|
||||
};
|
||||
};
|
||||
resolved.enable = false;
|
||||
};
|
||||
sops =
|
||||
{
|
||||
templates."xray-client.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
group = inputs.config.users.users.v2ray.group;
|
||||
content = let chinaDns = "223.5.5.5"; foreignDns = "8.8.8.8"; in builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
dns =
|
||||
{
|
||||
servers =
|
||||
# 先尝试匹配域名列表进行查询,若匹配成功则使用前两个 dns 查询。
|
||||
# 若匹配域名列表失败,或者匹配成功但是查询到的 IP 不在期望的 IP 列表中,则回落到使用后两个 dns 依次查询。
|
||||
[
|
||||
{
|
||||
address = chinaDns;
|
||||
domains = [ "geosite:geolocation-cn" ];
|
||||
expectIPs = [ "geoip:cn" ];
|
||||
skipFallback = true;
|
||||
}
|
||||
{
|
||||
address = foreignDns;
|
||||
domains = [ "geosite:geolocation-!cn" ];
|
||||
expectIPs = [ "geoip:!cn" ];
|
||||
skipFallback = true;
|
||||
}
|
||||
{ address = chinaDns; expectIPs = [ "geoip:cn" ]; }
|
||||
{ address = foreignDns; }
|
||||
];
|
||||
disableCache = true;
|
||||
queryStrategy = "UseIPv4";
|
||||
tag = "dns-internal";
|
||||
};
|
||||
inbounds =
|
||||
[
|
||||
{
|
||||
port = 10853;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { address = "8.8.8.8"; network = "tcp,udp"; port = 53; };
|
||||
tag = "dns-in";
|
||||
}
|
||||
{
|
||||
port = 10880;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
||||
tag = "common-in";
|
||||
}
|
||||
{
|
||||
port = 10881;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
tag = "xmu-in";
|
||||
}
|
||||
{
|
||||
port = 10883;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
tag = "proxy-in";
|
||||
}
|
||||
{ port = 10884; protocol = "socks"; settings.udp = true; tag = "proxy-socks-in"; }
|
||||
{ port = 10882; protocol = "socks"; settings.udp = true; tag = "direct-in"; }
|
||||
];
|
||||
outbounds =
|
||||
[
|
||||
{
|
||||
protocol = "vless";
|
||||
settings.vnext =
|
||||
[{
|
||||
address = xray.client.xray.serverAddress;
|
||||
port = 443;
|
||||
users =
|
||||
[{
|
||||
id = inputs.config.sops.placeholder."xray-client/uuid";
|
||||
encryption = "none";
|
||||
flow = "xtls-rprx-vision-udp443";
|
||||
}];
|
||||
}];
|
||||
streamSettings =
|
||||
{
|
||||
network = "raw";
|
||||
security = "reality";
|
||||
realitySettings =
|
||||
{
|
||||
inherit (xray.client.xray) serverName;
|
||||
publicKey = "Nl0eVZoDF9d71_3dVsZGJl3UWR9LCv3B14gu7G6vhjk";
|
||||
fingerprint = "firefox";
|
||||
};
|
||||
};
|
||||
tag = "proxy-vless";
|
||||
}
|
||||
{ protocol = "freedom"; tag = "direct"; }
|
||||
{ protocol = "dns"; tag = "dns-out"; }
|
||||
{
|
||||
protocol = "socks";
|
||||
settings.servers = [{ address = "127.0.0.1"; port = 10069; }];
|
||||
tag = "xmu-out";
|
||||
}
|
||||
{ protocol = "blackhole"; tag = "block"; }
|
||||
];
|
||||
routing =
|
||||
{
|
||||
domainStrategy = "AsIs";
|
||||
rules = builtins.map (rule: rule // { type = "field"; })
|
||||
[
|
||||
{ inboundTag = [ "dns-in" ]; outboundTag = "dns-out"; }
|
||||
{ inboundTag = [ "dns-internal" ]; ip = [ chinaDns ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "dns-internal" ]; ip = [ foreignDns ]; outboundTag = "proxy-vless"; }
|
||||
{ inboundTag = [ "dns-internal" ]; outboundTag = "block"; }
|
||||
{ inboundTag = [ "xmu-in" ]; outboundTag = "xmu-out"; }
|
||||
{ inboundTag = [ "direct-in" ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "proxy-in" "proxy-socks-in" ]; outboundTag = "proxy-vless"; }
|
||||
{ inboundTag = [ "common-in" ]; domain = [ "geosite:geolocation-cn" ]; outboundTag = "direct"; }
|
||||
{
|
||||
inboundTag = [ "common-in" ];
|
||||
domain = [ "geosite:geolocation-!cn" ];
|
||||
outboundTag = "proxy-vless";
|
||||
}
|
||||
{ inboundTag = [ "common-in" ]; ip = [ "geoip:cn" ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "common-in" ]; outboundTag = "proxy-vless"; }
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets."xray-client/uuid" = {};
|
||||
};
|
||||
systemd.services =
|
||||
{
|
||||
xray =
|
||||
{
|
||||
serviceConfig =
|
||||
{
|
||||
DynamicUser = inputs.lib.mkForce false;
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
CPUSchedulingPolicy = "rr";
|
||||
};
|
||||
restartTriggers = [ inputs.config.sops.templates."xray-client.json".file ];
|
||||
};
|
||||
v2ray-forwarder =
|
||||
{
|
||||
description = "v2ray-forwarder Daemon";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = let ip = "${inputs.pkgs.iproute2}/bin/ip"; in
|
||||
{
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = inputs.pkgs.writeShellScript "v2ray-forwarder.start"
|
||||
''
|
||||
${ip} rule add fwmark 1/1 table 100
|
||||
${ip} route add local 0.0.0.0/0 dev lo table 100
|
||||
'';
|
||||
ExecStop = inputs.pkgs.writeShellScript "v2ray-forwarder.stop"
|
||||
''
|
||||
${ip} rule del fwmark 1/1 table 100
|
||||
${ip} route del local 0.0.0.0/0 dev lo table 100
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray = { uid = inputs.config.nixos.user.uid.v2ray; group = "v2ray"; isSystemUser = true; };
|
||||
groups.v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
};
|
||||
environment.etc."resolv.conf".text = "nameserver 127.0.0.1";
|
||||
networking =
|
||||
{
|
||||
nftables.tables.v2ray =
|
||||
{
|
||||
family = "inet";
|
||||
content =
|
||||
let
|
||||
autoPort = "10880";
|
||||
xmuPort = "10881";
|
||||
proxyPort = "10883";
|
||||
loNet =
|
||||
[
|
||||
"0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12"
|
||||
"192.0.0.0/24" "192.88.99.0/24" "192.168.0.0/16" "59.77.0.143" "198.18.0.0/15"
|
||||
"198.51.100.0/24" "203.0.113.0/24" "224.0.0.0/4" "240.0.0.0/4"
|
||||
];
|
||||
loNetStr = builtins.concatStringsSep ", " loNet;
|
||||
noproxyUserStr = builtins.concatStringsSep ", " (builtins.map
|
||||
(user: builtins.toString inputs.config.nixos.user.uid.${user})
|
||||
(xray.client.v2ray-forwarder.noproxyUsers ++ [ "v2ray" ]));
|
||||
in
|
||||
''
|
||||
set lo_net { type ipv4_addr; flags interval; elements = { ${loNetStr} }; }
|
||||
set xmu_net { type ipv4_addr; flags interval; }
|
||||
set noproxy_net { type ipv4_addr; flags interval; elements = { 223.5.5.5 }; }
|
||||
set noproxy_src_net { type ipv4_addr; flags interval; }
|
||||
set proxy_net { type ipv4_addr; flags interval; elements = { 8.8.8.8 }; }
|
||||
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
meta l4proto != { tcp, udp } counter return
|
||||
|
||||
# 对于目标地址为本机的新建的流,标记并永不代理
|
||||
fib daddr type local ct state new counter ct mark set ct mark | 1 return
|
||||
ct mark & 1 == 1 counter return
|
||||
|
||||
ip saddr @noproxy_src_net counter return
|
||||
ip daddr @noproxy_net counter return
|
||||
ip saddr != 172.16.0.0/12 ip daddr @xmu_net meta l4proto { tcp, udp } counter \
|
||||
tproxy ip to :${xmuPort} meta mark set meta mark | 1 return
|
||||
ip daddr @proxy_net meta l4proto { tcp, udp } counter tproxy ip to :${proxyPort} \
|
||||
meta mark set meta mark | 1 return
|
||||
ip daddr @lo_net counter return
|
||||
meta l4proto { tcp, udp } counter tproxy ip to :${autoPort} meta mark set meta mark | 1 return
|
||||
return
|
||||
}
|
||||
|
||||
chain output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
ct mark & 1 == 1 counter return
|
||||
meta skuid { ${noproxyUserStr} } counter return
|
||||
|
||||
ip saddr @noproxy_src_net counter return
|
||||
ip daddr @noproxy_net counter return
|
||||
ip daddr @xmu_net counter meta mark set meta mark | 1 return
|
||||
ip daddr @proxy_net counter meta mark set meta mark | 1 return
|
||||
ip daddr @lo_net counter return
|
||||
meta l4proto { tcp, udp } counter meta mark set meta mark | 1 return
|
||||
return
|
||||
}
|
||||
'';
|
||||
};
|
||||
firewall =
|
||||
{
|
||||
allowedTCPPorts = [ 53 ];
|
||||
allowedUDPPorts = [ 53 ];
|
||||
allowedTCPPortRanges = [{ from = 10880; to = 10884; }];
|
||||
allowedUDPPortRanges = [{ from = 10880; to = 10884; }];
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
(
|
||||
inputs.lib.mkIf (xray.server != null)
|
||||
(
|
||||
let userList = builtins.attrNames
|
||||
(inputs.pkgs.localPackages.fromYaml (builtins.readFile inputs.config.sops.defaultSopsFile))
|
||||
.xray-server.clients;
|
||||
in
|
||||
{
|
||||
services.xray = { enable = true; settingsFile = inputs.config.sops.templates."xray-server.json".path; };
|
||||
sops =
|
||||
{
|
||||
templates."xray-server.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
group = inputs.config.users.users.v2ray.group;
|
||||
content = builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
inbounds =
|
||||
[
|
||||
(
|
||||
let fallbackPort = builtins.toString
|
||||
(with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2);
|
||||
in
|
||||
{
|
||||
port = 4726;
|
||||
listen = "127.0.0.1";
|
||||
protocol = "vless";
|
||||
settings =
|
||||
{
|
||||
clients = builtins.map
|
||||
(n:
|
||||
{
|
||||
id = inputs.config.sops.placeholder."xray-server/clients/${n}";
|
||||
flow = "xtls-rprx-vision";
|
||||
email = "${n}@xray.chn.moe";
|
||||
})
|
||||
userList;
|
||||
decryption = "none";
|
||||
fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }];
|
||||
};
|
||||
streamSettings =
|
||||
{
|
||||
network = "raw";
|
||||
security = "reality";
|
||||
realitySettings =
|
||||
{
|
||||
dest = "127.0.0.1:${fallbackPort}";
|
||||
serverNames = [ xray.server.serverName ];
|
||||
privateKey = inputs.config.sops.placeholder."xray-server/private-key";
|
||||
minClientVer = "1.8.0";
|
||||
shortIds = [ "" ];
|
||||
};
|
||||
};
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
||||
tag = "in-legacy";
|
||||
}
|
||||
)
|
||||
{
|
||||
port = 4638;
|
||||
listen = "127.0.0.1";
|
||||
protocol = "vless";
|
||||
settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; };
|
||||
streamSettings.network = "raw";
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; };
|
||||
tag = "in-localdns";
|
||||
}
|
||||
{
|
||||
listen = "127.0.0.1";
|
||||
port = 6149;
|
||||
protocol = "dokodemo-door";
|
||||
settings.address = "127.0.0.1";
|
||||
tag = "api";
|
||||
}
|
||||
];
|
||||
outbounds =
|
||||
[
|
||||
{ protocol = "freedom"; tag = "freedom"; }
|
||||
{
|
||||
protocol = "vless";
|
||||
settings.vnext =
|
||||
[{
|
||||
address = "127.0.0.1";
|
||||
port = 4638;
|
||||
users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }];
|
||||
}];
|
||||
streamSettings.network = "raw";
|
||||
tag = "loopback-localdns";
|
||||
}
|
||||
];
|
||||
routing =
|
||||
{
|
||||
domainStrategy = "AsIs";
|
||||
rules = builtins.map (rule: rule // { type = "field"; })
|
||||
[
|
||||
{
|
||||
inboundTag = [ "in-legacy" ];
|
||||
domain = [ "domain:openai.com" ];
|
||||
outboundTag = "loopback-localdns";
|
||||
}
|
||||
{ inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; }
|
||||
{ inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; }
|
||||
{ inboundTag = [ "api" ]; outboundTag = "api"; }
|
||||
];
|
||||
};
|
||||
stats = {};
|
||||
api = { tag = "api"; services = [ "StatsService" ]; };
|
||||
policy =
|
||||
{
|
||||
levels."0" = { statsUserUplink = true; statsUserDownlink = true; };
|
||||
system =
|
||||
{
|
||||
statsInboundUplink = true;
|
||||
statsInboundDownlink = true;
|
||||
statsOutboundUplink = true;
|
||||
statsOutboundDownlink = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets = builtins.listToAttrs
|
||||
(builtins.map (n: { name = "xray-server/clients/${n}"; value = {}; }) userList)
|
||||
// (builtins.listToAttrs (builtins.map
|
||||
(name:
|
||||
{
|
||||
name = "telegram/${name}";
|
||||
value =
|
||||
{
|
||||
group = "telegram";
|
||||
mode = "0440";
|
||||
sopsFile = "${inputs.config.nixos.system.sops.crossSopsDir}/default.yaml";
|
||||
};
|
||||
})
|
||||
[ "token" "user/chn" ]))
|
||||
// { "xray-server/private-key" = {}; };
|
||||
};
|
||||
systemd =
|
||||
{
|
||||
services =
|
||||
{
|
||||
xray =
|
||||
{
|
||||
serviceConfig =
|
||||
{
|
||||
DynamicUser = inputs.lib.mkForce false;
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
};
|
||||
restartTriggers = [ inputs.config.sops.templates."xray-server.json".file ];
|
||||
};
|
||||
xray-stat =
|
||||
{
|
||||
script =
|
||||
let
|
||||
xray = "${inputs.pkgs.xray}/bin/xray";
|
||||
awk = "${inputs.pkgs.gawk}/bin/awk";
|
||||
curl = "${inputs.pkgs.curl}/bin/curl";
|
||||
jq = "${inputs.pkgs.jq}/bin/jq";
|
||||
sed = "${inputs.pkgs.gnused}/bin/sed";
|
||||
cat = "${inputs.pkgs.coreutils}/bin/cat";
|
||||
token = inputs.config.sops.secrets."telegram/token".path;
|
||||
chat = inputs.config.sops.secrets."telegram/user/chn".path;
|
||||
in
|
||||
''
|
||||
message='${inputs.config.nixos.model.hostname} xray:\n'
|
||||
for i in ${builtins.concatStringsSep " " userList}
|
||||
do
|
||||
upload_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
||||
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>uplink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
||||
[ -z "$upload_bytes" ] && upload_bytes=0
|
||||
download_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
||||
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>downlink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
||||
[ -z "$download_bytes" ] && download_bytes=0
|
||||
traffic_gb=$(echo | ${awk} "{printf \"%.3f\",(''${upload_bytes}+''${download_bytes})/1073741824}")
|
||||
message="$message$i"'\t'"''${traffic_gb}"'G\n'
|
||||
done
|
||||
${curl} -X POST -H 'Content-Type: application/json' \
|
||||
-d "{\"chat_id\": \"$(${cat} ${chat})\", \"text\": \"$message\"}" \
|
||||
https://api.telegram.org/bot$(${cat} ${token})/sendMessage
|
||||
'';
|
||||
serviceConfig = { Type = "oneshot"; User = "v2ray"; Group = "v2ray"; };
|
||||
};
|
||||
};
|
||||
timers.xray-stat =
|
||||
{
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = { OnCalendar = "*-*-* 0:00:00"; Unit = "xray-stat.service"; };
|
||||
};
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray =
|
||||
{
|
||||
uid = inputs.config.nixos.user.uid.v2ray;
|
||||
group = "v2ray";
|
||||
extraGroups = [ "telegram" ];
|
||||
isSystemUser = true;
|
||||
};
|
||||
groups =
|
||||
{
|
||||
v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
telegram.gid = inputs.config.nixos.user.gid.telegram;
|
||||
};
|
||||
};
|
||||
nixos.services =
|
||||
{
|
||||
acme.cert.${xray.server.serverName}.group = inputs.config.users.users.nginx.group;
|
||||
nginx =
|
||||
{
|
||||
enable = true;
|
||||
transparentProxy.map.${xray.server.serverName} = 4726;
|
||||
https.${xray.server.serverName} =
|
||||
{
|
||||
listen.main = { proxyProtocol = false; addToTransparentProxy = false; };
|
||||
location."/".return.return = "400";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
))
|
||||
];
|
||||
}
|
||||
296
modules/services/xray/client.nix
Normal file
296
modules/services/xray/client.nix
Normal file
@@ -0,0 +1,296 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xray.client = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule (submoduleInputs: { options =
|
||||
{
|
||||
xray =
|
||||
{
|
||||
serverName = mkOption { type = types.nonEmptyStr; default = "xserver2.chn.moe"; };
|
||||
serverAddress = mkOption
|
||||
{
|
||||
type = types.nonEmptyStr;
|
||||
default = inputs.topInputs.self.config.dns."chn.moe".getAddress
|
||||
(inputs.lib.removeSuffix ".chn.moe" submoduleInputs.config.xray.serverName);
|
||||
};
|
||||
};
|
||||
dnsmasq =
|
||||
{
|
||||
extraInterfaces = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
||||
hosts = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
||||
};
|
||||
v2ray-forwarder.noproxyUsers = mkOption { type = types.listOf types.nonEmptyStr; default = [ "gb" "xll" ]; };
|
||||
};}));
|
||||
default = null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services.xray) client; in inputs.lib.mkIf (client != null)
|
||||
{
|
||||
services =
|
||||
{
|
||||
dnsmasq =
|
||||
{
|
||||
enable = true;
|
||||
settings =
|
||||
{
|
||||
no-poll = true;
|
||||
log-queries = true;
|
||||
server = [ "127.0.0.1#10853" ];
|
||||
interface = client.dnsmasq.extraInterfaces ++ [ "lo" ];
|
||||
bind-dynamic = true;
|
||||
address = builtins.map (host: "/${host.name}/${host.value}")
|
||||
(inputs.localLib.attrsToList client.dnsmasq.hosts);
|
||||
};
|
||||
};
|
||||
resolved.enable = false;
|
||||
};
|
||||
nixos.system.sops =
|
||||
{
|
||||
templates."xray-client.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
group = inputs.config.users.users.v2ray.group;
|
||||
content = let chinaDns = "223.5.5.5"; foreignDns = "8.8.8.8"; in builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
dns =
|
||||
{
|
||||
servers =
|
||||
# 先尝试匹配域名列表进行查询,若匹配成功则使用前两个 dns 查询。
|
||||
# 若匹配域名列表失败,或者匹配成功但是查询到的 IP 不在期望的 IP 列表中,则回落到使用后两个 dns 依次查询。
|
||||
[
|
||||
{
|
||||
address = chinaDns;
|
||||
domains = [ "geosite:geolocation-cn" ];
|
||||
expectIPs = [ "geoip:cn" ];
|
||||
skipFallback = true;
|
||||
}
|
||||
{
|
||||
address = foreignDns;
|
||||
domains = [ "geosite:geolocation-!cn" ];
|
||||
expectIPs = [ "geoip:!cn" ];
|
||||
skipFallback = true;
|
||||
}
|
||||
{ address = chinaDns; expectIPs = [ "geoip:cn" ]; }
|
||||
{ address = foreignDns; }
|
||||
];
|
||||
disableCache = true;
|
||||
queryStrategy = "UseIPv4";
|
||||
tag = "dns-internal";
|
||||
};
|
||||
inbounds =
|
||||
[
|
||||
{
|
||||
port = 10853;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { address = "8.8.8.8"; network = "tcp,udp"; port = 53; };
|
||||
tag = "dns-in";
|
||||
}
|
||||
{
|
||||
port = 10880;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
||||
tag = "common-in";
|
||||
}
|
||||
{
|
||||
port = 10881;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
tag = "xmu-in";
|
||||
}
|
||||
{
|
||||
port = 10883;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
tag = "proxy-in";
|
||||
}
|
||||
{ port = 10884; protocol = "socks"; settings.udp = true; tag = "proxy-socks-in"; }
|
||||
{ port = 10882; protocol = "socks"; settings.udp = true; tag = "direct-in"; }
|
||||
];
|
||||
outbounds =
|
||||
[
|
||||
{
|
||||
protocol = "vless";
|
||||
settings.vnext =
|
||||
[{
|
||||
address = client.xray.serverAddress;
|
||||
port = 443;
|
||||
users =
|
||||
[{
|
||||
id = inputs.config.nixos.system.sops.placeholder."xray-client/uuid";
|
||||
encryption = "none";
|
||||
flow = "xtls-rprx-vision-udp443";
|
||||
}];
|
||||
}];
|
||||
streamSettings =
|
||||
{
|
||||
network = "raw";
|
||||
security = "reality";
|
||||
realitySettings =
|
||||
{
|
||||
inherit (client.xray) serverName;
|
||||
publicKey = "Nl0eVZoDF9d71_3dVsZGJl3UWR9LCv3B14gu7G6vhjk";
|
||||
fingerprint = "firefox";
|
||||
};
|
||||
};
|
||||
tag = "proxy-vless";
|
||||
}
|
||||
{ protocol = "freedom"; tag = "direct"; }
|
||||
{ protocol = "dns"; tag = "dns-out"; }
|
||||
{
|
||||
protocol = "socks";
|
||||
settings.servers = [{ address = "127.0.0.1"; port = 10069; }];
|
||||
tag = "xmu-out";
|
||||
}
|
||||
{ protocol = "blackhole"; tag = "block"; }
|
||||
];
|
||||
routing =
|
||||
{
|
||||
domainStrategy = "AsIs";
|
||||
rules = builtins.map (rule: rule // { type = "field"; })
|
||||
[
|
||||
{ inboundTag = [ "dns-in" ]; outboundTag = "dns-out"; }
|
||||
{ inboundTag = [ "dns-internal" ]; ip = [ chinaDns ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "dns-internal" ]; ip = [ foreignDns ]; outboundTag = "proxy-vless"; }
|
||||
{ inboundTag = [ "dns-internal" ]; outboundTag = "block"; }
|
||||
{ inboundTag = [ "xmu-in" ]; outboundTag = "xmu-out"; }
|
||||
{ inboundTag = [ "direct-in" ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "proxy-in" "proxy-socks-in" ]; outboundTag = "proxy-vless"; }
|
||||
{ inboundTag = [ "common-in" ]; domain = [ "geosite:geolocation-cn" ]; outboundTag = "direct"; }
|
||||
{
|
||||
inboundTag = [ "common-in" ];
|
||||
domain = [ "geosite:geolocation-!cn" ];
|
||||
outboundTag = "proxy-vless";
|
||||
}
|
||||
{ inboundTag = [ "common-in" ]; ip = [ "geoip:cn" ]; outboundTag = "direct"; }
|
||||
{ inboundTag = [ "common-in" ]; outboundTag = "proxy-vless"; }
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets."xray-client/uuid" = {};
|
||||
};
|
||||
systemd.services =
|
||||
{
|
||||
xray-client =
|
||||
{
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let config = inputs.config.nixos.system.sops.templates."xray-client.json".path; in
|
||||
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
|
||||
serviceConfig =
|
||||
{
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
NoNewPrivileges = true;
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
CPUSchedulingPolicy = "rr";
|
||||
};
|
||||
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-client.json".file ];
|
||||
};
|
||||
v2ray-forwarder =
|
||||
{
|
||||
description = "v2ray-forwarder Daemon";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = let ip = "${inputs.pkgs.iproute2}/bin/ip"; in
|
||||
{
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = inputs.pkgs.writeShellScript "v2ray-forwarder.start"
|
||||
''
|
||||
${ip} rule add fwmark 1/1 table 100
|
||||
${ip} route add local 0.0.0.0/0 dev lo table 100
|
||||
'';
|
||||
ExecStop = inputs.pkgs.writeShellScript "v2ray-forwarder.stop"
|
||||
''
|
||||
${ip} rule del fwmark 1/1 table 100
|
||||
${ip} route del local 0.0.0.0/0 dev lo table 100
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray = { uid = inputs.config.nixos.user.uid.v2ray; group = "v2ray"; isSystemUser = true; };
|
||||
groups.v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
};
|
||||
environment.etc."resolv.conf".text = "nameserver 127.0.0.1";
|
||||
networking =
|
||||
{
|
||||
nftables.tables.v2ray =
|
||||
{
|
||||
family = "inet";
|
||||
content =
|
||||
let
|
||||
autoPort = "10880";
|
||||
xmuPort = "10881";
|
||||
proxyPort = "10883";
|
||||
loNet =
|
||||
[
|
||||
"0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12"
|
||||
"192.0.0.0/24" "192.88.99.0/24" "192.168.0.0/16" "59.77.0.143" "198.18.0.0/15"
|
||||
"198.51.100.0/24" "203.0.113.0/24" "224.0.0.0/4" "240.0.0.0/4"
|
||||
];
|
||||
loNetStr = builtins.concatStringsSep ", " loNet;
|
||||
noproxyUserStr = builtins.concatStringsSep ", " (builtins.map
|
||||
(user: builtins.toString inputs.config.nixos.user.uid.${user})
|
||||
(client.v2ray-forwarder.noproxyUsers ++ [ "v2ray" ]));
|
||||
in
|
||||
''
|
||||
set lo_net { type ipv4_addr; flags interval; elements = { ${loNetStr} }; }
|
||||
set xmu_net { type ipv4_addr; flags interval; }
|
||||
set noproxy_net { type ipv4_addr; flags interval; elements = { 223.5.5.5 }; }
|
||||
set noproxy_src_net { type ipv4_addr; flags interval; }
|
||||
set proxy_net { type ipv4_addr; flags interval; elements = { 8.8.8.8 }; }
|
||||
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
meta l4proto != { tcp, udp } counter return
|
||||
|
||||
# 对于目标地址为本机的新建的流,标记并永不代理
|
||||
fib daddr type local ct state new counter ct mark set ct mark | 1 return
|
||||
ct mark & 1 == 1 counter return
|
||||
|
||||
ip saddr @noproxy_src_net counter return
|
||||
ip daddr @noproxy_net counter return
|
||||
ip saddr != 172.16.0.0/12 ip daddr @xmu_net meta l4proto { tcp, udp } counter \
|
||||
tproxy ip to :${xmuPort} meta mark set meta mark | 1 return
|
||||
ip daddr @proxy_net meta l4proto { tcp, udp } counter tproxy ip to :${proxyPort} \
|
||||
meta mark set meta mark | 1 return
|
||||
ip daddr @lo_net counter return
|
||||
meta l4proto { tcp, udp } counter tproxy ip to :${autoPort} meta mark set meta mark | 1 return
|
||||
return
|
||||
}
|
||||
|
||||
chain output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
ct mark & 1 == 1 counter return
|
||||
meta skuid { ${noproxyUserStr} } counter return
|
||||
|
||||
ip saddr @noproxy_src_net counter return
|
||||
ip daddr @noproxy_net counter return
|
||||
ip daddr @xmu_net counter meta mark set meta mark | 1 return
|
||||
ip daddr @proxy_net counter meta mark set meta mark | 1 return
|
||||
ip daddr @lo_net counter return
|
||||
meta l4proto { tcp, udp } counter meta mark set meta mark | 1 return
|
||||
return
|
||||
}
|
||||
'';
|
||||
};
|
||||
firewall =
|
||||
{
|
||||
allowedTCPPorts = [ 53 ];
|
||||
allowedUDPPorts = [ 53 ];
|
||||
allowedTCPPortRanges = [{ from = 10880; to = 10884; }];
|
||||
allowedUDPPortRanges = [{ from = 10880; to = 10884; }];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
5
modules/services/xray/default.nix
Normal file
5
modules/services/xray/default.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
# sync with nixpkgs 5835771b10e3197408d3ac7d32558c8e2ae0ab8d
|
||||
inputs:
|
||||
{
|
||||
imports = inputs.localLib.findModules ./.;
|
||||
}
|
||||
229
modules/services/xray/server.nix
Normal file
229
modules/services/xray/server.nix
Normal file
@@ -0,0 +1,229 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xray.server = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
serverName = mkOption { type = types.nonEmptyStr; default = "xserver2.chn.moe"; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services.xray) server; in inputs.lib.mkIf (server != null)
|
||||
(
|
||||
let userList = builtins.map (user: builtins.elemAt user 2) (builtins.filter
|
||||
(user: builtins.elem user == 3 && inputs.lib.lists.hasPrefix [ "xray-server" "clients" ])
|
||||
inputs.config.nixos.system.sops.availableKeys);
|
||||
in
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
system.sops =
|
||||
{
|
||||
templates."xray-server.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
group = inputs.config.users.users.v2ray.group;
|
||||
content = builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
inbounds =
|
||||
[
|
||||
(
|
||||
let fallbackPort = builtins.toString
|
||||
(with inputs.config.nixos.services.nginx.global; httpsPort + httpsPortShift.http2);
|
||||
in
|
||||
{
|
||||
port = 4726;
|
||||
listen = "127.0.0.1";
|
||||
protocol = "vless";
|
||||
settings =
|
||||
{
|
||||
clients = builtins.map
|
||||
(n:
|
||||
{
|
||||
id = inputs.config.nixos.system.sops.placeholder."xray-server/clients/${n}";
|
||||
flow = "xtls-rprx-vision";
|
||||
email = "${n}@xray.chn.moe";
|
||||
})
|
||||
userList;
|
||||
decryption = "none";
|
||||
fallbacks = [{ dest = "127.0.0.1:${fallbackPort}"; }];
|
||||
};
|
||||
streamSettings =
|
||||
{
|
||||
network = "raw";
|
||||
security = "reality";
|
||||
realitySettings =
|
||||
{
|
||||
dest = "127.0.0.1:${fallbackPort}";
|
||||
serverNames = [ server.serverName ];
|
||||
privateKey = inputs.config.nixos.system.sops.placeholder."xray-server/private-key";
|
||||
minClientVer = "1.8.0";
|
||||
shortIds = [ "" ];
|
||||
};
|
||||
};
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
||||
tag = "in-legacy";
|
||||
}
|
||||
)
|
||||
{
|
||||
port = 4638;
|
||||
listen = "127.0.0.1";
|
||||
protocol = "vless";
|
||||
settings = { clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }]; decryption = "none"; };
|
||||
streamSettings.network = "raw";
|
||||
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; };
|
||||
tag = "in-localdns";
|
||||
}
|
||||
{
|
||||
listen = "127.0.0.1";
|
||||
port = 6149;
|
||||
protocol = "dokodemo-door";
|
||||
settings.address = "127.0.0.1";
|
||||
tag = "api";
|
||||
}
|
||||
];
|
||||
outbounds =
|
||||
[
|
||||
{ protocol = "freedom"; tag = "freedom"; }
|
||||
{
|
||||
protocol = "vless";
|
||||
settings.vnext =
|
||||
[{
|
||||
address = "127.0.0.1";
|
||||
port = 4638;
|
||||
users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }];
|
||||
}];
|
||||
streamSettings.network = "raw";
|
||||
tag = "loopback-localdns";
|
||||
}
|
||||
];
|
||||
routing =
|
||||
{
|
||||
domainStrategy = "AsIs";
|
||||
rules = builtins.map (rule: rule // { type = "field"; })
|
||||
[
|
||||
{
|
||||
inboundTag = [ "in-legacy" ];
|
||||
domain = [ "domain:openai.com" ];
|
||||
outboundTag = "loopback-localdns";
|
||||
}
|
||||
{ inboundTag = [ "in-legacy" ]; outboundTag = "freedom"; }
|
||||
{ inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; }
|
||||
{ inboundTag = [ "api" ]; outboundTag = "api"; }
|
||||
];
|
||||
};
|
||||
stats = {};
|
||||
api = { tag = "api"; services = [ "StatsService" ]; };
|
||||
policy =
|
||||
{
|
||||
levels."0" = { statsUserUplink = true; statsUserDownlink = true; };
|
||||
system =
|
||||
{
|
||||
statsInboundUplink = true;
|
||||
statsInboundDownlink = true;
|
||||
statsOutboundUplink = true;
|
||||
statsOutboundDownlink = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets = builtins.listToAttrs
|
||||
(builtins.map (n: inputs.lib.nameValuePair "xray-server/clients/${n}" {}) userList)
|
||||
// (builtins.listToAttrs (builtins.map
|
||||
(name: inputs.lib.nameValuePair "telegram/${name}" { group = "telegram"; mode = "0440"; })
|
||||
[ "token" "user/chn" ]))
|
||||
// { "xray-server/private-key" = {}; };
|
||||
};
|
||||
services =
|
||||
{
|
||||
acme.cert.${server.serverName}.group = inputs.config.users.users.nginx.group;
|
||||
nginx =
|
||||
{
|
||||
transparentProxy.map.${server.serverName} = 4726;
|
||||
https.${server.serverName} =
|
||||
{
|
||||
listen.main = { proxyProtocol = false; addToTransparentProxy = false; };
|
||||
location."/".return.return = "400";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
systemd =
|
||||
{
|
||||
services =
|
||||
{
|
||||
xray-server =
|
||||
{
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let config = inputs.config.nixos.system.sops.templates."xray-server.json".path; in
|
||||
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
|
||||
serviceConfig =
|
||||
{
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
};
|
||||
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-server.json".file ];
|
||||
};
|
||||
xray-stat =
|
||||
{
|
||||
script =
|
||||
let
|
||||
xray = "${inputs.pkgs.xray}/bin/xray";
|
||||
awk = "${inputs.pkgs.gawk}/bin/awk";
|
||||
curl = "${inputs.pkgs.curl}/bin/curl";
|
||||
jq = "${inputs.pkgs.jq}/bin/jq";
|
||||
sed = "${inputs.pkgs.gnused}/bin/sed";
|
||||
cat = "${inputs.pkgs.coreutils}/bin/cat";
|
||||
token = inputs.config.nixos.system.sops.secrets."telegram/token".path;
|
||||
chat = inputs.config.nixos.system.sops.secrets."telegram/user/chn".path;
|
||||
in
|
||||
''
|
||||
message='${inputs.config.nixos.model.hostname} xray:\n'
|
||||
for i in ${builtins.concatStringsSep " " userList}
|
||||
do
|
||||
upload_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
||||
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>uplink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
||||
[ -z "$upload_bytes" ] && upload_bytes=0
|
||||
download_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
||||
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>downlink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
||||
[ -z "$download_bytes" ] && download_bytes=0
|
||||
traffic_gb=$(echo | ${awk} "{printf \"%.3f\",(''${upload_bytes}+''${download_bytes})/1073741824}")
|
||||
message="$message$i"'\t'"''${traffic_gb}"'G\n'
|
||||
done
|
||||
${curl} -X POST -H 'Content-Type: application/json' \
|
||||
-d "{\"chat_id\": \"$(${cat} ${chat})\", \"text\": \"$message\"}" \
|
||||
https://api.telegram.org/bot$(${cat} ${token})/sendMessage
|
||||
'';
|
||||
serviceConfig = { Type = "oneshot"; User = "v2ray"; Group = "v2ray"; };
|
||||
};
|
||||
};
|
||||
timers.xray-stat =
|
||||
{
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = { OnCalendar = "*-*-* 0:00:00"; Unit = "xray-stat.service"; };
|
||||
};
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray =
|
||||
{
|
||||
uid = inputs.config.nixos.user.uid.v2ray;
|
||||
group = "v2ray";
|
||||
extraGroups = [ "telegram" ];
|
||||
isSystemUser = true;
|
||||
};
|
||||
groups =
|
||||
{
|
||||
v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
telegram.gid = inputs.config.nixos.user.gid.telegram;
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
104
modules/services/xray/xmuClient.nix
Normal file
104
modules/services/xray/xmuClient.nix
Normal file
@@ -0,0 +1,104 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xray.xmuClient = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule (submoduleInputs: { options =
|
||||
{
|
||||
hostname = mkOption { type = types.nonEmptyStr; default = "xserverxmu.chn.moe"; };
|
||||
};}));
|
||||
default = null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services.xray) xmuClient; in inputs.lib.mkIf (xmuClient != null)
|
||||
{
|
||||
nixos.system.sops =
|
||||
{
|
||||
templates."xray-xmu-client.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
group = inputs.config.users.users.v2ray.group;
|
||||
content = builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
inbounds =
|
||||
[
|
||||
{
|
||||
port = 10983;
|
||||
protocol = "dokodemo-door";
|
||||
settings = { network = "tcp,udp"; followRedirect = true; };
|
||||
streamSettings.sockopt.tproxy = "tproxy";
|
||||
tag = "tproxy-in";
|
||||
}
|
||||
{ port = 10984; protocol = "socks"; settings.udp = true; tag = "socks-in"; }
|
||||
];
|
||||
outbounds =
|
||||
[{
|
||||
protocol = "vless";
|
||||
settings.vnext =
|
||||
[{
|
||||
address = "webvpn.xmu.edu.cn";
|
||||
port = 443;
|
||||
users =
|
||||
[{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/uuid"; encryption = "none"; }];
|
||||
}];
|
||||
streamSettings =
|
||||
{
|
||||
network = "xhttp";
|
||||
security = "tls";
|
||||
xhttpSettings =
|
||||
{
|
||||
path =
|
||||
let
|
||||
inherit (xmuClient) hostname;
|
||||
paddedLength = ((builtins.div ((builtins.stringLength hostname) - 1) 16) + 1) * 16;
|
||||
paddedString = builtins.concatStringsSep ""
|
||||
(builtins.genList
|
||||
(n: if n < builtins.stringLength hostname then builtins.substring n 1 hostname else "0")
|
||||
paddedLength);
|
||||
paddedHex = inputs.pkgs.localPackages.aes128CfbHex
|
||||
{ data = hostname; key = "wrdvpnisthebest!"; iv = "wrdvpnisthebest!"; };
|
||||
prefix = builtins.concatStringsSep "" (builtins.map
|
||||
(c: inputs.lib.toHexString (inputs.lib.strings.charToInt c))
|
||||
(inputs.lib.stringToCharacters "wrdvpnisthebest!"));
|
||||
in "/https/${prefix}${paddedHex}/xsession";
|
||||
mode = "packet-up";
|
||||
security = "tls";
|
||||
extra.headers.Cookie =
|
||||
let ticket = inputs.config.nixos.system.sops.placeholder."xray-xmu-client/cookie";
|
||||
in "show_vpn=0; heartbeat=1; show_faq=0; wengine_vpn_ticketwebvpn_xmu_edu_cn=${ticket}";
|
||||
};
|
||||
tlsSettings.alpn = [ "http/1.1" ];
|
||||
};
|
||||
}];
|
||||
};
|
||||
};
|
||||
secrets = { "xray-xmu-client/uuid" = {}; "xray-xmu-client/cookie" = {}; };
|
||||
};
|
||||
systemd.services =
|
||||
{
|
||||
xray-xmu-client =
|
||||
{
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-client.json".path; in
|
||||
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
|
||||
serviceConfig =
|
||||
{
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
NoNewPrivileges = true;
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
CPUSchedulingPolicy = "rr";
|
||||
};
|
||||
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-client.json".file ];
|
||||
};
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray = { uid = inputs.config.nixos.user.uid.v2ray; group = "v2ray"; isSystemUser = true; };
|
||||
groups.v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
};
|
||||
};
|
||||
}
|
||||
65
modules/services/xray/xmuServer.nix
Normal file
65
modules/services/xray/xmuServer.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xray.xmuServer = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{
|
||||
type = types.nullOr (types.submodule { options =
|
||||
{
|
||||
hostname = mkOption { type = types.nonEmptyStr; default = "xserverxmu.chn.moe"; };
|
||||
};});
|
||||
default = null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services.xray) xmuServer; in inputs.lib.mkIf (xmuServer != null)
|
||||
{
|
||||
nixos.system.sops =
|
||||
{
|
||||
templates."xray-xmu-server.json" =
|
||||
{
|
||||
owner = inputs.config.users.users.v2ray.name;
|
||||
content = builtins.toJSON
|
||||
{
|
||||
log.loglevel = "warning";
|
||||
inbounds =
|
||||
[{
|
||||
port = 4727;
|
||||
listen = "127.0.0.1";
|
||||
protocol = "vless";
|
||||
settings =
|
||||
{
|
||||
clients = [{ id = inputs.config.nixos.system.sops.placeholder."xray-xmu-server"; }];
|
||||
decryption = "none";
|
||||
};
|
||||
streamSettings = { network = "xhttp"; xhttpSettings = { mode = "stream-one"; path = "/xsession"; }; };
|
||||
tag = "in";
|
||||
}];
|
||||
outbounds = [{ protocol = "freedom"; tag = "freedom"; }];
|
||||
};
|
||||
};
|
||||
secrets."xray-xmu-server" = {};
|
||||
};
|
||||
systemd.services.xray-xmu-server =
|
||||
{
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = let config = inputs.config.nixos.system.sops.templates."xray-xmu-server.json".path; in
|
||||
"exec ${inputs.pkgs.xray}/bin/xray -config ${config}";
|
||||
serviceConfig =
|
||||
{
|
||||
User = "v2ray";
|
||||
Group = "v2ray";
|
||||
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
||||
NoNewPrivileges = true;
|
||||
LimitNPROC = 65536;
|
||||
LimitNOFILE = 524288;
|
||||
};
|
||||
restartTriggers = [ inputs.config.nixos.system.sops.templates."xray-xmu-server.json".file ];
|
||||
};
|
||||
users =
|
||||
{
|
||||
users.v2ray = { uid = inputs.config.nixos.user.uid.v2ray; group = "v2ray"; isSystemUser = true; };
|
||||
groups.v2ray.gid = inputs.config.nixos.user.gid.v2ray;
|
||||
};
|
||||
nixos.services.nginx.https.${xmuServer.hostname}.location =
|
||||
{ "/".return.return = "400"; "/xsession".proxy = { upstream = "127.0.0.1:4727"; grpc = true; }; };
|
||||
};
|
||||
}
|
||||
36
modules/services/xrdp.nix
Normal file
36
modules/services/xrdp.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.services.xrdp = let inherit (inputs.lib) mkOption types; in
|
||||
{
|
||||
enable = mkOption { type = types.bool; default = false; };
|
||||
port = mkOption { type = types.ints.unsigned; default = 3389; };
|
||||
hostname = mkOption { type = types.nullOr (types.nonEmptyListOf types.nonEmptyStr); default = null; };
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.services) xrdp;
|
||||
in inputs.lib.mkIf xrdp.enable (inputs.lib.mkMerge
|
||||
[
|
||||
{
|
||||
services.xrdp =
|
||||
{
|
||||
enable = true;
|
||||
port = xrdp.port;
|
||||
openFirewall = true;
|
||||
defaultWindowManager = "${inputs.pkgs.kdePackages.plasma-workspace}/bin/startplasma-x11";
|
||||
};
|
||||
}
|
||||
(
|
||||
inputs.lib.mkIf (xrdp.hostname != null)
|
||||
(
|
||||
let mainDomain = builtins.elemAt xrdp.hostname 0;
|
||||
in
|
||||
{
|
||||
services.xrdp =
|
||||
let keydir = inputs.config.security.acme.certs.${mainDomain}.directory;
|
||||
in { sslCert = "${keydir}/full.pem"; sslKey = "${keydir}/key.pem"; };
|
||||
nixos.services.acme.cert.${mainDomain} =
|
||||
{ domains = xrdp.hostname; group = inputs.config.systemd.services.xrdp.serviceConfig.Group; };
|
||||
}
|
||||
)
|
||||
)
|
||||
]);
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
inputs:
|
||||
{
|
||||
options.nixos.system.binfmt = let inherit (inputs.lib) mkOption types; in mkOption
|
||||
{ type = types.nullOr (types.submodule {}); default = null; };
|
||||
{
|
||||
type = types.nullOr (types.submodule {});
|
||||
default = if builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ] then {} else null;
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.system) binfmt; in inputs.lib.mkIf (binfmt != null)
|
||||
{
|
||||
programs.java = { enable = true; binfmt = true; };
|
||||
|
||||
@@ -26,14 +26,20 @@ inputs:
|
||||
XDG_CONFIG_HOME = "$HOME/.config";
|
||||
XDG_DATA_HOME = "$HOME/.local/share";
|
||||
XDG_STATE_HOME = "$HOME/.local/state";
|
||||
# do not set ANDROID_HOME, since some adb tools does not respect it
|
||||
# ANDROID_HOME = "${XDG_DATA_HOME}/android";
|
||||
HISTFILE= "${XDG_STATE_HOME}/bash/history";
|
||||
# do not export HISTFILE
|
||||
# when HISTFILE is export but HISTSIZE is set but not export, in sub shell,
|
||||
# HISTFILE will persist but HISTSIZE will not, make history file be overwritten
|
||||
# HISTFILE= "${XDG_STATE_HOME}/bash/history";
|
||||
CUDA_CACHE_PATH = "${XDG_CACHE_HOME}/nv";
|
||||
GNUPGHOME = "${XDG_DATA_HOME}/gnupg";
|
||||
GTK2_RC_FILES = "${XDG_CONFIG_HOME}/gtk-2.0/gtkrc";
|
||||
XCOMPOSECACHE = "${XDG_CACHE_HOME}/X11/xcompose";
|
||||
MATHEMATICA_USERBASE = "${XDG_CONFIG_HOME}/mathematica";
|
||||
_JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java";
|
||||
# it is safe to always enable this, only effective when using wayland
|
||||
NIXOS_OZONE_WL = "1";
|
||||
};
|
||||
variables =
|
||||
{
|
||||
|
||||
@@ -53,12 +53,18 @@ inputs:
|
||||
{
|
||||
device = device.name;
|
||||
fsType = "btrfs";
|
||||
# zstd:15 cause sound stuttering
|
||||
# test on e20dae7d8b317f95718b5f4175bd4246c09735de mathematica ~15G
|
||||
# zstd:15 5m33s 7.16G
|
||||
# zstd:8 54s 7.32G
|
||||
# zstd:3 17s 7.52G
|
||||
options = [ "compress-force=zstd" "subvol=${subvol.name}" "acl" "noatime" ];
|
||||
options =
|
||||
[
|
||||
"subvol=${subvol.name}" "acl" "noatime"
|
||||
# zstd:15 cause sound stuttering
|
||||
# test on e20dae7d8b317f95718b5f4175bd4246c09735de mathematica ~15G
|
||||
# zstd:15 5m33s 7.16G
|
||||
# zstd:8 54s 7.32G
|
||||
# zstd:3 17s 7.52G
|
||||
"compress-force=zstd"
|
||||
# large btrfs volume need more time to mount (default 90s might not be enough)
|
||||
"x-systemd.mount-timeout=300s"
|
||||
];
|
||||
neededForBoot = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ inputs:
|
||||
"/nix/rootfs/current" =
|
||||
{
|
||||
hideMounts = true;
|
||||
directories = builtins.map (f: "/var/lib/systemd/${f}") [ "linger" "coredump" "backlight" ];
|
||||
directories = [ "/var/lib/flatpak" ]
|
||||
++ builtins.map (f: "/var/lib/systemd/${f}") [ "linger" "coredump" "backlight" ];
|
||||
};
|
||||
"/nix/nodatacow" =
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
inputs:
|
||||
{
|
||||
config = inputs.lib.mkIf (inputs.config.nixos.model.type == "desktop")
|
||||
config = inputs.lib.mkIf (builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ])
|
||||
{
|
||||
fonts =
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ inputs:
|
||||
config = let inherit (inputs.config.nixos.system) gui; in inputs.lib.mkMerge
|
||||
[
|
||||
# enable gui
|
||||
(inputs.lib.mkIf (inputs.config.nixos.model.type == "desktop")
|
||||
(inputs.lib.mkIf (builtins.elem inputs.config.nixos.model.type [ "desktop" "server" ])
|
||||
{
|
||||
services =
|
||||
{
|
||||
@@ -57,11 +57,10 @@ inputs:
|
||||
})];
|
||||
})
|
||||
# prefer gui or not
|
||||
(inputs.localLib.mkConditional (builtins.elem inputs.config.nixos.model.type [ "desktop" ])
|
||||
{ environment.sessionVariables.NIXOS_OZONE_WL = "1"; }
|
||||
{
|
||||
environment.plasma6.excludePackages = inputs.lib.mkIf (gui.implementation == "kde")
|
||||
[ inputs.pkgs.kdePackages.plasma-nm ];
|
||||
})
|
||||
(inputs.lib.mkIf (inputs.config.nixos.model.type == "server")
|
||||
{
|
||||
environment.plasma6.excludePackages = inputs.lib.mkIf (gui.implementation == "kde")
|
||||
[ inputs.pkgs.kdePackages.plasma-nm ];
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ inputs:
|
||||
default = "xanmod-lts";
|
||||
};
|
||||
patches = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
||||
modules.modprobeConfig = mkOption { type = types.listOf types.str; default = []; };
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.system) kernel; in
|
||||
{
|
||||
@@ -37,13 +36,14 @@ inputs:
|
||||
# network for srv3
|
||||
"igb"
|
||||
# touchscreen for one
|
||||
"pinctrl-tigerlake"
|
||||
"pinctrl-tigerlake" "i2c-hid-acpi"
|
||||
# bridge network
|
||||
"bridge"
|
||||
]
|
||||
++ (inputs.lib.optionals (kernel.variant != "nixos") [ "crypto_simd" ]);
|
||||
extraModulePackages = with inputs.config.boot.kernelPackages; [ v4l2loopback zenpower ];
|
||||
extraModprobeConfig = builtins.concatStringsSep "\n" kernel.modules.modprobeConfig;
|
||||
# force i2c-hid-acpi to load after pinctrl-tigerlake
|
||||
extraModprobeConfig = "softdep i2c-hid-acpi pre: pinctrl-tigerlake";
|
||||
kernelParams = [ "delayacct" ];
|
||||
kernelPackages = inputs.lib.mkIf (kernel.variant != null)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user