Compare commits

...

172 Commits

Author SHA1 Message Date
Inex Code ce3231774e chore: update nixpkgs 2024-05-02 22:34:36 +03:00
Inex Code f8223192e5 fix: Add DeSEC to dnsPropagationCheckExceptions
Probably a temp fix to #59
2024-05-02 22:31:30 +03:00
Alexander 4c183d5b40 fix deSEC: DESEC_POLLING_INTERVAL=30, propagation timeout and TTL 2024-03-12 19:58:37 +04:00
Inex Code 5e005dc436 chore: update API 3.1.0 2024-03-07 23:52:30 +03:00
Inex Code 6619760f47 Revert "try fix"
This reverts commit 3b4466b49d.
2024-02-23 20:46:24 +03:00
Inex Code 3b4466b49d try fix 2024-02-23 20:45:38 +03:00
Inex Code 5d9c385d08 Revert "chore: update API 3.0.1"
This reverts commit 3a7876aeb4.
2024-02-23 20:40:26 +03:00
Inex Code 3a7876aeb4 chore: update API 3.0.1 2024-02-23 20:22:35 +03:00
Inex Code c7583bf501 Merge pull request 'modules: parameterize all subdomains' (#54) from subdomains into flakes
Reviewed-on: #54
2024-02-20 17:51:47 +02:00
Alexander ad43d31c0c modules: parameterize all subdomains 2024-02-20 14:42:37 +04:00
Inex Code 2159c4cc6e Merge pull request 'Bitwarden: Fix webauthn login' (#55) from fix-bitwarden into flakes
Reviewed-on: #55
2024-02-19 14:29:27 +02:00
Inex Code 3d6f47e0e7 chore: update nixpkgs 2024-02-19 15:23:38 +03:00
Inex Code f103f708da fix(bitwarden): Webauthn login didn't work 2024-02-19 15:23:25 +03:00
Alexander Tomokhov 2d4e7e89a1 configure NixOS to allow configuration without password nor ssh key 2024-01-23 16:37:35 +04:00
Alexander d389b6785f Merge branch 'flakes-test' into flakes 2024-01-19 09:59:09 +04:00
Inex Code a8aca42762 feat(ssh): Allow ecdsa-sha2-nistp256 keys 2024-01-19 03:01:20 +04:00
Alexander f9b86f403d default timezone is "Etc/UTC" 2024-01-19 02:59:29 +04:00
Alexander 643f7716ae remove DOMAIN environment variable 2024-01-19 02:48:27 +04:00
Alexander c96e6fe099 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=refs/heads/master&rev=0ccb85d5cc24a20ecc8647035c93bc08e3e31b78' (2024-01-10)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=refs/heads/master&rev=e3761a200c1ce244b285772a0c731a10e6169ef3' (2024-01-15)
2024-01-18 15:18:32 +04:00
Alexander 842d5a0dd1 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=remove-rest-flaked&rev=fb5a8142da48436cd7a30f267d156d50f47829f6' (2024-01-09)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=refs/heads/master&rev=0ccb85d5cc24a20ecc8647035c93bc08e3e31b78' (2024-01-10)
2024-01-11 00:13:44 +04:00
Alexander 3311c5ff50 readme: small additions 2024-01-11 00:03:01 +04:00
Alexander 6b66513870 readme: how to update inputs of this flake 2024-01-10 07:13:17 +04:00
Alexander c08d56ae1c flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/1e2e384c5b7c50dbf8e9c441a9e58d85f408b01f' (2023-12-17)
  → 'github:nixos/nixpkgs/c1be43e8e837b8dbee2b3665a007e761680f0c3d' (2024-01-05)
2024-01-10 06:57:58 +04:00
Alexander e8842e455b Merge branch 'flakes' into flakes-test 2024-01-10 03:35:26 +04:00
Alexander 1a677f273b fix nextcloud auth page redirection 2024-01-10 01:49:51 +04:00
Inex Code 94456c8bd8 upd 2024-01-09 22:33:24 +03:00
Inex Code 3e0eae6d7d Test SP API 3.0.0 2024-01-09 22:04:53 +03:00
Inex Code c0af154421 Update SP API version 2023-12-31 19:22:33 +03:00
Inex Code f287e68f2b fix setuptools version 2023-12-28 22:26:53 +03:00
Inex Code f1e789c7af Update SP API version 2023-12-28 22:25:16 +03:00
Alexander 3d8de64da0 selfprivacy-api git branch: userdata => flakes 2023-12-28 20:52:51 +04:00
Alexander 1e73c88547 uppercase config.selfprivacy.server.provider 2023-12-28 20:05:33 +04:00
Alexander 51f3f12640 system.autoUpgrade: no verbosity of nixos-rebuild 2023-12-28 13:28:46 +04:00
Alexander 013bd9b8e2 sp-nixos: split script into ExecStartPre && ExecStart 2023-12-28 13:20:49 +04:00
Alexander 15f5d6096d sp-modules: refactor options types 2023-12-28 13:19:47 +04:00
Alexander a32613ece4 nixos-upgrade.serviceConfig.ExecCondition on /etc/nixos changes 2023-12-28 13:19:47 +04:00
Alexander 0c895e4015 module: set to false: restartIfChanged and unitConfig.X-StopOnRemoval 2023-12-28 11:07:18 +04:00
Alexander 08aa0b9ffc systemd.services.nixos-upgrade.serviceConfig.WorkingDirectory 2023-12-28 10:57:45 +04:00
Alexander be45d3ed52 systemd.services.nixos-upgrade.serviceConfig.ExecStartPre 2023-12-28 10:42:58 +04:00
Alexander efc703bf0c system services lock path:./sp-modules without flake.lock; cd /etc/nixos 2023-12-28 04:38:24 +04:00
Alexander cc78c2915f remove channel option value from syustem.autoUpgrade 2023-12-28 02:07:46 +04:00
Alexander fe44ba6fd8 fix nextcloud: fail if secrets are missing 2023-12-27 15:05:23 +04:00
Alexander 77619456d7 /etc/nixos#sp-nixos => /etc/nixos#default 2023-12-27 14:02:27 +04:00
Alexander f94d0aef03 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=400be88738fd6c8d18bcc439a81ee208b49bc749' (2023-12-22)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=7883063dca4d946c0955faafd78642224d4a9be8' (2023-12-27)
2023-12-27 13:37:55 +04:00
Alexander 23332cda46 add TODO about environment.variables.DOMAIN 2023-12-27 12:54:10 +04:00
Alexander 85f85239a3 do not set nix.package 2023-12-27 11:37:59 +04:00
Alexander 33ba5c41ac API systemd service Type is simple 2023-12-22 23:52:03 +04:00
Alexander 5bd15a768a system.stateVersion: default or config.selfprivacy.stateVersion 2023-12-22 23:04:03 +04:00
Alexander a185dd1e3e selfprivacy-api: add debug for nixos-rebuild 2023-12-22 21:18:05 +04:00
Alexander e6496b95a4 useACMEHost for all services 2023-12-22 21:18:05 +04:00
Alexander 5aba990f95 move system.stateVersion back to userdata 2023-12-22 19:33:24 +04:00
Alexander 05fe40ac21 fix ACME for DigitalOcean: add DNS propagation check exceptions 2023-12-22 19:08:53 +04:00
Alexander 19f30daf80 sp-modules: x-systemd.before=... for all mountpoints 2023-12-22 18:07:14 +04:00
Alexander 5f8cc727e0 ACME: CLOUDFLARE_POLLING_INTERVAL=30
As said in https://github.com/go-acme/lego/issues/2068.
2023-12-22 14:06:55 +04:00
Alexander 64fc2ae57e mailserver: localDnsResolver = false 2023-12-21 15:13:21 +04:00
Alexander 66c0184a93 ACME: dnsPropagationCheck = true 2023-12-21 13:38:28 +04:00
Alexander 4c3072ade8 ACME: CLOUDFLARE_POLLING_INTERVAL=10 2023-12-21 13:08:34 +04:00
Alexander 0e62c9292b dnsPropagationCheck = false explicitly for certs.${domain} 2023-12-21 12:15:28 +04:00
Alexander 5760a753af ACME dnsPropagationCheck = false 2023-12-20 18:29:39 +04:00
Alexander f2a951a71e API module: systemd service Type = "oneshot" 2023-12-20 18:21:51 +04:00
Alexander fd6e49a21a ACME: do not disable DNS propagation check 2023-12-20 17:43:47 +04:00
Alexander dcaf96c773 Revert "Revert "Revert "add wildcard ACME certificate"""
This reverts commit 4faf8e7dda.
2023-12-20 17:43:47 +04:00
Alexander 3a66da49e1 do not `lib.mkForce` acme.certs 2023-12-20 17:43:47 +04:00
Alexander 5cd12848cc `nix.channel.enable = false` since we're on flakes 2023-12-20 17:43:46 +04:00
Alexander 4faf8e7dda Revert "Revert "add wildcard ACME certificate""
This reverts commit 0c4d57c33d.
2023-12-20 16:59:57 +04:00
Alexander c18f332f5f Revert "use enableACME for all virtualHosts"
This reverts commit 46366702bc.
2023-12-19 23:46:42 +04:00
Alexander 46366702bc use enableACME for all virtualHosts 2023-12-19 17:22:32 +04:00
Alexander 0c4d57c33d Revert "add wildcard ACME certificate"
This reverts commit b37cadff68
(except pleroma virtualHosts).
2023-12-19 17:22:32 +04:00
Alexander 426e6f72c5 gitea: bind mount /var/lib/gitea 2023-12-19 17:22:32 +04:00
Alexander eb59d33e1f nginx: / location with root = "/var/www/root" 2023-12-19 17:22:31 +04:00
Alexander b37cadff68 add wildcard ACME certificate 2023-12-19 01:52:27 +04:00
Inex Code 312077240a fix(acme): add dns propagation check exceptions 2023-12-19 01:19:03 +04:00
Alexander 69f84cdc2b bitwarden: "ConditionPathExists" instead of "after" 2023-12-19 01:19:03 +04:00
Alexander 0ad2ffc30e api module: avoid simultaneous runs 2023-12-19 00:20:18 +04:00
Alexander 83a17063ac explicit dependency between backup-vaultwarden and vaultwarden 2023-12-18 23:40:15 +04:00
Alexander 257b0c08e8 sp-modules: some startup fixes 2023-12-18 22:42:13 +04:00
Alexander da5dac6877 sp-nixos-upgrade: update sp-modules/ own flake.lock 2023-12-18 22:30:24 +04:00
Alexander 3d7aa5e6de fix selfprivacy-api build with new nixpkgs 2023-12-18 21:44:32 +04:00
Alexander 365f027326 move nginx exclusive virtualHosts to SP modules 2023-12-18 19:02:54 +04:00
Alexander d881cc8ce5 upgrade nixpkgs to NixOS 23.11 2023-12-18 18:44:18 +04:00
Alexander b7045a8198 upgrade nixpkgs to NixOS 23.05 2023-12-18 17:56:15 +04:00
Alexander 67c2b12c44 sp-modules: get rid of systemd.tmpfiles
Because it causes troubles when using bind-mounts for /var/lib/*.
2023-12-18 16:30:40 +04:00
Alexander 83e8f6e8a1 get rid of files.nix; ACME/credentialsFile and other cleanup 2023-12-18 07:49:27 +04:00
Alexander 7f6c48f978 gitea: RequiresMountsFor and ConditionPathIsMountPoint @ /var/lib/gitea 2023-12-12 20:50:09 +04:00
Alexander a797b856fc flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=dc230e2e898a510bfdc52e57d829996df02f26b5' (2023-12-12)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=2bdb73d348d1a8b85a71aa480ab1c08fafb2c9ba' (2023-12-12)
2023-12-12 16:30:22 +04:00
Alexander d1711ea9c3 selfprivacy-api: sp-nixos-rebuild with sp-modules relocking 2023-12-12 14:15:06 +04:00
Alexander defaca8793 clean configuration; simple-nixos-mailserver is an ordinary SP module 2023-12-12 08:25:10 +04:00
Alexander 25bd151ef3 use lower case for config.selfprivacy.server.provider 2023-12-11 21:58:12 +04:00
Alexander 519ebbcb69 get rid of system argument; do not set nixpkgs.hostPlatform 2023-12-05 07:36:26 +04:00
Alexander 4c4aef5363 get system.stateVersion from "deployment" argument 2023-12-05 04:51:37 +04:00
Alexander 9dde55159b update selfprivacy-api 2023-12-05 01:56:49 +04:00
Alexander 6cd002ae1d remove restic SP module 2023-12-05 01:56:13 +04:00
Alexander c052f9172a move gitea to SP module 2023-12-04 15:59:22 +04:00
Alexander 054d6d9182 move jitsi-meet to SP module 2023-12-04 15:50:00 +04:00
Alexander 3f573e3dc3 activationScripts: rewrite /etc/nixos with configuration source 2023-12-04 15:25:01 +04:00
Alexander c63b6b808c acme: RestartSec = 15 * 60 2023-12-04 14:33:43 +04:00
Alexander Tomokhov c0aa73ca1b move bitwarden to SP module 2023-12-04 14:33:43 +04:00
Alexander Tomokhov ade4dc08b1 sp-modules: use jq exit status code 2023-12-03 10:37:37 +04:00
Alexander Tomokhov 4716b9bf19 move restic to SP module 2023-12-03 10:05:51 +04:00
Alexander Tomokhov c7419b3255 move pleroma to SP module 2023-12-03 09:46:36 +04:00
Alexander Tomokhov b458458c30 move ocserv to SP module 2023-12-03 09:46:36 +04:00
Alexander Tomokhov 4cbe63ac64 flake: abort on missing configPathsNeeded with message 2023-12-01 08:32:31 +04:00
Alexander Tomokhov 600d8f427d mailserver: set users.groups.acmereceivers.members 2023-11-29 08:28:19 +04:00
Alexander Tomokhov b6cd5846f2 users.groups: acmerecievers => acmereceivers 2023-11-29 08:25:24 +04:00
Alexander Tomokhov 1a5a4be306 nextcloud: fix secrets extraction 2023-11-29 08:19:04 +04:00
Alexander Tomokhov 364a5c8076 mailserver: adapt to deprecated and new types of certificateScheme 2023-11-26 09:39:47 +04:00
Alexander Tomokhov a224731dcf nextcloud: write passwords using `install` 2023-11-26 09:39:47 +04:00
Alexander Tomokhov e814157437 fix config attributes contrain for function imports 2023-11-26 08:56:48 +04:00
Alexander Tomokhov 0db1c4a6ce downgrade simple-nixos-mailserver to 6d0d9fb9 2023-11-26 04:28:36 +04:00
Alexander Tomokhov a98dafc98c fix nextcloud (case when enabled)
Previously, second mkIf for cleanup case took precedence when merge with
`//`. Now it's 2 modules: one for selfprivacy.modules.nextcloud.enable
== true, another for selfprivacy.modules.nextcloud.enable == false.
2023-11-26 03:11:29 +04:00
Alexander Tomokhov 3138260605 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=8791462f87c4a134f5ccb7099a814892c110d43b' (2023-11-23)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=75f4e8d40eff59debcd5eb96e64e2e7c3db75e7f' (2023-11-23)
2023-11-23 21:33:35 +04:00
Alexander Tomokhov 1bf7190388 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=8ccec537401b51583d89f59790953ad32534563a' (2023-11-23)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=8791462f87c4a134f5ccb7099a814892c110d43b' (2023-11-23)
2023-11-23 21:20:35 +04:00
Alexander Tomokhov cc26a5e150 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=9c18ab285cd2221a50950c796456929019f5fb2a' (2023-11-22)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=8ccec537401b51583d89f59790953ad32534563a' (2023-11-23)
2023-11-23 11:36:20 +04:00
Alexander Tomokhov 6ebcc35882 systemd.enableEmergencyMode = false; systemd.coredump.enable = false; 2023-11-23 11:09:49 +04:00
Alexander Tomokhov 985aff90d3 disable ssh passwordAuthentication by default 2023-11-23 11:08:59 +04:00
Alexander Tomokhov bd6b8a5e75 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=2bbc2be6b57f05a159db1f175e8fa84d67eac8da' (2023-11-22)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=9c18ab285cd2221a50950c796456929019f5fb2a' (2023-11-22)
2023-11-23 03:00:25 +04:00
Alexander Tomokhov 6d96b4aa8f flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=aa4e5a9251b440c161b79590fef7d2707cdce9b4' (2023-11-22)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=2bbc2be6b57f05a159db1f175e8fa84d67eac8da' (2023-11-22)
2023-11-22 23:09:42 +04:00
Alexander Tomokhov 8067559207 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=22f9d2e9df2db29493003d436c6b75fe58b5c5f0' (2023-11-21)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=aa4e5a9251b440c161b79590fef7d2707cdce9b4' (2023-11-22)
2023-11-22 22:17:00 +04:00
Alexander Tomokhov 252ed72154 remove autoUpgrade from userdata-variables.nix 2023-11-22 06:45:23 +04:00
Alexander Tomokhov e53eb8d65d flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=e1847e1ce8327d8d36e80b84cd55d7b38baaa40c' (2023-11-20)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=22f9d2e9df2db29493003d436c6b75fe58b5c5f0' (2023-11-21)
2023-11-22 01:58:44 +04:00
Alexander Tomokhov e59d86fcdc flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=nixos-module&rev=e28aa8d60d824133fc3e170d2ed144bf0ec342a3' (2023-11-18)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=userdata&rev=e1847e1ce8327d8d36e80b84cd55d7b38baaa40c' (2023-11-20)
2023-11-21 03:49:45 +04:00
Alexander Tomokhov 7c5bc70fec rm -rf /old-root on every boot
NixOS stage 1 init moves all remnants of previous OS to /old-root.
2023-11-21 03:01:28 +04:00
Alexander Tomokhov 308a70fe20 selfprivacy/current-config-source => selfprivacy/nixos-config-source 2023-11-21 01:24:36 +04:00
Alexander Tomokhov a3063ec732 fileSystems./.options = [ noatime ]; 2023-11-21 01:23:28 +04:00
Alexander Tomokhov e45224d67f fix resources/limits.txt but do not use them for now 2023-11-18 19:26:52 +04:00
Alexander Tomokhov 391e41e8a4 disable documentation.enable = false alltogether 2023-11-18 18:54:55 +04:00
Alexander Tomokhov 0704d18b1a do not install {man,info}-pages and docs to save space 2023-11-18 17:39:14 +04:00
Alexander Tomokhov 6a3a83e270 files.nix: /etc/nixos/userdata.json => /etc/selfprivacy/secrets.json 2023-11-18 09:11:54 +04:00
Alexander Tomokhov b64be4e34f /etc/nixos/userdata/userdata.json => /etc/nixos/userdata.json 2023-11-18 08:54:29 +04:00
Alexander Tomokhov 65e58666fd nixpkgs.hostPlatform = system 2023-11-18 08:28:04 +04:00
Alexander Tomokhov 43abd2ca45 flake.lock: Update
Flake lock file updates:

• Updated input 'selfprivacy-api':
    'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=nixos-module&rev=e6e9d0677e51e5b1f2f5ee60809d190ab18a9f3e' (2023-11-16)
  → 'git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=nixos-module&rev=e28aa8d60d824133fc3e170d2ed144bf0ec342a3' (2023-11-18)
2023-11-18 06:39:10 +04:00
Alexander Tomokhov e6e2f1fd84 configuration.nix: a few nix.* tweaks 2023-11-18 06:37:45 +04:00
Alexander Tomokhov 72d73b6297 autoUpgrade.enable = false by default 2023-11-18 05:40:57 +04:00
Alexander Tomokhov 0f54898cb8 sp-modules: fix nextcloud secrets json path 2023-11-18 05:40:02 +04:00
Alexander Tomokhov d5b04699c1 sp-module: refactor simple-nixos-mailserver flake 2023-11-16 06:36:39 +04:00
Alexander Tomokhov d69a8cd662 migrate selfprivacy-api NixOS module to selfprivacy API repository
But do not treat it as a SP module.
2023-11-16 06:36:39 +04:00
Alexander Tomokhov 80447abb2e selfprivacy.userdata -> selfprivacy; SP modules -> selfprivacy.modules 2023-11-16 04:00:15 +04:00
Alexander Tomokhov f4fb0a9ce8 move nextcloud nginx configuration part to SP module 2023-11-15 23:43:59 +04:00
Alexander Tomokhov 41c3a0fc00 add PoC SP module for nextcloud 2023-11-15 22:36:19 +04:00
Alexander Tomokhov d281f51775 TODO notes: flake: config contrain algorithm 2023-11-15 20:18:49 +04:00
Alexander Tomokhov b0bb84138b delete garbage sp-modules-options.json file 2023-11-15 20:12:33 +04:00
Alexander Tomokhov 4419a1323a fix config attributes contrain mechanism for SP modules
Now it should work for all nested imports too. `imports` are traversed
recursively to redefine each imported module function with altered one,
constraining its config attribute (respecting config-paths-needed.json).
2023-11-15 04:31:20 +04:00
Alexander Tomokhov 26b3071929 system.configurationRevision = self.rev or "@${self.lastModifiedDate}" 2023-11-14 06:22:39 +04:00
Alexander Tomokhov f33fb9e9bf just-nixos => sp-nixos; selfprivacy/current-config-source; add formatter 2023-11-14 02:47:08 +04:00
Alexander Tomokhov e656719ebd remove userdata folder 2023-11-13 19:53:15 +04:00
Alexander Tomokhov f440006806 remove erroneous system attribute from nixosConfigurations 2023-11-13 19:52:34 +04:00
Alexander Tomokhov 80ba7d0bda PoC working SP module system
+ simple-nixos-mailserver as an SP module
2023-11-13 00:37:50 +04:00
Alexander Tomokhov d9e2311f3c system.configurationRevision = self.rev; 2023-11-12 01:39:52 +04:00
Alexander Tomokhov 6c849e2628 embed top-level flake source folder into the build 2023-11-10 07:05:38 +04:00
Alexander Tomokhov 7378329891 pass top-level-flake to set system.configurationRevision 2023-11-10 06:53:21 +04:00
Alexander Tomokhov b4b37f42f2 get rid of overlay for selfprivacy-graphql-api 2023-11-06 13:04:03 +04:00
Alexander Tomokhov 7cee132d8e nixosConfiguration-fun takes a set as an argument
This set must contain:
- hardware-configuration
- userdata (parsed)
2023-11-06 12:50:46 +04:00
Alexander Tomokhov 4afa777e7c Revert "add hardware-configuration.nix for testing purposes"
This reverts commit 659ca147fd.
2023-11-06 11:24:38 +04:00
Alexander Tomokhov 57412e328d .gitignore: /result 2023-11-06 11:11:34 +04:00
Alexander Tomokhov a822f97699 pin dependencies in flake 2023-07-17 05:05:29 +04:00
Alexander Tomokhov 82dd9ad2d4 now it's a function, requiring userdata argument 2023-07-17 04:37:04 +04:00
Alexander Tomokhov d4af9f4459 attempt to readFile userdsata.json 2023-07-17 04:19:57 +04:00
Alexander Tomokhov ee2a895c61 test 2023-07-17 04:15:03 +04:00
Alexander Tomokhov 659ca147fd add hardware-configuration.nix for testing purposes 2023-07-15 16:52:30 +04:00
Inex Code 65b5a19777 Merge pull request 'fix: Reloading nginx after ACME' (#34) from nginx-reload-fix into master
Reviewed-on: #34
2023-06-14 19:19:56 +03:00
Inex Code 60dd766846 fix: Reloading nginx after ACME 2023-06-14 19:19:49 +03:00
Inex Code 8006f83257 Merge pull request 'refactor(jitsi): Use the common TLS cert for Jitsi' (#33) from jitsi-tls-fix into master
Reviewed-on: #33
2023-06-09 16:01:09 +03:00
Inex Code 74d35b16f2 fix(jitsi): disable gettings tls certs 2023-06-09 15:59:15 +03:00
Inex Code dd020c3a7d fix(acme): Disable DNS propagation check 2023-06-09 15:57:19 +03:00
Inex Code ba1695c642 fix(jitsi): Use the common TLS cert 2023-06-09 14:06:22 +03:00
Inex Code bc5778fdea feat(dns): Add support for DigitalOcean DNS and DeSEC DNS (#31)
Co-authored-by: inexcode <inex.code@selfprivacy.org>
Co-authored-by: NaiJi  <naiji@udongein.xyz>
Reviewed-on: #31
2023-06-05 15:45:07 +03:00
Inex Code 8d99d1c78a fix: Make bitwarden read the env file 2023-05-14 17:22:09 +03:00
Inex Code 5e64b08381 feat(bitwarden): Add admin token support 2023-05-03 10:48:57 +03:00
Inex Code 7e590ae60c revert(gitea): Nix deprecations x2 2023-03-20 18:39:41 +03:00
Inex Code eb36e9b265 revert(gitea): Nix deprecations 2023-03-20 18:36:32 +03:00
Inex Code 3626506e3a fix: Conflicting Gitea log level 2023-03-20 18:31:39 +03:00
Inex Code c8c69957b5 Merge pull request 'nixos-22.11' (#25) from nixos-22.11 into master
Reviewed-on: #25
2023-03-20 17:23:02 +02:00
55 changed files with 1311 additions and 1266 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
userdata/userdata.json
userdata/tokens.json
hardware-configuration.nix
networking.nix
networking.nix
/result

125
README.md
View File

@ -1,67 +1,70 @@
# SelfPrivacy NixOS configuration
This is a NixOS config which builds a SelfPrivacy server distribution
based on data provided in `userdata/userdata.json`.
This configuration is not self-contained, as it needs to be plugged as an input of a top-level NixOS configuration flake (i.e. https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-template/). This flake outputs the following function:
```nix
nixosConfigurations-fun =
{ hardware-configuration # hardware-configuration.nix file
, deployment # deployment.nix file
, userdata # nix attrset, obtained by fromJSON from userdata.json
, top-level-flake # `self`-reference of the top-level flake
, sp-modules # flake inputs of sp-modules flake
}:
```
which returns one or more attributes, containing NixOS configurations (created with `nixpkgs.lib.nixosSystem`). (As of 2024-01-10 there is only a single configuration named `default`.)
JSON schema is provided in `userdata/schema.json` for reference.
## updating flake inputs
**hardware-configuration.nix is not included.**
We have 2 flake inputs:
- nixpkgs
- selfprivacy-api
Example JSON config:
Both get updated the same ways.
```json
{
"backblaze": {
"accountId": "BACKBLAZE_KEY_ID",
"accountKey": "BACKBLAZE_ACCOUNT_KEY",
"bucket": "BACKBLAZE_BUCKET_NAME"
},
"api": {
"token": "API_TOKEN",
"enableSwagger": false
},
"bitwarden": {
"enable": true
},
"cloudflare": {
"apiKey": "CF_TOKEN"
},
"databasePassword": "DB_PASSWORD",
"domain": "DOMAIN",
"hashedMasterPassword": "HASHED_PASSWORD",
"hostname": "DOMAIN",
"nextcloud": {
"enable": true,
"adminPassword": "PASSWORD",
"databasePassword": "PASSWORD"
},
"gitea": {
"enable": true
},
"jitsi": {
"enable": true
},
"ocserv": {
"enable": true
},
"pleroma": {
"enable": true
},
"timezone": "Europe/Moscow",
"resticPassword": "PASSWORD",
"ssh": {
"enable": true,
"rootSshKeys": [
"ssh-ed25519 KEY user@host"
],
"passwordAuthentication": true
},
"username": "LUSER",
"users": [
{
"hashedPassword": "OTHER_USER_HASHED_PASSWORD",
"username": "OTHER_USER"
}
]
}
```
There are 2 methods:
1. specify input name only in a command, relying on URL inside `flake.nix`
2. specify input name and URL in a command, **overriding** whatever URL is inside `flake.nix` for the input to update (override)
In any case a Nix flake input is specified using some special _references_ syntax, including URLs, revisions, etc, described in manual: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#examples. Such reference can be used inside `flake.nix` or as an argument to `nix flake` commands. When a new reference is encountered Nix downloads and extracts it to /nix/store.
Before and after running `nix flake lock` (or `nix flake update`) commands you would most likely want to list current inputs using `nix flake metadata`, which are read from `flake.lock` file. Although, Nix should also print a diff between changed references once changed.
`--commit-lock-file` option tells Nix commands to do `git commit flake.lock` automatically, creating a new commit for you.
### method 1: update specific input
Example:
```console
$ nix flake lock --update-input nixpkgs
$ nix flake lock --update-input selfprivacy-api
```
Depending on how "precise" the URL was speficied in `flake.nix`, with _unmodified_ `flake.nix` the result might be:
* URL with `rev` (sha1) parameter => nothing will update (as we're already at exact commit)
* URL with `ref` (branch) parameter => input will update to the latest commit of the specified branch
* URL without `rev` nor `ref` => input will update to the latest commit of a default branch!
---
Once Nix 2.19 stabilizes, a different command _must_ be used for updating a single input (recursively), like this:
```console
$ nix flake update nixpkgs
```
### method 2: override specific input
Overriding is more powerful (for non-nested flakes) as it allows to change a flake input reference to anything just in one command (not only update in the bounds of a branch or a repository).
Example:
```console
$ nix flake lock --override-input nixpkgs github:nixos/nixpkgs?ref=nixos-23.11
$ nix flake lock --override-input selfprivacy-api git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git?ref=flakes
```
Similarly to update mechanism (described above), depending on the "precision" of an URL, its update scope varies accordingly.
Note, that subsequent calls of `nix flake lock --update-input <INPUT>` or `nix flake update` (or `nix flake update INPUT` by Nix 2.19+) will update the input regardless of the prior override. The information about override is stored only in `flake.lock` (`flake.nix` is not altered by Nix).
---
Note, that override does not update flake inputs recursively (say, you have a flake nested inside your flake input). For recursive updates only `nix flake lock --update-input` and `nix flake update` mechanisms are suitable. However, as of 2024-01-10 none of the SP NixOS configuration inputs contain other flakes, hence override mechanism is fine (don't confuse with top-level flake which has nested inputs).

View File

@ -1,152 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.selfprivacy-api;
directionArg =
if cfg.direction == ""
then ""
else "--direction=${cfg.direction}";
in
{
options.services.selfprivacy-api = {
enable = mkOption {
default = true;
type = types.bool;
description = ''
Enable SelfPrivacy API service
'';
};
enableSwagger = mkOption {
default = false;
type = types.bool;
description = ''
Enable Swagger UI
'';
};
b2Bucket = mkOption {
type = types.str;
description = ''
B2 bucket
'';
};
};
config = lib.mkIf cfg.enable {
systemd.services.selfprivacy-api = {
description = "API Server used to control system from the mobile application";
environment = config.nix.envVars // {
inherit (config.environment.sessionVariables) NIX_PATH;
HOME = "/root";
PYTHONUNBUFFERED = "1";
ENABLE_SWAGGER = (if cfg.enableSwagger then "1" else "0");
B2_BUCKET = cfg.b2Bucket;
} // config.networking.proxy.envVars;
path = [
"/var/"
"/var/dkim/"
pkgs.coreutils
pkgs.gnutar
pkgs.xz.bin
pkgs.gzip
pkgs.gitMinimal
config.nix.package.out
pkgs.nixos-rebuild
pkgs.restic
pkgs.mkpasswd
pkgs.util-linux
pkgs.e2fsprogs
pkgs.iproute2
];
after = [ "network-online.target" ];
wantedBy = [ "network-online.target" ];
serviceConfig = {
User = "root";
ExecStart = "${pkgs.selfprivacy-graphql-api}/bin/app.py";
Restart = "always";
RestartSec = "5";
};
};
systemd.services.selfprivacy-api-worker = {
description = "Task worker for SelfPrivacy API";
environment = config.nix.envVars // {
inherit (config.environment.sessionVariables) NIX_PATH;
HOME = "/root";
PYTHONUNBUFFERED = "1";
ENABLE_SWAGGER = (if cfg.enableSwagger then "1" else "0");
B2_BUCKET = cfg.b2Bucket;
PYTHONPATH = pkgs.selfprivacy-graphql-api.pythonPath + ":${pkgs.selfprivacy-graphql-api}/lib/python3.10/site-packages/";
} // config.networking.proxy.envVars;
path = [
"/var/"
"/var/dkim/"
pkgs.coreutils
pkgs.gnutar
pkgs.xz.bin
pkgs.gzip
pkgs.gitMinimal
config.nix.package.out
pkgs.nixos-rebuild
pkgs.restic
pkgs.mkpasswd
pkgs.util-linux
pkgs.e2fsprogs
pkgs.iproute2
];
after = [ "network-online.target" ];
wantedBy = [ "network-online.target" ];
serviceConfig = {
User = "root";
ExecStart = "${pkgs.python310Packages.huey}/bin/huey_consumer.py selfprivacy_api.task_registry.huey";
Restart = "always";
RestartSec = "5";
};
};
# One shot systemd service to rebuild NixOS using nixos-rebuild
systemd.services.sp-nixos-rebuild = {
description = "Upgrade NixOS using nixos-rebuild";
environment = config.nix.envVars // {
inherit (config.environment.sessionVariables) NIX_PATH;
HOME = "/root";
} // config.networking.proxy.envVars;
path = [ pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gzip pkgs.gitMinimal config.nix.package.out pkgs.nixos-rebuild ];
serviceConfig = {
User = "root";
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch";
KillMode = "none";
SendSIGKILL = "no";
};
};
# One shot systemd service to upgrade NixOS using nixos-rebuild
systemd.services.sp-nixos-upgrade = {
description = "Upgrade NixOS using nixos-rebuild";
environment = config.nix.envVars // {
inherit (config.environment.sessionVariables) NIX_PATH;
HOME = "/root";
} // config.networking.proxy.envVars;
path = [ pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gzip pkgs.gitMinimal config.nix.package.out pkgs.nixos-rebuild ];
serviceConfig = {
User = "root";
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --upgrade";
KillMode = "none";
SendSIGKILL = "no";
};
};
# One shot systemd service to rollback NixOS using nixos-rebuild
systemd.services.sp-nixos-rollback = {
description = "Rollback NixOS using nixos-rebuild";
environment = config.nix.envVars // {
inherit (config.environment.sessionVariables) NIX_PATH;
HOME = "/root";
} // config.networking.proxy.envVars;
path = [ pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gzip pkgs.gitMinimal config.nix.package.out pkgs.nixos-rebuild ];
serviceConfig = {
User = "root";
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --rollback";
KillMode = "none";
SendSIGKILL = "no";
};
};
};
}

View File

@ -1,18 +0,0 @@
{ config, pkgs, ... }:
{
services.selfprivacy-api = {
enable = true;
enableSwagger = config.services.userdata.api.enableSwagger;
b2Bucket = config.services.userdata.backup.bucket;
};
users.users."selfprivacy-api" = {
isNormalUser = false;
isSystemUser = true;
extraGroups = [ "opendkim" ];
group = "selfprivacy-api";
};
users.groups."selfprivacy-api" = {
members = [ "selfprivacy-api" ];
};
}

View File

@ -1,29 +0,0 @@
{ config, pkgs, ... }:
let
cfg = config.services.userdata;
in
{
services.restic.backups = {
options = {
passwordFile = "/etc/restic/resticPasswd";
repository = "s3:s3.anazonaws.com/${cfg.backup.bucket}";
initialize = true;
paths = [
"/var/dkim"
"/var/vmail"
];
timerConfig = {
OnCalendar = [ "daily" ];
};
user = "restic";
pruneOpts = [
"--keep-daily 5"
];
};
};
users.users.restic = {
isNormalUser = false;
isSystemUser = true;
group = "restic";
};
}

View File

@ -1,34 +1,19 @@
{ config, pkgs, lib, ... }:
let
url-overlay = "https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nix-repo/archive/22-11.tar.gz";
nix-overlay = (import (builtins.fetchTarball url-overlay));
in
{
imports = [
./hardware-configuration.nix
./variables-module.nix
./variables.nix
./files.nix
./selfprivacy-module.nix
./volumes.nix
./users.nix
./mailserver/system/mailserver.nix
./vpn/ocserv.nix
./api/api.nix
./api/api-module.nix
./social/pleroma.nix
./letsencrypt/acme.nix
./letsencrypt/resolve.nix
./backup/restic.nix
./passmgr/bitwarden.nix
./webserver/nginx.nix
./webserver/memcached.nix
./nextcloud/nextcloud.nix
./resources/limits.nix
./videomeet/jitsi.nix
./git/gitea.nix
# ./resources/limits.nix
];
nixpkgs.overlays = [ (nix-overlay) ];
fileSystems."/".options = [ "noatime" ];
services.selfprivacy-api.enable = true;
services.redis.servers.sp-api = {
enable = true;
@ -48,11 +33,12 @@ in
};
};
services.do-agent.enable = if config.services.userdata.server.provider == "DIGITALOCEAN" then true else false;
services.do-agent.enable = if config.selfprivacy.server.provider == "DIGITALOCEAN" then true else false;
boot.cleanTmpDir = true;
boot.tmp.cleanOnBoot = true;
networking = {
hostName = config.services.userdata.hostname;
hostName = config.selfprivacy.hostname;
domain = config.selfprivacy.domain;
usePredictableInterfaceNames = false;
firewall = {
allowedTCPPorts = lib.mkForce [ 22 25 80 143 443 465 587 993 4443 8443 ];
@ -64,43 +50,89 @@ in
};
nameservers = [ "1.1.1.1" "1.0.0.1" ];
};
time.timeZone = config.services.userdata.timezone;
time.timeZone = config.selfprivacy.timezone;
i18n.defaultLocale = "en_GB.UTF-8";
users.users.root.openssh.authorizedKeys.keys = config.services.userdata.ssh.rootKeys;
users.users.root.openssh.authorizedKeys.keys = config.selfprivacy.ssh.rootKeys;
services.openssh = {
enable = config.services.userdata.ssh.enable;
passwordAuthentication = config.services.userdata.ssh.passwordAuthentication;
permitRootLogin = "yes";
enable = config.selfprivacy.ssh.enable;
settings = {
PasswordAuthentication = config.selfprivacy.ssh.passwordAuthentication;
PermitRootLogin = "yes";
};
openFirewall = false;
};
programs.ssh = {
pubkeyAcceptedKeyTypes = [ "ssh-ed25519" "ssh-rsa" ];
pubkeyAcceptedKeyTypes = [ "ssh-ed25519" "ssh-rsa" "ecdsa-sha2-nistp256" ];
hostKeyAlgorithms = [ "ssh-ed25519" "ssh-rsa" ];
};
environment.systemPackages = with pkgs; [
git
jq
];
environment.variables = {
DOMAIN = config.services.userdata.domain;
};
# consider environment.defaultPackages = lib.mkForce [];
documentation.enable = false; # no {man,info}-pages & docs, etc to save space
# (or create a systemd service with `ConditionFirstBoot=yes`?)
systemd.tmpfiles.rules = [
"# Completely remove remnants of NIXOS_LUSTRATE."
"R! /old-root"
];
system.stateVersion =
lib.mkIf (config.selfprivacy.stateVersion != null)
config.selfprivacy.stateVersion;
system.autoUpgrade = {
enable = config.services.userdata.autoUpgrade.enable;
allowReboot = config.services.userdata.autoUpgrade.allowReboot;
channel = "https://channel.selfprivacy.org/nixos-selfpricacy";
enable = config.selfprivacy.autoUpgrade.enable;
allowReboot = config.selfprivacy.autoUpgrade.allowReboot;
# TODO get attribute name from selfprivacy options
flake = "/etc/nixos#default";
};
system.stateVersion = config.services.userdata.stateVersion;
systemd.services.nixos-upgrade.serviceConfig.WorkingDirectory = "/etc/nixos";
# TODO parameterize URL somehow; run nix flake update as non-root user
systemd.services.nixos-upgrade.serviceConfig.ExecCondition =
pkgs.writeShellScript "flake-update-script" ''
set -o xtrace
if ${config.nix.package.out}/bin/nix flake update \
--override-input selfprivacy-nixos-config git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-config.git?ref=flakes
then
if ${pkgs.diffutils}/bin/diff -u -r /etc/selfprivacy/nixos-config-source/ /etc/nixos/
then
set +o xtrace
echo "No configuration changes detected. Nothing to upgrade."
exit 1
fi
else
# ExecStart must not start after 255 exit code, service must fail.
exit 255
fi
'';
nix = {
optimise.automatic = true;
channel.enable = false;
# daemonCPUSchedPolicy = "idle";
# daemonIOSchedClass = "idle";
# daemonIOSchedPriority = 7;
# this is superseded by nix.settings.auto-optimise-store.
# optimise.automatic = true;
gc = {
automatic = true;
automatic = true; # TODO it's debatable, because of IO&CPU load
options = "--delete-older-than 7d";
};
};
nix.settings = {
sandbox = true;
experimental-features = [ "nix-command" "flakes" "repl-flake" ];
# auto-optimise-store = true;
# evaluation restrictions:
# restrict-eval = true;
# allowed-uris = [];
allow-dirty = false;
};
services.journald.extraConfig = "SystemMaxUse=500M";
boot.kernel.sysctl = {
"net.ipv4.ip_forward" = 1;
"net.ipv4.ip_forward" = 1; # TODO why is it here by default, for VPN only?
};
# TODO must be configurable and determined at nixos-infect stage
swapDevices = [
{
device = "/swapfile";
@ -108,9 +140,12 @@ in
size = 2048;
}
];
# TODO why is sudo needed?
security = {
sudo = {
enable = true;
};
};
systemd.enableEmergencyMode = false;
systemd.coredump.enable = false;
}

View File

@ -1,83 +0,0 @@
{ config, pkgs, ... }:
let
cfg = config.services.userdata;
in
{
systemd.tmpfiles.rules =
let
domain = builtins.replaceStrings [ "\n" "\"" "\\" "%" ] [ "\\n" "\\\"" "\\\\" "%%" ] cfg.domain;
in
[
(if cfg.bitwarden.enable then "d /var/lib/bitwarden 0777 vaultwarden vaultwarden -" else "")
(if cfg.bitwarden.enable then "d /var/lib/bitwarden/backup 0777 vaultwarden vaultwarden -" else "")
(if cfg.pleroma.enable then "d /var/lib/pleroma 0700 pleroma pleroma - -" else "")
"d /var/lib/restic 0600 restic - - -"
(if cfg.pleroma.enable then "f /var/lib/pleroma/secrets.exs 0755 pleroma pleroma - -" else "")
"f+ /var/domain 0444 selfprivacy-api selfprivacy-api - ${domain}"
];
system.activationScripts =
let
jq = "${pkgs.jq}/bin/jq";
sed = "${pkgs.gnused}/bin/sed";
in
{
nextcloudSecrets =
if cfg.nextcloud.enable then ''
mkdir -p /var/lib/nextcloud
cat /etc/nixos/userdata/userdata.json | ${jq} -r '.nextcloud.databasePassword' > /var/lib/nextcloud/db-pass
chmod 0440 /var/lib/nextcloud/db-pass
chown nextcloud:nextcloud /var/lib/nextcloud/db-pass
cat /etc/nixos/userdata/userdata.json | ${jq} -r '.nextcloud.adminPassword' > /var/lib/nextcloud/admin-pass
chmod 0440 /var/lib/nextcloud/admin-pass
chown nextcloud:nextcloud /var/lib/nextcloud/admin-pass
''
else ''
rm -f /var/lib/nextcloud/db-pass
rm -f /var/lib/nextcloud/admin-pass
'';
cloudflareCredentials = ''
mkdir -p /var/lib/cloudflare
chmod 0440 /var/lib/cloudflare
chown nginx:acmerecievers /var/lib/cloudflare
echo 'CF_API_KEY=REPLACEME' > /var/lib/cloudflare/Credentials.ini
echo 'CLOUDFLARE_DNS_API_TOKEN=REPLACEME' >> /var/lib/cloudflare/Credentials.ini
echo 'CLOUDFLARE_ZONE_API_TOKEN=REPLACEME' >> /var/lib/cloudflare/Credentials.ini
${sed} -i "s/REPLACEME/$(cat /etc/nixos/userdata/userdata.json | ${jq} -r '.dns.apiKey')/g" /var/lib/cloudflare/Credentials.ini
chmod 0440 /var/lib/cloudflare/Credentials.ini
chown nginx:acmerecievers /var/lib/cloudflare/Credentials.ini
'';
resticCredentials = ''
mkdir -p /root/.config/rclone
chmod 0400 /root/.config/rclone
chown root:root /root/.config/rclone
echo '[backblaze]' > /root/.config/rclone/rclone.conf
echo 'type = b2' >> /root/.config/rclone/rclone.conf
echo 'account = REPLACEME1' >> /root/.config/rclone/rclone.conf
echo 'key = REPLACEME2' >> /root/.config/rclone/rclone.conf
${sed} -i "s/REPLACEME1/$(cat /etc/nixos/userdata/userdata.json | ${jq} -r '.backup.accountId')/g" /root/.config/rclone/rclone.conf
${sed} -i "s/REPLACEME2/$(cat /etc/nixos/userdata/userdata.json | ${jq} -r '.backup.accountKey')/g" /root/.config/rclone/rclone.conf
chmod 0400 /root/.config/rclone/rclone.conf
chown root:root /root/.config/rclone/rclone.conf
cat /etc/nixos/userdata/userdata.json | ${jq} -r '.resticPassword' > /var/lib/restic/pass
chmod 0400 /var/lib/restic/pass
chown restic /var/lib/restic/pass
'';
pleromaCredentials =
if cfg.pleroma.enable then ''
echo 'import Config' > /var/lib/pleroma/secrets.exs
echo 'config :pleroma, Pleroma.Repo,' >> /var/lib/pleroma/secrets.exs
echo ' password: "REPLACEME"' >> /var/lib/pleroma/secrets.exs
${sed} -i "s/REPLACEME/$(cat /etc/nixos/userdata/userdata.json | ${jq} -r '.databasePassword')/g" /var/lib/pleroma/secrets.exs
chmod 0750 /var/lib/pleroma/secrets.exs
chown pleroma:pleroma /var/lib/pleroma/secrets.exs
'' else ''
rm -f /var/lib/pleroma/secrets.exs
'';
};
}

47
flake.lock Normal file
View File

@ -0,0 +1,47 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1714531828,
"narHash": "sha256-ILsf3bdY/hNNI/Hu5bSt2/KbmHaAVhBbNUOdGztTHEg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "0638fe2715d998fa81d173aad264eb671ce2ebc1",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"selfprivacy-api": "selfprivacy-api"
}
},
"selfprivacy-api": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1709843377,
"narHash": "sha256-lQGd4xtKWsIlD5vVurrA/xtNYxYFGfLGyev4oOUeMmY=",
"ref": "master",
"rev": "1f1fcc223be4c6ae65eef1d50918aed0826e5ad1",
"revCount": 1259,
"type": "git",
"url": "https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git"
},
"original": {
"type": "git",
"url": "https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git"
}
}
},
"root": "root",
"version": 7
}

98
flake.nix Normal file
View File

@ -0,0 +1,98 @@
{
description = "SelfPrivacy NixOS configuration flake";
inputs = {
nixpkgs.url = github:nixos/nixpkgs;
selfprivacy-api.url =
git+https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git;
# make selfprivacy-api use the same shared nixpkgs
selfprivacy-api.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, selfprivacy-api }: {
nixosConfigurations-fun =
{ hardware-configuration
, deployment
, userdata
, top-level-flake
, sp-modules
}:
{
default = nixpkgs.lib.nixosSystem {
modules = [
hardware-configuration
deployment
./configuration.nix
selfprivacy-api.nixosModules.default
{
# pass userdata (parsed from JSON) options to selfprivacy module
selfprivacy = userdata;
# embed top-level flake source folder into the build
environment.etc."selfprivacy/nixos-config-source".source =
top-level-flake;
# for running "nix search nixpkgs", etc
nix.registry.nixpkgs.flake = nixpkgs;
# embed commit sha1 for `nixos-version --configuration-revision`
system.configurationRevision = self.rev
or "@${self.lastModifiedDate}"; # for development
# TODO assertion to forbid dirty builds caused by top-level-flake
# reset contents of /etc/nixos to match running NixOS generation
system.activationScripts.selfprivacy-nixos-config-source = ''
rm -rf /etc/nixos/{*,.[!.]*}
cp -r --no-preserve=all ${top-level-flake}/ -T /etc/nixos/
'';
}
]
++
# add SP modules, but contrain available config attributes for each
# (TODO revise evaluation performance of the code below)
nixpkgs.lib.attrsets.mapAttrsToList
(name: sp-module: args@{ config, pkgs, ... }:
let
lib = nixpkgs.lib;
configPathsNeeded = sp-module.configPathsNeeded or
(abort "allowed config paths not set for module \"${name}\"");
constrainConfigArgs = args'@{ pkgs, ... }: args' // {
config =
# TODO use lib.attrsets.mergeAttrsList from nixpkgs 23.05
(builtins.foldl' lib.attrsets.recursiveUpdate { }
(map
(p: lib.attrsets.setAttrByPath p
(lib.attrsets.getAttrFromPath p config))
configPathsNeeded
)
);
};
constrainImportsArgsRecursive = lib.attrsets.mapAttrsRecursive
(p: v:
# TODO traverse only imports and imports of imports, etc
# without traversing all attributes
if lib.lists.last p == "imports"
then
map
(m:
(args'@{ pkgs, ... }: constrainImportsArgsRecursive
(if builtins.isPath m
then import m (constrainConfigArgs args')
else
if builtins.isFunction m
then m (constrainConfigArgs args')
else m))
)
v
else v);
in
constrainImportsArgsRecursive
(sp-module.nixosModules.default (constrainConfigArgs args))
)
sp-modules;
};
};
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;
};
}

View File

@ -1,66 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.userdata;
in
{
fileSystems = lib.mkIf cfg.useBinds {
"/var/lib/gitea" = {
device = "/volumes/${cfg.gitea.location}/gitea";
options = [ "bind" ];
};
};
services = {
gitea = {
enable = cfg.gitea.enable;
stateDir = "/var/lib/gitea";
user = "gitea";
database = {
type = "sqlite3";
host = "127.0.0.1";
name = "gitea";
user = "gitea";
path = "/var/lib/gitea/data/gitea.db";
createDatabase = true;
};
# ssh = {
# enable = true;
# clonePort = 22;
# };
lfs = {
enable = true;
contentDir = "/var/lib/gitea/lfs";
};
appName = "SelfPrivacy git Service";
repositoryRoot = "/var/lib/gitea/repositories";
domain = "git.${cfg.domain}";
rootUrl = "https://git.${cfg.domain}/";
httpAddress = "0.0.0.0";
httpPort = 3000;
settings = {
mailer = {
ENABLED = false;
};
ui = {
DEFAULT_THEME = "arc-green";
SHOW_USER_EMAIL = false;
};
picture = {
DISABLE_GRAVATAR = true;
};
admin = {
ENABLE_KANBAN_BOARD = true;
};
repository = {
FORCE_PRIVATE = false;
};
session = {
COOKIE_SECURE = true;
};
log = {
ROOT_PATH = "/var/lib/gitea/log";
LEVEL = "Warn";
};
};
};
};
}

View File

@ -1,31 +1,63 @@
{ config, pkgs, lib, ... }:
{ config, lib, pkgs, ... }:
let
cfg = config.services.userdata;
cfg = config.selfprivacy;
dnsCredentialsTemplates = {
DIGITALOCEAN = "DO_AUTH_TOKEN=$TOKEN";
CLOUDFLARE = ''
CF_API_KEY=$TOKEN
CLOUDFLARE_DNS_API_TOKEN=$TOKEN
CLOUDFLARE_ZONE_API_TOKEN=$TOKEN
CLOUDFLARE_POLLING_INTERVAL=30
'';
DESEC = ''
DESEC_TOKEN=$TOKEN
DESEC_POLLING_INTERVAL=30
DESEC_PROPAGATION_TIMEOUT=180
DESEC_TTL=3600
'';
};
dnsCredentialsTemplate = dnsCredentialsTemplates.${cfg.dns.provider};
acme-env-filepath = "/var/lib/selfprivacy/acme-env";
secrets-filepath = "/etc/selfprivacy/secrets.json";
dnsPropagationCheckExceptions = [ "DIGITALOCEAN" "DESEC" ];
in
{
users.groups.acmerecievers = {
members = [ "nginx" "dovecot2" "postfix" "virtualMail" "ocserv" ];
};
users.groups.acmereceivers.members = [ "nginx" ];
security.acme = {
acceptTerms = true;
defaults = {
email = "${cfg.username}@${cfg.domain}";
server = if cfg.dns.useStagingACME then "https://acme-staging-v02.api.letsencrypt.org/directory" else "https://acme-v02.api.letsencrypt.org/directory";
reloadServices = [ "nginx" ];
};
certs = lib.mkForce {
certs = {
"${cfg.domain}" = {
domain = "*.${cfg.domain}";
extraDomainNames = [ "${cfg.domain}" ];
group = "acmerecievers";
dnsProvider = "cloudflare";
credentialsFile = "/var/lib/cloudflare/Credentials.ini";
};
"meet.${cfg.domain}" = {
domain = "meet.${cfg.domain}";
group = "acmerecievers";
dnsProvider = "cloudflare";
credentialsFile = "/var/lib/cloudflare/Credentials.ini";
group = "acmereceivers";
dnsProvider = lib.strings.toLower cfg.dns.provider;
credentialsFile = acme-env-filepath;
dnsPropagationCheck =
! (lib.elem cfg.dns.provider dnsPropagationCheckExceptions);
};
};
};
systemd.services.acme-secrets = {
before = [ "acme-${cfg.domain}.service" ];
requiredBy = [ "acme-${cfg.domain}.service" ];
serviceConfig.Type = "oneshot";
path = with pkgs; [ coreutils jq ];
script = ''
set -o nounset
TOKEN="$(jq -re '.dns.apiKey' ${secrets-filepath})"
filecontents=$(cat <<- EOF
${dnsCredentialsTemplate}
EOF
)
install -m 0440 -o root -g acmereceivers -DT \
<(printf "%s\n" "$filecontents") ${acme-env-filepath}
'';
};
}

View File

@ -1,6 +1,6 @@
{ config, pkgs, ... }:
{ config, lib, ... }:
let
domain = config.services.userdata.domain;
domain = config.selfprivacy.domain;
in
{
systemd = {
@ -12,11 +12,6 @@ in
Restart = "on-failure";
};
};
"nginx-config-reload" = {
serviceConfig = {
After = [ "acme-${domain}.service" ];
};
};
};
};
}

View File

@ -1,40 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.services.userdata;
in
{
fileSystems = lib.mkIf cfg.useBinds {
"/var/lib/nextcloud" = {
device = "/volumes/${cfg.nextcloud.location}/nextcloud";
options = [ "bind" ];
};
};
services.nextcloud = {
enable = cfg.nextcloud.enable;
package = pkgs.nextcloud25;
hostName = "cloud.${cfg.domain}";
# Use HTTPS for links
https = false;
# Auto-update Nextcloud Apps
autoUpdateApps.enable = true;
# Set what time makes sense for you
autoUpdateApps.startAt = "05:00:00";
config = {
# Further forces Nextcloud to use HTTPS
overwriteProtocol = "https";
# Nextcloud PostegreSQL database configuration, recommended over using SQLite
dbtype = "sqlite";
dbuser = "nextcloud";
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
dbname = "nextcloud";
dbpassFile = "/var/lib/nextcloud/db-pass";
adminpassFile = "/var/lib/nextcloud/admin-pass";
adminuser = "admin";
};
};
}

View File

@ -1,26 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.services.userdata;
in
{
fileSystems = lib.mkIf cfg.useBinds {
"/var/lib/bitwarden" = {
device = "/volumes/${cfg.bitwarden.location}/bitwarden";
options = [ "bind" ];
};
"/var/lib/bitwarden_rs" = {
device = "/volumes/${cfg.bitwarden.location}/bitwarden_rs";
options = [ "bind" ];
};
};
services.vaultwarden = {
enable = cfg.bitwarden.enable;
dbBackend = "sqlite";
backupDir = "/var/lib/bitwarden/backup";
config = {
domain = "https://password.${cfg.domain}/";
signupsAllowed = true;
rocketPort = 8222;
};
};
}

View File

@ -1,47 +1,46 @@
{ pkgs, ... }:
{
systemd.services = {
dovecot2 = {
serviceConfig = {
cpuAccounting = true;
cpuQuota = "20%";
memoryAccounting = true;
memoryMax = "256M";
startLimitIntervalSec = 500;
startLimitBurst = 5;
blockIOWeigth = 25;
CpuAccounting = true;
CpuQuota = "20%";
MemoryAccounting = true;
MemoryMax = "256M";
StartLimitIntervalSec = 500;
StartLimitBurst = 5;
BlockIOWeight = 25;
};
};
postfix = {
serviceConfig = {
cpuAccounting = true;
cpuQuota = "20%";
memoryAccounting = true;
memoryMax = "256M";
startLimitIntervalSec = 500;
startLimitBurst = 5;
blockIOWeigth = 25;
CpuAccounting = true;
CpuQuota = "20%";
MemoryAccounting = true;
MemoryMax = "256M";
StartLimitIntervalSec = 500;
StartLimitBurst = 5;
BlockIOWeight = 25;
};
};
ocserv = {
serviceConfig = {
cpuAccounting = true;
cpuQuota = "70%";
memoryAccounting = true;
memoryMax = "512M";
startLimitIntervalSec = 500;
startLimitBurst = 5;
CpuAccounting = true;
CpuQuota = "70%";
MemoryAccounting = true;
MemoryMax = "512M";
StartLimitIntervalSec = 500;
StartLimitBurst = 5;
};
};
nginx = {
serviceConfig = {
cpuAccounting = true;
cpuQuota = "70%";
memoryAccounting = true;
memoryMax = "768M";
startLimitIntervalSec = 500;
startLimitBurst = 5;
blockIOWeigth = 10;
CpuAccounting = true;
CpuQuota = "70%";
MemoryAccounting = true;
MemoryMax = "768M";
StartLimitIntervalSec = 500;
StartLimitBurst = 5;
BlockIOWeight = 10;
};
};
};

View File

@ -1,16 +1,8 @@
{ config, lib, pkgs, ... }:
{ lib, ... }:
with lib;
let
cfg = config.services.userdata;
directionArg =
if cfg.direction == ""
then ""
else "--direction=${cfg.direction}";
in
{
options.services.userdata = {
options.selfprivacy = {
# General server options
hostname = mkOption {
description = "The hostname of the server.";
@ -20,19 +12,20 @@ in
description = ''
Domain used by the server
'';
type = types.nullOr types.str;
# see: https://regexr.com/7p7ep, https://stackoverflow.com/a/26987741
type = lib.types.strMatching ''^(xn--)?[a-z0-9][a-z0-9_-]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$'';
};
timezone = mkOption {
description = ''
Timezone used by the server
'';
type = types.nullOr types.str;
default = "Europe/Uzhgorod";
default = "Etc/UTC";
};
autoUpgrade = {
enable = mkOption {
description = "Enable auto-upgrade of the server.";
default = true;
default = false;
type = types.nullOr types.bool;
};
allowReboot = mkOption {
@ -42,11 +35,9 @@ in
};
};
stateVersion = mkOption {
description = ''
State version of the server
'';
type = types.str;
default = "22.11";
description = "State version of the server";
type = types.nullOr types.str;
default = null;
};
########################
# Server admin options #
@ -70,109 +61,24 @@ in
type = types.nullOr (types.listOf types.str);
default = [ ];
};
###############
# API options #
###############
api = {
enableSwagger = mkOption {
default = true;
description = ''
Enable Swagger UI
'';
type = types.bool;
};
skippedMigrations = mkOption {
default = [ ];
description = ''
List of migrations that should be skipped
'';
type = types.listOf types.str;
};
};
#############
# Secrets #
# DNS #
#############
dns = {
provider = mkOption {
description = "DNS provider that was defined at the initial setup process. Default is ClOUDFLARE";
description = "DNS provider that was defined at the initial setup process.";
type = types.nullOr types.str;
};
useStagingACME = mkOption {
description = "Use staging ACME server. Default is false";
type = types.nullOr types.bool;
};
};
backup = {
bucket = mkOption {
description = "Bucket name used for userdata backups";
type = types.nullOr types.str;
default = false;
};
};
server = {
provider = mkOption {
description = "Server provider that was defined at the initial setup process. Default is HETZNER";
type = types.nullOr types.str;
};
};
##############
# Services #
##############
bitwarden = {
enable = mkOption {
default = false;
type = types.nullOr types.bool;
};
location = mkOption {
default = "sda1";
type = types.nullOr types.str;
};
};
email = {
location = mkOption {
default = "sda1";
type = types.nullOr types.str;
};
};
gitea = {
enable = mkOption {
default = false;
type = types.nullOr types.bool;
};
location = mkOption {
default = "sda1";
type = types.nullOr types.str;
};
};
nextcloud = {
enable = mkOption {
default = true;
type = types.nullOr types.bool;
};
location = mkOption {
default = "sda1";
type = types.nullOr types.str;
};
};
pleroma = {
enable = mkOption {
default = false;
type = types.nullOr types.bool;
};
location = mkOption {
default = "sda1";
type = types.nullOr types.str;
};
};
jitsi = {
enable = mkOption {
default = false;
type = types.nullOr types.bool;
};
};
ocserv = {
enable = mkOption {
default = true;
type = types.nullOr types.bool;
description = "Server provider that was defined at the initial setup process.";
type = types.str;
};
};
#########
@ -185,7 +91,7 @@ in
};
rootKeys = mkOption {
description = ''
Root SSH Keys
Root SSH authorized keys
'';
type = types.nullOr (types.listOf types.str);
default = [ "" ];
@ -194,7 +100,7 @@ in
description = ''
Password authentication for SSH
'';
default = true;
default = false;
type = types.nullOr types.bool;
};
};
@ -221,6 +127,7 @@ in
useBinds = mkOption {
type = types.nullOr types.bool;
default = false;
description = "Whether to bind-mount vmail and sieve folders";
};
};
}

View File

@ -1,60 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.services.userdata;
in
{
fileSystems = lib.mkIf cfg.useBinds {
"/var/lib/pleroma" = {
device = "/volumes/${cfg.pleroma.location}/pleroma";
options = [ "bind" ];
};
"/var/lib/postgresql" = {
device = "/volumes/${cfg.pleroma.location}/postgresql";
options = [ "bind" ];
};
};
services = {
pleroma = {
enable = cfg.pleroma.enable;
user = "pleroma";
group = "pleroma";
configs = [
(builtins.replaceStrings
[ "$DOMAIN" "$LUSER" ]
[ cfg.domain cfg.username ]
(builtins.readFile ./config.exs))
];
};
postgresql = {
enable = true;
package = pkgs.postgresql_12;
initialScript = "/etc/setup.psql";
ensureDatabases = [
"pleroma"
];
ensureUsers = [
{
name = "pleroma";
ensurePermissions = {
"DATABASE pleroma" = "ALL PRIVILEGES";
};
}
];
};
};
environment.etc."setup.psql".text = ''
CREATE USER pleroma;
CREATE DATABASE pleroma OWNER pleroma;
\c pleroma;
--Extensions made by ecto.migrate that need superuser access
CREATE EXTENSION IF NOT EXISTS citext;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
'';
users.users.pleroma = {
extraGroups = [ "postgres" ];
isNormalUser = false;
isSystemUser = true;
group = "pleroma";
};
}

View File

@ -0,0 +1,17 @@
{ config, lib, ... }:
let
inherit (import ./common.nix config) bitwarden-env sp;
in
# FIXME do we really want to delete passwords on module deactivation!?
{
config = lib.mkIf (!sp.modules.bitwarden.enable) {
system.activationScripts.bitwarden =
lib.trivial.warn
(
"bitwarden service is disabled, ${bitwarden-env} will be removed!"
)
''
rm -f -v ${bitwarden-env}
'';
};
}

View File

@ -0,0 +1,5 @@
config:
{
sp = config.selfprivacy;
bitwarden-env = "/var/lib/bitwarden/.env";
}

View File

@ -0,0 +1,5 @@
[
[ "selfprivacy", "domain" ],
[ "selfprivacy", "useBinds" ],
[ "selfprivacy", "modules", "bitwarden" ]
]

View File

@ -0,0 +1,10 @@
{
description = "PoC SP module for Bitwarden password management solution";
outputs = { self }: {
nixosModules.default = _:
{ imports = [ ./module.nix ./cleanup-module.nix ]; };
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

View File

@ -0,0 +1,107 @@
{ config, lib, pkgs, ... }:
let
secrets-filepath = "/etc/selfprivacy/secrets.json";
backup-dir = "/var/lib/bitwarden/backup";
cfg = sp.modules.bitwarden;
inherit (import ./common.nix config) bitwarden-env sp;
in
{
options.selfprivacy.modules.bitwarden = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
location = lib.mkOption {
type = lib.types.str;
};
subdomain = lib.mkOption {
default = "password";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config = lib.mkIf config.selfprivacy.modules.bitwarden.enable {
fileSystems = lib.mkIf sp.useBinds {
"/var/lib/bitwarden" = {
device = "/volumes/${cfg.location}/bitwarden";
options = [
"bind"
"x-systemd.required-by=bitwarden-secrets.service"
"x-systemd.required-by=backup-vaultwarden.service"
"x-systemd.required-by=vaultwarden.service"
"x-systemd.before=bitwarden-secrets.service"
"x-systemd.before=backup-vaultwarden.service"
"x-systemd.before=vaultwarden.service"
];
};
"/var/lib/bitwarden_rs" = {
device = "/volumes/${cfg.location}/bitwarden_rs";
options = [
"bind"
"x-systemd.required-by=bitwarden-secrets.service"
"x-systemd.required-by=backup-vaultwarden.service"
"x-systemd.required-by=vaultwarden.service"
"x-systemd.before=bitwarden-secrets.service"
"x-systemd.before=backup-vaultwarden.service"
"x-systemd.before=vaultwarden.service"
];
};
};
services.vaultwarden = {
enable = true;
dbBackend = "sqlite";
backupDir = backup-dir;
environmentFile = "${bitwarden-env}";
config = {
domain = "https://${cfg.subdomain}.${sp.domain}/";
signupsAllowed = true;
rocketPort = 8222;
};
};
systemd.services.bitwarden-secrets = {
before = [ "vaultwarden.service" ];
requiredBy = [ "vaultwarden.service" ];
serviceConfig.Type = "oneshot";
path = with pkgs; [ coreutils jq ];
script = ''
set -o nounset
token="$(jq -r '.bitwarden.adminToken' ${secrets-filepath})"
if [ "$token" == "null" ]; then
# If it's null, empty the contents of the file
bitwarden_env=""
else
bitwarden_env="ADMIN_TOKEN=$token"
fi
install -C -m 0700 -o vaultwarden -g vaultwarden \
-d /var/lib/bitwarden
install -C -m 0600 -o vaultwarden -g vaultwarden -DT \
<(printf "%s" "$bitwarden_env") ${bitwarden-env}
'';
};
services.nginx.virtualHosts."${cfg.subdomain}.${sp.domain}" = {
useACMEHost = sp.domain;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:8222";
};
};
};
# NixOS upstream bug? Otherwise, backup-vaultwarden cannot find sqlite DB.
systemd.services.backup-vaultwarden.unitConfig.ConditionPathExists =
"/var/lib/bitwarden_rs/db.sqlite3";
};
}

View File

@ -0,0 +1,5 @@
[
[ "selfprivacy", "domain" ],
[ "selfprivacy", "useBinds" ],
[ "selfprivacy", "modules", "gitea" ]
]

View File

@ -0,0 +1,9 @@
{
description = "PoC SP module for Gitea forge service";
outputs = { self }: {
nixosModules.default = import ./module.nix;
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

113
sp-modules/gitea/module.nix Normal file
View File

@ -0,0 +1,113 @@
{ config, lib, ... }:
let
sp = config.selfprivacy;
stateDir =
if sp.useBinds
then "/volumes/${cfg.location}/gitea"
else "/var/lib/gitea";
cfg = sp.modules.gitea;
in
{
options.selfprivacy.modules.gitea = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
location = lib.mkOption {
type = lib.types.str;
};
subdomain = lib.mkOption {
default = "git";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config = lib.mkIf cfg.enable {
fileSystems = lib.mkIf sp.useBinds {
"/var/lib/gitea" = {
device = "/volumes/${cfg.location}/gitea";
options = [ "bind" ];
};
};
services.gitea = {
enable = true;
inherit stateDir;
# log = {
# rootPath = "/var/lib/gitea/log";
# level = "Warn";
# };
user = "gitea";
database = {
type = "sqlite3";
host = "127.0.0.1";
name = "gitea";
user = "gitea";
path = "${stateDir}/data/gitea.db";
createDatabase = true;
};
# ssh = {
# enable = true;
# clonePort = 22;
# };
lfs = {
enable = true;
contentDir = "${stateDir}/lfs";
};
appName = "SelfPrivacy git Service";
repositoryRoot = "${stateDir}/repositories";
# cookieSecure = true;
settings = {
server = {
DOMAIN = "${cfg.subdomain}.${sp.domain}";
ROOT_URL = "https://${cfg.subdomain}.${sp.domain}/";
HTTP_ADDR = "0.0.0.0";
HTTP_PORT = 3000;
};
mailer = {
ENABLED = false;
};
ui = {
DEFAULT_THEME = "arc-green";
SHOW_USER_EMAIL = false;
};
picture = {
DISABLE_GRAVATAR = true;
};
admin = {
ENABLE_KANBAN_BOARD = true;
};
repository = {
FORCE_PRIVATE = false;
};
session = {
COOKIE_SECURE = true;
};
log = {
ROOT_PATH = "${stateDir}/log";
LEVEL = "Warn";
};
};
};
services.nginx.virtualHosts."${cfg.subdomain}.${sp.domain}" = {
useACMEHost = sp.domain;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:3000";
};
};
};
systemd.services.gitea.unitConfig.RequiresMountsFor =
lib.mkIf sp.useBinds "/volumes/${cfg.location}/gitea";
};
}

View File

@ -0,0 +1,4 @@
[
[ "selfprivacy", "domain" ],
[ "selfprivacy", "modules", "jitsi-meet" ]
]

View File

@ -0,0 +1,9 @@
{
description = "PoC SP module for Jitsi Meet video conferences server";
outputs = { self }: {
nixosModules.default = import ./module.nix;
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

View File

@ -0,0 +1,34 @@
{ config, lib, ... }:
let
domain = config.selfprivacy.domain;
cfg = config.selfprivacy.modules.jitsi-meet;
in
{
options.selfprivacy.modules.jitsi-meet = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
subdomain = lib.mkOption {
default = "meet";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config = lib.mkIf cfg.enable {
services.jitsi-meet = {
enable = true;
hostName = "${cfg.subdomain}.${domain}";
nginx.enable = true;
interfaceConfig = {
SHOW_JITSI_WATERMARK = false;
SHOW_WATERMARK_FOR_GUESTS = false;
};
};
services.nginx.virtualHosts."${cfg.subdomain}.${domain}" = {
forceSSL = true;
useACMEHost = domain;
enableACME = false;
};
};
}

View File

@ -0,0 +1,19 @@
{ config, lib, ... }:
let
inherit (import ./common.nix config) sp db-pass-filepath admin-pass-filepath;
in
# FIXME do we really want to delete passwords on module deactivation!?
{
config = lib.mkIf (!sp.modules.nextcloud.enable) {
system.activationScripts.nextcloudSecrets =
lib.trivial.warn
(
"nextcloud service is disabled, " +
"${db-pass-filepath} and ${admin-pass-filepath} will be removed!"
)
''
rm -f -v ${db-pass-filepath}
rm -f -v ${admin-pass-filepath}
'';
};
}

View File

@ -0,0 +1,6 @@
config: rec {
sp = config.selfprivacy;
secrets-filepath = "/etc/selfprivacy/secrets.json";
db-pass-filepath = "/var/lib/nextcloud/db-pass";
admin-pass-filepath = "/var/lib/nextcloud/admin-pass";
}

View File

@ -0,0 +1,5 @@
[
[ "selfprivacy", "domain" ],
[ "selfprivacy", "useBinds" ],
[ "selfprivacy", "modules", "nextcloud" ]
]

View File

@ -0,0 +1,10 @@
{
description = "PoC SP module for nextcloud";
outputs = { self }: {
nixosModules.default = _:
{ imports = [ ./module.nix ./cleanup-module.nix ]; };
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

View File

@ -0,0 +1,85 @@
{ config, lib, pkgs, ... }:
{
options.selfprivacy.modules.nextcloud = with lib; {
enable = mkOption {
type = types.bool;
default = false;
};
location = mkOption {
type = types.str;
};
subdomain = lib.mkOption {
default = "cloud";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config =
let
inherit (import ./common.nix config)
sp secrets-filepath db-pass-filepath admin-pass-filepath;
cfg = sp.modules.nextcloud;
hostName = "${cfg.subdomain}.${sp.domain}";
in
lib.mkIf sp.modules.nextcloud.enable {
fileSystems = lib.mkIf sp.useBinds {
"/var/lib/nextcloud" = {
device = "/volumes/${cfg.location}/nextcloud";
options = [
"bind"
"x-systemd.required-by=nextcloud-setup.service"
"x-systemd.required-by=nextcloud-secrets.service"
"x-systemd.before=nextcloud-setup.service"
"x-systemd.before=nextcloud-secrets.service"
];
};
};
systemd.services.nextcloud-secrets = {
before = [ "nextcloud-setup.service" ];
requiredBy = [ "nextcloud-setup.service" ];
serviceConfig.Type = "oneshot";
path = with pkgs; [ coreutils jq ];
script = ''
databasePassword=$(jq -re '.modules.nextcloud.databasePassword' ${secrets-filepath})
adminPassword=$(jq -re '.modules.nextcloud.adminPassword' ${secrets-filepath})
install -C -m 0440 -o nextcloud -g nextcloud -DT \
<(printf "%s\n" "$databasePassword") \
${db-pass-filepath}
install -C -m 0440 -o nextcloud -g nextcloud -DT \
<(printf "%s\n" "$adminPassword") \
${admin-pass-filepath}
'';
};
services.nextcloud = {
enable = true;
package = pkgs.nextcloud26;
inherit hostName;
# Use HTTPS for links
https = true;
# auto-update Nextcloud Apps
autoUpdateApps.enable = true;
# set what time makes sense for you
autoUpdateApps.startAt = "05:00:00";
config = {
# further forces Nextcloud to use HTTPS
overwriteProtocol = "https";
dbtype = "sqlite";
dbuser = "nextcloud";
dbname = "nextcloud";
dbpassFile = db-pass-filepath;
adminpassFile = admin-pass-filepath;
adminuser = "admin";
};
};
services.nginx.virtualHosts.${hostName} = {
useACMEHost = sp.domain;
forceSSL = true;
};
};
}

View File

@ -0,0 +1,5 @@
[
[ "security", "acme", "certs" ],
[ "selfprivacy", "domain" ],
[ "selfprivacy", "modules", "ocserv" ]
]

View File

@ -0,0 +1,9 @@
{
description = "PoC SP module for OpenConnect VPN server (ocserv)";
outputs = { self }: {
nixosModules.default = import ./module.nix;
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

View File

@ -0,0 +1,81 @@
{ config, lib, ... }:
let
domain = config.selfprivacy.domain;
cert = "${config.security.acme.certs.${domain}.directory}/fullchain.pem";
key = "${config.security.acme.certs.${domain}.directory}/key.pem";
cfg = config.selfprivacy.modules.ocserv;
in
{
options.selfprivacy.modules.ocserv = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
subdomain = lib.mkOption {
default = "vpn";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config = lib.mkIf cfg.enable {
users.groups.ocserv.members = [ "ocserv" ];
users.users.ocserv = {
isNormalUser = false;
isSystemUser = true;
extraGroups = [ "acmereceivers" ];
group = "ocserv";
};
services.ocserv = {
enable = true;
config = ''
socket-file = /var/run/ocserv-socket
auth = "pam"
tcp-port = 8443
udp-port = 8443
server-cert = ${cert}
server-key = ${key}
compression = true
max-clients = 0
max-same-clients = 6
try-mtu-discovery = true
idle-timeout=1200
mobile-idle-timeout=2400
default-domain = ${cfg.subdomain}.${domain}
device = vpn0
ipv4-network = 10.10.10.0
ipv4-netmask = 255.255.255.0
tunnel-all-dns = true
dns = 1.1.1.1
dns = 1.0.0.1
route = default
'';
};
services.nginx.virtualHosts."${cfg.subdomain}.${domain}" = {
useACMEHost = domain;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
};
systemd.services.ocserv.unitConfig.ConditionPathExists = [ cert key ];
};
}

View File

@ -0,0 +1,17 @@
{ config, lib, ... }:
let
inherit (import ./common.nix config) secrets-exs sp;
in
# FIXME do we really want to delete passwords on module deactivation!?
{
config = lib.mkIf (!sp.modules.pleroma.enable) {
system.activationScripts.pleroma =
lib.trivial.warn
(
"pleroma service is disabled, ${secrets-exs} will be removed!"
)
''
rm -f -v ${secrets-exs}
'';
};
}

View File

@ -0,0 +1,5 @@
config:
{
sp = config.selfprivacy;
secrets-exs = "/var/lib/pleroma/secrets.exs";
}

View File

@ -0,0 +1,6 @@
[
[ "selfprivacy", "domain" ],
[ "selfprivacy", "username" ],
[ "selfprivacy", "useBinds" ],
[ "selfprivacy", "modules", "pleroma" ]
]

View File

@ -0,0 +1,9 @@
{
description = "PoC SP module for Pleroma lightweight fediverse server";
outputs = { self }: {
nixosModules.default = import ./module.nix;
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
};
}

View File

@ -0,0 +1,131 @@
{ config, lib, pkgs, ... }:
let
secrets-filepath = "/etc/selfprivacy/secrets.json";
cfg = config.selfprivacy.modules.pleroma;
inherit (import ./common.nix config) secrets-exs sp;
in
{
options.selfprivacy.modules.pleroma = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
location = lib.mkOption {
type = lib.types.str;
};
subdomain = lib.mkOption {
default = "social";
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
};
};
config = lib.mkIf cfg.enable {
fileSystems = lib.mkIf sp.useBinds {
"/var/lib/pleroma" = {
device = "/volumes/${cfg.location}/pleroma";
options = [
"bind"
"x-systemd.required-by=pleroma-secrets.service"
"x-systemd.required-by=pleroma.service"
"x-systemd.before=pleroma.service"
"x-systemd.before=pleroma-secrets.service"
];
};
"/var/lib/postgresql" = {
device = "/volumes/${cfg.location}/postgresql";
options = [
"bind"
"x-systemd.required-by=pleroma-secrets.service"
"x-systemd.required-by=pleroma.service"
"x-systemd.before=pleroma-secrets.service"
"x-systemd.before=pleroma.service"
];
};
};
services = {
pleroma = {
enable = true;
user = "pleroma";
group = "pleroma";
configs = [
(builtins.replaceStrings
[ "$DOMAIN" "$LUSER" ]
[ sp.domain sp.username ]
(builtins.readFile ./config.exs.in))
];
};
postgresql = {
enable = true;
package = pkgs.postgresql_12;
initialScript = "/etc/setup.psql";
ensureDatabases = [
"pleroma"
];
ensureUsers = [
{
name = "pleroma";
ensureDBOwnership = true;
}
];
};
};
systemd.services.pleroma-secrets = {
before = [ "pleroma.service" ];
requiredBy = [ "pleroma.service" ];
serviceConfig.Type = "oneshot";
path = with pkgs; [ coreutils jq ];
script = ''
set -o nounset
password="$(jq -re '.databasePassword' ${secrets-filepath})"
filecontents=$(cat <<- EOF
import Config
config :pleroma, Pleroma.Repo,
password: "$password"
EOF
)
install -C -m 0700 -o pleroma -g pleroma -d /var/lib/pleroma
install -C -m 0600 -o pleroma -g pleroma -DT \
<(printf "%s" "$filecontents") ${secrets-exs}
'';
};
environment.etc."setup.psql".text = ''
CREATE USER pleroma;
CREATE DATABASE pleroma OWNER pleroma;
\c pleroma;
--Extensions made by ecto.migrate that need superuser access
CREATE EXTENSION IF NOT EXISTS citext;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
'';
users.users.pleroma = {
extraGroups = [ "postgres" ];
isNormalUser = false;
isSystemUser = true;
group = "pleroma";
};
# seems to be an upstream nixpkgs/nixos bug (missing hexdump)
systemd.services.pleroma.path = [ pkgs.util-linux ];
services.nginx.virtualHosts."${cfg.subdomain}.${sp.domain}" = {
useACMEHost = sp.domain;
root = "/var/www/${cfg.subdomain}.${sp.domain}";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:4000";
};
};
};
};
}

View File

@ -0,0 +1,16 @@
[
[ "mailserver" ],
[ "security", "acme", "certs" ],
[ "selfprivacy", "domain" ],
[ "selfprivacy", "hashedMasterPassword" ],
[ "selfprivacy", "useBinds" ],
[ "selfprivacy", "username" ],
[ "selfprivacy", "users" ],
[ "services", "dovecot2" ],
[ "services", "opendkim" ],
[ "services", "postfix", "group" ],
[ "services", "postfix", "user" ],
[ "services", "redis" ],
[ "services", "rspamd" ],
[ "selfprivacy", "modules", "simple-nixos-mailserver" ]
]

View File

@ -1,28 +1,30 @@
{ config, pkgs, lib, ... }:
{ config, lib, ... }:
let
cfg = config.services.userdata;
sp = config.selfprivacy;
in
lib.mkIf sp.modules.simple-nixos-mailserver.enable
{
imports = [
(builtins.fetchTarball {
# Pick a commit from the branch you are interested in
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/6d0d9fb9/nixos-mailserver-6d0d9fb9.tar.gz";
# And set its hash
sha256 = "sha256:0h35al73p15z9v8zb6hi5nq987sfl5wp4rm5c8947nlzlnsjl61x";
})
];
fileSystems = lib.mkIf cfg.useBinds {
"/var/vmail" = {
device = "/volumes/${cfg.email.location}/vmail";
options = [ "bind" ];
fileSystems = lib.mkIf sp.useBinds
{
"/var/vmail" = {
device =
"/volumes/${sp.modules.simple-nixos-mailserver.location}/vmail";
options = [
"bind"
"x-systemd.required-by=postfix.service"
"x-systemd.before=postfix.service"
];
};
"/var/sieve" = {
device =
"/volumes/${sp.modules.simple-nixos-mailserver.location}/sieve";
options = [
"bind"
"x-systemd.required-by=dovecot2.service"
"x-systemd.before=dovecot2.service"
];
};
};
"/var/sieve" = {
device = "/volumes/${cfg.email.location}/sieve";
options = [ "bind" ];
};
};
users.users = {
virtualMail = {
@ -30,16 +32,19 @@ in
};
};
users.groups.acmereceivers.members = [ "dovecot2" "postfix" "virtualMail" ];
mailserver = {
enable = true;
fqdn = cfg.domain;
domains = [ cfg.domain ];
fqdn = sp.domain;
domains = [ sp.domain ];
localDnsResolver = false;
# A list of all login accounts. To create the password hashes, use
# mkpasswd -m sha-512 "super secret password"
loginAccounts = {
"${cfg.username}@${cfg.domain}" = {
hashedPassword = cfg.hashedMasterPassword;
"${sp.username}@${sp.domain}" = {
hashedPassword = sp.hashedMasterPassword;
sieveScript = ''
require ["fileinto", "mailbox"];
if header :contains "Chat-Version" "1.0"
@ -51,7 +56,7 @@ in
};
} // builtins.listToAttrs (builtins.map
(user: {
name = "${user.username}@${cfg.domain}";
name = "${user.username}@${sp.domain}";
value = {
hashedPassword = user.hashedPassword;
sieveScript = ''
@ -64,15 +69,13 @@ in
'';
};
})
cfg.users);
sp.users);
extraVirtualAliases = {
"admin@${cfg.domain}" = "${cfg.username}@${cfg.domain}";
"admin@${sp.domain}" = "${sp.username}@${sp.domain}";
};
certificateScheme = 1;
certificateFile = "/var/lib/acme/${cfg.domain}/fullchain.pem";
keyFile = "/var/lib/acme/${cfg.domain}/key.pem";
certificateScheme = "acme";
# Enable IMAP and POP3
enableImap = true;

View File

@ -0,0 +1,126 @@
{
"nodes": {
"blobs": {
"flake": false,
"locked": {
"lastModified": 1604995301,
"narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=",
"owner": "simple-nixos-mailserver",
"repo": "blobs",
"rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"repo": "blobs",
"type": "gitlab"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"mailserver": {
"inputs": {
"blobs": "blobs",
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"nixpkgs-22_11": "nixpkgs-22_11",
"nixpkgs-23_05": "nixpkgs-23_05",
"utils": "utils"
},
"locked": {
"lastModified": 1700085753,
"narHash": "sha256-qtib7f3eRwfaUF+VziJXiBcZFqpHCAXS4HlrFsnzzl4=",
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"rev": "008d78cc21959e33d0d31f375b88353a7d7121ae",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"type": "gitlab"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1670751203,
"narHash": "sha256-XdoH1v3shKDGlrwjgrNX/EN8s3c+kQV7xY6cLCE8vcI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "64e0bf055f9d25928c31fb12924e59ff8ce71e60",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"nixpkgs-22_11": {
"locked": {
"lastModified": 1669558522,
"narHash": "sha256-yqxn+wOiPqe6cxzOo4leeJOp1bXE/fjPEi/3F/bBHv8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ce5fe99df1f15a09a91a86be9738d68fadfbad82",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-22.11",
"type": "indirect"
}
},
"nixpkgs-23_05": {
"locked": {
"lastModified": 1684782344,
"narHash": "sha256-SHN8hPYYSX0thDrMLMWPWYulK3YFgASOrCsIL3AJ78g=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8966c43feba2c701ed624302b6a935f97bcbdf88",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"mailserver": "mailserver"
}
},
"utils": {
"locked": {
"lastModified": 1605370193,
"narHash": "sha256-YyMTf3URDL/otKdKgtoMChu4vfVL3vCMkRqpGifhUn0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5021eac20303a61fafe17224c087f5519baed54d",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@ -0,0 +1,22 @@
{
description = "PoC SP module for the simple-nixos-mailserver";
inputs.mailserver.url =
gitlab:simple-nixos-mailserver/nixos-mailserver;
outputs = { self, mailserver }: {
nixosModules.default = _: {
imports = [
mailserver.nixosModules.default
./options.nix
./config.nix
];
};
configPathsNeeded =
builtins.fromJSON (builtins.readFile ./config-paths-needed.json);
# TODO generate json docs from module? something like:
# nix eval --impure --expr 'let flake = builtins.getFlake (builtins.toPath ./.); pkgs = flake.inputs.mailserver.inputs.nixpkgs.legacyPackages.x86_64-linux; in (pkgs.nixosOptionsDoc { inherit (pkgs.lib.evalModules { modules = [ flake.nixosModules.default ]; }) options; }).optionsJSON'
# (doesn't work because of `assertions`)
};
}

View File

@ -0,0 +1,12 @@
{ lib, ... }:
{
options.selfprivacy.modules.simple-nixos-mailserver = {
enable = lib.mkOption {
default = false;
type = lib.types.bool;
};
location = lib.mkOption {
type = lib.types.str;
};
};
}

View File

@ -1,190 +0,0 @@
{
"$schema": "http://json-schema.org/schema#",
"$id": "https://git.selfprivacy.org/inex/selfprivacy-nixos-config/raw/branch/master/userdata/schema.json",
"type": "object",
"properties": {
"autoUpgrade": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
},
"allowReboot": {
"type": "boolean"
}
}
},
"hostname": {
"type": "string"
},
"domain": {
"type": "string"
},
"username": {
"type": "string"
},
"hashedMasterPassword": {
"type": "string"
},
"sshKeys": {
"type": "array",
"items": {
"type": "string"
}
},
"timezone": {
"type": "string"
},
"api": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"enableSwagger": {
"type": "boolean"
},
"skippedMigrations": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"backblaze": {
"type": "object",
"properties": {
"bucket": {
"type": "string"
},
"accountId": {
"type": "string"
},
"accountKey": {
"type": "string"
}
},
"required": ["bucket", "accountId", "accountKey"]
},
"cloudflare": {
"type": "object",
"properties": {
"apiKey": {
"type": "string"
}
},
"required": ["apiKey"]
},
"databasePassword": {
"type": "string"
},
"bitwarden": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"gitea": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"nextcloud": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
},
"databasePassword": {
"type": "string"
},
"adminPassword": {
"type": "string"
}
},
"required": ["databasePassword", "adminPassword"]
},
"pleroma": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"jitsi": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"ocserv": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"resticPassword": {
"type": "string"
},
"ssh": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
},
"rootKeys": {
"type": "array",
"items": {
"type": "string"
}
},
"passwordAuthentication": {
"type": "boolean"
}
}
},
"users": {
"type": "array",
"items": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"hashedPassword": {
"type": "string"
},
"sshKeys": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["username", "hashedPassword"]
}
}
},
"required": [
"hostname",
"domain",
"username",
"hashedMasterPassword",
"backblaze",
"cloudflare",
"databasePassword",
"nextcloud",
"resticPassword"
]
}

View File

@ -1,72 +0,0 @@
{
"$schema": "http://json-schema.org/schema#",
"$id": "https://git.selfprivacy.org/inex/selfprivacy-nixos-config/raw/branch/master/userdata/tokens_schema.json",
"type": "object",
"properties": {
"tokens": {
"type": "array",
"items": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"name": {
"type": "string"
},
"date": {
"type": "string"
}
},
"required": [
"token",
"name",
"date"
]
}
},
"recovery_token": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"date": {
"type": "string"
},
"expiration": {
"type": "string"
},
"uses_left": {
"type": "integer"
}
},
"required": [
"token",
"date"
]
},
"new_device": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"date": {
"type": "string"
},
"expiration": {
"type": "string"
}
},
"required": [
"token",
"date",
"expiration"
]
}
},
"required": [
"tokens"
]
}

View File

@ -1,10 +1,11 @@
{ pkgs, config, ... }:
{ config, ... }:
let
cfg = config.services.userdata;
cfg = config.selfprivacy;
in
{
users.mutableUsers = false;
users = {
mutableUsers = false;
allowNoPasswordLogin = true;
users = {
"${cfg.username}" = {
isNormalUser = true;

View File

@ -1,66 +0,0 @@
{ pkgs, lib, ... }:
let
jsonData = builtins.fromJSON (builtins.readFile ./userdata/userdata.json);
in
{
services.userdata = {
hostname = lib.attrsets.attrByPath [ "hostname" ] null jsonData;
domain = lib.attrsets.attrByPath [ "domain" ] null jsonData;
timezone = lib.attrsets.attrByPath [ "timezone" ] "Europe/Uzhgorod" jsonData;
stateVersion = lib.attrsets.attrByPath [ "stateVersion" ] "22.05" jsonData;
autoUpgrade = {
enable = lib.attrsets.attrByPath [ "autoUpgrade" "enable" ] true jsonData;
allowReboot = lib.attrsets.attrByPath [ "autoUpgrade" "allowReboot" ] true jsonData;
};
username = lib.attrsets.attrByPath [ "username" ] null jsonData;
hashedMasterPassword = lib.attrsets.attrByPath [ "hashedMasterPassword" ] null jsonData;
sshKeys = lib.attrsets.attrByPath [ "sshKeys" ] [ ] jsonData;
api = {
enableSwagger = lib.attrsets.attrByPath [ "api" "enableSwagger" ] false jsonData;
skippedMigrations = lib.attrsets.attrByPath [ "api" "skippedMigrations" ] [ ] jsonData;
};
dns = {
provider = lib.attrsets.attrByPath [ "dns" "provider" ] "CLOUDFLARE" jsonData;
useStagingACME = lib.attrsets.attrByPath [ "dns" "useStagingACME" ] false jsonData;
};
backup = {
bucket = lib.attrsets.attrByPath [ "backup" "bucket" ] (lib.attrsets.attrByPath [ "backblaze" "bucket" ] "" jsonData) jsonData;
};
server = {
provider = lib.attrsets.attrByPath [ "server" "provider" ] "HETZNER" jsonData;
};
bitwarden = {
enable = lib.attrsets.attrByPath [ "bitwarden" "enable" ] false jsonData;
location = lib.attrsets.attrByPath [ "bitwarden" "location" ] "sda1" jsonData;
};
gitea = {
enable = lib.attrsets.attrByPath [ "gitea" "enable" ] false jsonData;
location = lib.attrsets.attrByPath [ "gitea" "location" ] "sda1" jsonData;
};
nextcloud = {
enable = lib.attrsets.attrByPath [ "nextcloud" "enable" ] false jsonData;
location = lib.attrsets.attrByPath [ "nextcloud" "location" ] "sda1" jsonData;
};
pleroma = {
enable = lib.attrsets.attrByPath [ "pleroma" "enable" ] false jsonData;
location = lib.attrsets.attrByPath [ "pleroma" "location" ] "sda1" jsonData;
};
jitsi = {
enable = lib.attrsets.attrByPath [ "jitsi" "enable" ] false jsonData;
};
ocserv = {
enable = lib.attrsets.attrByPath [ "ocserv" "enable" ] false jsonData;
};
ssh = {
enable = lib.attrsets.attrByPath [ "ssh" "enable" ] true jsonData;
rootKeys = lib.attrsets.attrByPath [ "ssh" "rootKeys" ] [ "" ] jsonData;
passwordAuthentication = lib.attrsets.attrByPath [ "ssh" "passwordAuthentication" ] true jsonData;
};
email = {
location = lib.attrsets.attrByPath [ "email" "location" ] "sda1" jsonData;
};
users = lib.attrsets.attrByPath [ "users" ] [ ] jsonData;
volumes = lib.attrsets.attrByPath [ "volumes" ] [ ] jsonData;
useBinds = lib.attrsets.attrByPath [ "useBinds" ] false jsonData;
};
}

View File

@ -1,15 +0,0 @@
{ pkgs, config, ... }:
let
domain = config.services.userdata.domain;
in
{
services.jitsi-meet = {
enable = config.services.userdata.jitsi.enable;
hostName = "meet.${domain}";
nginx.enable = true;
interfaceConfig = {
SHOW_JITSI_WATERMARK = false;
SHOW_WATERMARK_FOR_GUESTS = false;
};
};
}

View File

@ -1,9 +1,9 @@
{ pkgs, config, ... }:
{ config, ... }:
let
cfg = config.services.userdata;
cfg = config.selfprivacy;
in
{
fileSystems = { } // builtins.listToAttrs (builtins.map
fileSystems = builtins.listToAttrs (builtins.map
(volume: {
name = "${volume.mountPoint}";
value = {

View File

@ -1,52 +0,0 @@
{ pkgs, config, ... }:
let
domain = config.services.userdata.domain;
in
{
users.groups.ocserv = {
members = [ "ocserv" ];
};
users.users.ocserv = {
isNormalUser = false;
isSystemUser = true;
extraGroups = [ "ocserv" "acmerecievers" ];
group = "ocserv";
};
services.ocserv = {
enable = config.services.userdata.ocserv.enable;
config = ''
socket-file = /var/run/ocserv-socket
auth = "pam"
tcp-port = 8443
udp-port = 8443
server-cert = /var/lib/acme/${domain}/fullchain.pem
server-key = /var/lib/acme/${domain}/key.pem
compression = true
max-clients = 0
max-same-clients = 6
try-mtu-discovery = true
idle-timeout=1200
mobile-idle-timeout=2400
default-domain = vpn.${domain}
device = vpn0
ipv4-network = 10.10.10.0
ipv4-netmask = 255.255.255.0
tunnel-all-dns = true
dns = 1.1.1.1
dns = 1.0.0.1
route = default
'';
};
}

View File

@ -1,6 +1,6 @@
{ pkgs, config, lib, ... }:
{ config, lib, ... }:
let
domain = config.services.userdata.domain;
domain = config.selfprivacy.domain;
in
{
services.nginx = {
@ -16,42 +16,12 @@ in
map $scheme $hsts_header {
https "max-age=31536000; includeSubdomains; preload";
}
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 512;
'';
virtualHosts = {
"${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
};
"vpn.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
};
"git.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
useACMEHost = domain;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
@ -65,53 +35,12 @@ in
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:3000";
};
};
};
"cloud.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:80/";
};
};
};
"password.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:8222";
root = "/var/www/root";
};
};
};
"api.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
useACMEHost = domain;
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
@ -130,27 +59,9 @@ in
};
};
};
"social.${domain}" = {
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
root = "/var/www/social.${domain}";
forceSSL = true;
extraConfig = ''
add_header Strict-Transport-Security $hsts_header;
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
add_header 'Referrer-Policy' 'origin-when-cross-origin';
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
expires 10m;
'';
locations = {
"/" = {
proxyPass = "http://127.0.0.1:4000";
};
};
};
};
};
systemd.tmpfiles.rules = [
"d /var/www/root 0750 nginx nginx - -"
];
}