Compare commits
92 Commits
Author | SHA1 | Date |
---|---|---|
Inex Code | 40f92d15d3 | |
Inex Code | 2c2bb80006 | |
Alexander Tomokhov | 5685a9e128 | |
Inex Code | f8befb0e3d | |
Inex Code | 1464d7f3bd | |
Inex Code | d02524bb8f | |
Inex Code | 23155b3c96 | |
Inex Code | 6c07cc024b | |
Inex Code | 5710f5892b | |
Inex Code | 325dc40f34 | |
Inex Code | 25d7bc6ec5 | |
Inex Code | 29b855818d | |
Inex Code | e0ad80b4ca | |
Inex Code | e8a25ec565 | |
Inex Code | d41cf6a4db | |
Inex Code | 2f0107ce3b | |
Inex Code | 8f72f60286 | |
Inex Code | 58e4f3acd8 | |
Inex Code | 65b5a19777 | |
Inex Code | 60dd766846 | |
Inex Code | 8006f83257 | |
Inex Code | 74d35b16f2 | |
Inex Code | dd020c3a7d | |
Inex Code | ba1695c642 | |
Inex Code | bc5778fdea | |
Inex Code | 8d99d1c78a | |
Inex Code | 5e64b08381 | |
Inex Code | 7e590ae60c | |
Inex Code | eb36e9b265 | |
Inex Code | 3626506e3a | |
Inex Code | c8c69957b5 | |
Inex Code | 9a8af62e0b | |
Inex Code | a5b965f08f | |
Inex Code | d7edf5a95d | |
Inex Code | bdaf88208f | |
Inex Code | 2e175f8c10 | |
Inex Code | 497cf28ecc | |
Inex Code | 9c662d9629 | |
Inex Code | 0500315ae0 | |
Inex Code | d8f0922b8a | |
Inex Code | ab0c3e113c | |
Inex Code | b4827e6e26 | |
Inex Code | bfe0d18090 | |
Inex Code | 426d84f636 | |
sоvд[сова] | 41edc9f26f | |
sоvд[сова] | 5d3395648a | |
Inex Code | 1944739d28 | |
Inex Code | 08d8407a86 | |
Inex Code | 0d3e8c890c | |
Inex Code | 3dd8ff1821 | |
Inex Code | 895a816ef5 | |
Inex Code | 5210e610df | |
Inex Code | eab3d1e761 | |
Inex Code | a59fbef22a | |
Inex Code | 7a6f57def8 | |
Inex Code | e4ba827d5a | |
Inex Code | aeeffe42b1 | |
Inex Code | 399790e202 | |
Inex Code | 5f2ab0495b | |
Inex Code | 53c9655b7b | |
Inex Code | 52b896da45 | |
Inex Code | 8c81f24fa7 | |
Inex Code | c1ed3a522c | |
NaiJi ✨ | dbb6757d77 | |
NaiJi ✨ | 0c41badf3b | |
NaiJi ✨ | 23e424b841 | |
Inex Code | 67851c7bee | |
Inex Code | 5b4128c010 | |
Inex Code | f6b3c26900 | |
Inex Code | 9d1249d10e | |
Inex Code | ea7572c4e9 | |
Inex Code | a5b57d378d | |
Inex Code | 289b715873 | |
Inex Code | 1a31e32424 | |
Inex Code | cb6378a970 | |
Inex Code | 4bf80d7a2d | |
Inex Code | a0a6c99fe8 | |
Inex Code | 8cb55168eb | |
Illia Chub | 896600bf52 | |
Illia Chub | c03fd25959 | |
Inex Code | b583340e1d | |
Inex Code | dc767677d8 | |
Illia Chub | 163afde7cf | |
Inex Code | d4bb381693 | |
Inex Code | c3ee4d00fc | |
Illia Chub | f5ec301441 | |
Illia Chub | ae8e8b2c9b | |
Illia Chub | b7f49e52c0 | |
Illia Chub | b5011cdd65 | |
Inex Code | 1b8bdb013a | |
Inex Code | 3f42ad5c68 | |
Inex Code | 63aaeec08c |
|
@ -1,3 +1,5 @@
|
||||||
userdata/userdata.json
|
userdata/userdata.json
|
||||||
|
userdata/tokens.json
|
||||||
hardware-configuration.nix
|
hardware-configuration.nix
|
||||||
networking.nix
|
networking.nix
|
||||||
|
/result
|
||||||
|
|
|
@ -12,49 +12,12 @@ in
|
||||||
{
|
{
|
||||||
options.services.selfprivacy-api = {
|
options.services.selfprivacy-api = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
default = false;
|
default = true;
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = ''
|
description = ''
|
||||||
Enable SelfPrivacy API service
|
Enable SelfPrivacy API service
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
token = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
SelfPrivacy API token
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
enableSwagger = mkOption {
|
|
||||||
default = false;
|
|
||||||
type = types.bool;
|
|
||||||
description = ''
|
|
||||||
Enable Swagger UI
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
b2AccountId = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
B2 account ID
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
b2AccountKey = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
B2 account key
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
b2Bucket = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
B2 bucket
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
resticPassword = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
Restic password
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
@ -64,19 +27,67 @@ in
|
||||||
inherit (config.environment.sessionVariables) NIX_PATH;
|
inherit (config.environment.sessionVariables) NIX_PATH;
|
||||||
HOME = "/root";
|
HOME = "/root";
|
||||||
PYTHONUNBUFFERED = "1";
|
PYTHONUNBUFFERED = "1";
|
||||||
AUTH_TOKEN = cfg.token;
|
|
||||||
ENABLE_SWAGGER = (if cfg.enableSwagger then "1" else "0");
|
|
||||||
B2_ACCOUNT_ID = cfg.b2AccountId;
|
|
||||||
B2_ACCOUNT_KEY = cfg.b2AccountKey;
|
|
||||||
B2_BUCKET = cfg.b2Bucket;
|
|
||||||
RESTIC_PASSWORD = cfg.resticPassword;
|
|
||||||
} // config.networking.proxy.envVars;
|
} // 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 ];
|
path = [
|
||||||
|
"/var/"
|
||||||
|
"/var/dkim/"
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.gnutar
|
||||||
|
pkgs.xz.bin
|
||||||
|
pkgs.gzip
|
||||||
|
pkgs.gitMinimal
|
||||||
|
config.nix.package.out
|
||||||
|
pkgs.nixos-rebuild
|
||||||
|
pkgs.rclone
|
||||||
|
pkgs.restic
|
||||||
|
pkgs.mkpasswd
|
||||||
|
pkgs.util-linux
|
||||||
|
pkgs.e2fsprogs
|
||||||
|
pkgs.iproute2
|
||||||
|
pkgs.fuse-overlayfs
|
||||||
|
pkgs.fuse
|
||||||
|
];
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
wantedBy = [ "network-online.target" ];
|
wantedBy = [ "network-online.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = "root";
|
User = "root";
|
||||||
ExecStart = "${pkgs.selfprivacy-api}/bin/app.py";
|
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";
|
||||||
|
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.rclone
|
||||||
|
pkgs.restic
|
||||||
|
pkgs.mkpasswd
|
||||||
|
pkgs.util-linux
|
||||||
|
pkgs.e2fsprogs
|
||||||
|
pkgs.iproute2
|
||||||
|
pkgs.fuse-overlayfs
|
||||||
|
pkgs.fuse
|
||||||
|
];
|
||||||
|
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";
|
Restart = "always";
|
||||||
RestartSec = "5";
|
RestartSec = "5";
|
||||||
};
|
};
|
||||||
|
@ -92,6 +103,8 @@ in
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = "root";
|
User = "root";
|
||||||
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch";
|
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch";
|
||||||
|
KillMode = "none";
|
||||||
|
SendSIGKILL = "no";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# One shot systemd service to upgrade NixOS using nixos-rebuild
|
# One shot systemd service to upgrade NixOS using nixos-rebuild
|
||||||
|
@ -105,6 +118,8 @@ in
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = "root";
|
User = "root";
|
||||||
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --upgrade";
|
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --upgrade";
|
||||||
|
KillMode = "none";
|
||||||
|
SendSIGKILL = "no";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# One shot systemd service to rollback NixOS using nixos-rebuild
|
# One shot systemd service to rollback NixOS using nixos-rebuild
|
||||||
|
@ -118,6 +133,8 @@ in
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = "root";
|
User = "root";
|
||||||
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --rollback";
|
ExecStart = "${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --rollback";
|
||||||
|
KillMode = "none";
|
||||||
|
SendSIGKILL = "no";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,18 +2,13 @@
|
||||||
{
|
{
|
||||||
services.selfprivacy-api = {
|
services.selfprivacy-api = {
|
||||||
enable = true;
|
enable = true;
|
||||||
token = config.services.userdata.api.token;
|
|
||||||
enableSwagger = config.services.userdata.api.enableSwagger;
|
|
||||||
b2AccountId = config.services.userdata.backblaze.accountId;
|
|
||||||
b2AccountKey = config.services.userdata.backblaze.accountKey;
|
|
||||||
b2Bucket = config.services.userdata.backblaze.bucket;
|
|
||||||
resticPassword = config.services.userdata.resticPassword;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users."selfprivacy-api" = {
|
users.users."selfprivacy-api" = {
|
||||||
isNormalUser = false;
|
isNormalUser = false;
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
extraGroups = [ "opendkim" ];
|
extraGroups = [ "opendkim" ];
|
||||||
|
group = "selfprivacy-api";
|
||||||
};
|
};
|
||||||
users.groups."selfprivacy-api" = {
|
users.groups."selfprivacy-api" = {
|
||||||
members = [ "selfprivacy-api" ];
|
members = [ "selfprivacy-api" ];
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
{ config, pkgs, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.services.userdata;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
services.restic.backups = {
|
|
||||||
options = {
|
|
||||||
passwordFile = "/etc/restic/resticPasswd";
|
|
||||||
repository = "s3:s3.anazonaws.com/${cfg.backblaze.bucket}";
|
|
||||||
initialize = true;
|
|
||||||
paths = [
|
|
||||||
"/var/dkim"
|
|
||||||
"/var/vmail"
|
|
||||||
];
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = [ "daily" ];
|
|
||||||
};
|
|
||||||
user = "restic";
|
|
||||||
pruneOpts = [
|
|
||||||
"--keep-daily 5"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
users.users.restic = {
|
|
||||||
isNormalUser = false;
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
environment.etc."restic/resticPasswd".text = ''
|
|
||||||
${cfg.resticPassword}
|
|
||||||
'';
|
|
||||||
environment.etc."restic/s3Passwd".text = ''
|
|
||||||
AWS_ACCESS_KEY_ID=${cfg.backblaze.accountId}
|
|
||||||
AWS_SECRET_ACCESS_KEY=${cfg.backblaze.accountKey}
|
|
||||||
'';
|
|
||||||
}
|
|
|
@ -1,25 +1,23 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
url-overlay = "https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nix-repo/archive/master.tar.gz";
|
url-overlay = "https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nix-repo/archive/test-migration.tar.gz";
|
||||||
nix-overlay = (import (builtins.fetchTarball url-overlay));
|
nix-overlay = (import (builtins.fetchTarball url-overlay));
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
|
|
||||||
./variables-module.nix
|
./variables-module.nix
|
||||||
./variables.nix
|
./variables.nix
|
||||||
./files.nix
|
./files.nix
|
||||||
|
./volumes.nix
|
||||||
./users.nix
|
./users.nix
|
||||||
./mailserver/system/mailserver.nix
|
./mailserver/system/mailserver.nix
|
||||||
./mailserver/system/alps.nix
|
|
||||||
./vpn/ocserv.nix
|
./vpn/ocserv.nix
|
||||||
./api/api.nix
|
./api/api.nix
|
||||||
./api/api-module.nix
|
./api/api-module.nix
|
||||||
./social/pleroma.nix
|
./social/pleroma.nix
|
||||||
./letsencrypt/acme.nix
|
./letsencrypt/acme.nix
|
||||||
./letsencrypt/resolve.nix
|
./letsencrypt/resolve.nix
|
||||||
./backup/restic.nix
|
|
||||||
./passmgr/bitwarden.nix
|
./passmgr/bitwarden.nix
|
||||||
./webserver/nginx.nix
|
./webserver/nginx.nix
|
||||||
./webserver/memcached.nix
|
./webserver/memcached.nix
|
||||||
|
@ -31,12 +29,37 @@ in
|
||||||
|
|
||||||
nixpkgs.overlays = [ (nix-overlay) ];
|
nixpkgs.overlays = [ (nix-overlay) ];
|
||||||
|
|
||||||
|
services.redis.servers.sp-api = {
|
||||||
|
enable = true;
|
||||||
|
save = [
|
||||||
|
[
|
||||||
|
30
|
||||||
|
1
|
||||||
|
]
|
||||||
|
[
|
||||||
|
10
|
||||||
|
10
|
||||||
|
]
|
||||||
|
];
|
||||||
|
port = 0;
|
||||||
|
settings = {
|
||||||
|
notify-keyspace-events = "KEA";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.do-agent.enable = if config.services.userdata.server.provider == "DIGITALOCEAN" then true else false;
|
||||||
|
|
||||||
boot.cleanTmpDir = true;
|
boot.cleanTmpDir = true;
|
||||||
networking = {
|
networking = {
|
||||||
hostName = config.services.userdata.hostname;
|
hostName = config.services.userdata.hostname;
|
||||||
|
usePredictableInterfaceNames = false;
|
||||||
firewall = {
|
firewall = {
|
||||||
allowedTCPPorts = lib.mkForce [ 22 25 80 143 443 465 587 993 8443 ];
|
allowedTCPPorts = lib.mkForce [ 22 25 80 143 443 465 587 993 4443 8443 ];
|
||||||
allowedUDPPorts = lib.mkForce [ 8443 ];
|
allowedUDPPorts = lib.mkForce [ 8443 10000 ];
|
||||||
|
extraCommands = ''
|
||||||
|
iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE
|
||||||
|
iptables --append FORWARD --in-interface vpn00 -j ACCEPT
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
nameservers = [ "1.1.1.1" "1.0.0.1" ];
|
nameservers = [ "1.1.1.1" "1.0.0.1" ];
|
||||||
};
|
};
|
||||||
|
@ -50,25 +73,33 @@ in
|
||||||
openFirewall = false;
|
openFirewall = false;
|
||||||
};
|
};
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
pubkeyAcceptedKeyTypes = [ "ssh-ed25519" "ssh-rsa" ];
|
pubkeyAcceptedKeyTypes = [ "ssh-ed25519" "ssh-rsa" "ecdsa-sha2-nistp256" ];
|
||||||
hostKeyAlgorithms = [ "ssh-ed25519" "ssh-rsa" ];
|
hostKeyAlgorithms = [ "ssh-ed25519" "ssh-rsa" ];
|
||||||
};
|
};
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
git
|
git
|
||||||
|
jq
|
||||||
];
|
];
|
||||||
environment.variables = {
|
environment.variables = {
|
||||||
DOMAIN = config.services.userdata.domain;
|
DOMAIN = config.services.userdata.domain;
|
||||||
};
|
};
|
||||||
system.autoUpgrade.enable = config.services.userdata.autoUpgrade.enable;
|
system.autoUpgrade = {
|
||||||
system.autoUpgrade.allowReboot = config.services.userdata.autoUpgrade.allowReboot;
|
enable = config.services.userdata.autoUpgrade.enable;
|
||||||
system.autoUpgrade.channel = https://nixos.org/channels/nixos-21.05-small;
|
allowReboot = config.services.userdata.autoUpgrade.allowReboot;
|
||||||
|
channel = "https://channel.selfprivacy.org/nixos-selfpricacy";
|
||||||
|
};
|
||||||
|
system.stateVersion = config.services.userdata.stateVersion;
|
||||||
nix = {
|
nix = {
|
||||||
optimise.automatic = true;
|
optimise.automatic = true;
|
||||||
gc = {
|
gc = {
|
||||||
automatic = true;
|
automatic = true;
|
||||||
options = "--delete-older-than 7d";
|
options = "--delete-older-than 7d";
|
||||||
};
|
};
|
||||||
|
extraOptions = ''
|
||||||
|
experimental-features = nix-command flakes repl-flake
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
services.journald.extraConfig = "SystemMaxUse=500M";
|
||||||
boot.kernel.sysctl = {
|
boot.kernel.sysctl = {
|
||||||
"net.ipv4.ip_forward" = 1;
|
"net.ipv4.ip_forward" = 1;
|
||||||
};
|
};
|
||||||
|
|
102
files.nix
102
files.nix
|
@ -1,37 +1,89 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
|
dnsCredentialsTemplates = {
|
||||||
|
DIGITALOCEAN = "DO_AUTH_TOKEN=REPLACEME";
|
||||||
|
CLOUDFLARE = ''
|
||||||
|
CF_API_KEY=REPLACEME
|
||||||
|
CLOUDFLARE_DNS_API_TOKEN=REPLACEME
|
||||||
|
CLOUDFLARE_ZONE_API_TOKEN=REPLACEME
|
||||||
|
'';
|
||||||
|
DESEC = "DESEC_TOKEN=REPLACEME";
|
||||||
|
};
|
||||||
|
dnsCredentialsTemplate = dnsCredentialsTemplates.${cfg.dns.provider};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
systemd.tmpfiles.rules =
|
systemd.tmpfiles.rules =
|
||||||
let
|
let
|
||||||
nextcloudDBPass = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] cfg.nextcloud.databasePassword;
|
domain = builtins.replaceStrings [ "\n" "\"" "\\" "%" ] [ "\\n" "\\\"" "\\\\" "%%" ] cfg.domain;
|
||||||
nextcloudAdminPass = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] cfg.nextcloud.adminPassword;
|
|
||||||
resticPass = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] cfg.resticPassword;
|
|
||||||
domain = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] cfg.domain;
|
|
||||||
cloudflareCredentials = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] ''
|
|
||||||
CF_API_KEY=${cfg.cloudflare.apiKey}
|
|
||||||
CLOUDFLARE_DNS_API_TOKEN=${cfg.cloudflare.apiKey}
|
|
||||||
CLOUDFLARE_ZONE_API_TOKEN=${cfg.cloudflare.apiKey}
|
|
||||||
'';
|
|
||||||
rcloneConfig = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] ''
|
|
||||||
[backblaze]
|
|
||||||
type = b2
|
|
||||||
account = ${cfg.backblaze.accountId}
|
|
||||||
key = ${cfg.backblaze.accountKey}
|
|
||||||
'';
|
|
||||||
in
|
in
|
||||||
[
|
[
|
||||||
(if cfg.bitwarden.enable then "d /var/lib/bitwarden 0777 bitwarden_rs bitwarden_rs -" else "")
|
(if cfg.bitwarden.enable then "d /var/lib/bitwarden 0770 vaultwarden vaultwarden -" else "")
|
||||||
(if cfg.bitwarden.enable then "d /var/lib/bitwarden/backup 0777 bitwarden_rs bitwarden_rs -" else "")
|
(if cfg.bitwarden.enable then "d /var/lib/bitwarden/backup 0770 vaultwarden vaultwarden -" else "")
|
||||||
(if cfg.pleroma.enable then "d /var/lib/pleroma 0600 pleroma pleroma - -" 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 0750 pleroma pleroma - -" else "")
|
||||||
"f+ /var/lib/restic/pass 0400 restic - - ${resticPass}"
|
|
||||||
"f+ /root/.config/rclone/rclone.conf 0400 root root - ${rcloneConfig}"
|
|
||||||
(if cfg.pleroma.enable then "f+ /var/lib/pleroma/secrets.exs 0755 pleroma pleroma - -" else "")
|
|
||||||
"f+ /var/domain 0444 selfprivacy-api selfprivacy-api - ${domain}"
|
"f+ /var/domain 0444 selfprivacy-api selfprivacy-api - ${domain}"
|
||||||
(if cfg.nextcloud.enable then "f+ /var/lib/nextcloud/db-pass 0440 nextcloud nextcloud - ${nextcloudDBPass}" else "")
|
(if cfg.bitwarden.enable then "f /var/lib/bitwarden/.env 0640 vaultwarden vaultwarden - -" else "")
|
||||||
(if cfg.nextcloud.enable then "f+ /var/lib/nextcloud/admin-pass 0440 nextcloud nextcloud - ${nextcloudAdminPass}" else "")
|
"d /var/sieve 0770 virtualMail virtualMail - -"
|
||||||
"f+ /var/lib/cloudflare/Credentials.ini 0440 nginx acmerecievers - ${cloudflareCredentials}"
|
"d /var/www/root 0750 nginx nginx - -"
|
||||||
];
|
];
|
||||||
|
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 '${dnsCredentialsTemplate}' > /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
|
||||||
|
'';
|
||||||
|
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
|
||||||
|
'';
|
||||||
|
bitwardenCredentials =
|
||||||
|
if cfg.bitwarden.enable then ''
|
||||||
|
mkdir -p /var/lib/bitwarden
|
||||||
|
token=$(cat /etc/nixos/userdata/userdata.json | ${jq} -r '.bitwarden.adminToken')
|
||||||
|
if [ "$token" == "null" ]; then
|
||||||
|
# If it's null, delete the contents of the file
|
||||||
|
> /var/lib/bitwarden/.env
|
||||||
|
else
|
||||||
|
echo "ADMIN_TOKEN=$token" > /var/lib/bitwarden/.env
|
||||||
|
fi
|
||||||
|
chmod 0640 /var/lib/bitwarden/.env
|
||||||
|
chown vaultwarden:vaultwarden /var/lib/bitwarden/.env
|
||||||
|
'' else ''
|
||||||
|
rm -f /var/lib/bitwarden/.env
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
fileSystems = lib.mkIf cfg.useBinds {
|
||||||
|
"/var/lib/gitea" = {
|
||||||
|
device = "/volumes/${cfg.gitea.location}/gitea";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
services = {
|
services = {
|
||||||
gitea = {
|
gitea = {
|
||||||
enable = cfg.gitea.enable;
|
enable = cfg.gitea.enable;
|
||||||
stateDir = "/var/lib/gitea";
|
stateDir = "/var/lib/gitea";
|
||||||
log = {
|
# log = {
|
||||||
rootPath = "/var/lib/gitea/log";
|
# rootPath = "/var/lib/gitea/log";
|
||||||
level = "Warn";
|
# level = "Warn";
|
||||||
};
|
# };
|
||||||
user = "gitea";
|
user = "gitea";
|
||||||
database = {
|
database = {
|
||||||
type = "sqlite3";
|
type = "sqlite3";
|
||||||
|
@ -20,10 +26,10 @@ in
|
||||||
path = "/var/lib/gitea/data/gitea.db";
|
path = "/var/lib/gitea/data/gitea.db";
|
||||||
createDatabase = true;
|
createDatabase = true;
|
||||||
};
|
};
|
||||||
ssh = {
|
# ssh = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
clonePort = 22;
|
# clonePort = 22;
|
||||||
};
|
# };
|
||||||
lfs = {
|
lfs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
contentDir = "/var/lib/gitea/lfs";
|
contentDir = "/var/lib/gitea/lfs";
|
||||||
|
@ -31,16 +37,17 @@ in
|
||||||
appName = "SelfPrivacy git Service";
|
appName = "SelfPrivacy git Service";
|
||||||
repositoryRoot = "/var/lib/gitea/repositories";
|
repositoryRoot = "/var/lib/gitea/repositories";
|
||||||
domain = "git.${cfg.domain}";
|
domain = "git.${cfg.domain}";
|
||||||
rootUrl = "https://${cfg.domain}/";
|
rootUrl = "https://git.${cfg.domain}/";
|
||||||
httpAddress = "0.0.0.0";
|
httpAddress = "0.0.0.0";
|
||||||
httpPort = 3000;
|
httpPort = 3000;
|
||||||
cookieSecure = true;
|
# cookieSecure = true;
|
||||||
settings = {
|
settings = {
|
||||||
mailer = {
|
mailer = {
|
||||||
ENABLED = false;
|
ENABLED = false;
|
||||||
};
|
};
|
||||||
ui = {
|
ui = {
|
||||||
DEFAULT_THEME = "arc-green";
|
DEFAULT_THEME = "arc-green";
|
||||||
|
SHOW_USER_EMAIL = false;
|
||||||
};
|
};
|
||||||
picture = {
|
picture = {
|
||||||
DISABLE_GRAVATAR = true;
|
DISABLE_GRAVATAR = true;
|
||||||
|
@ -51,6 +58,13 @@ in
|
||||||
repository = {
|
repository = {
|
||||||
FORCE_PRIVATE = false;
|
FORCE_PRIVATE = false;
|
||||||
};
|
};
|
||||||
|
session = {
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
};
|
||||||
|
log = {
|
||||||
|
ROOT_PATH = "/var/lib/gitea/log";
|
||||||
|
LEVEL = "Warn";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
|
dnsPropagationCheckExceptions = [ "DIGITALOCEAN" ];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
users.groups.acmerecievers = {
|
users.groups.acmerecievers = {
|
||||||
|
@ -8,15 +9,24 @@ in
|
||||||
};
|
};
|
||||||
security.acme = {
|
security.acme = {
|
||||||
acceptTerms = true;
|
acceptTerms = true;
|
||||||
email = "${cfg.username}@${cfg.domain}";
|
defaults = {
|
||||||
certs = {
|
email = "${cfg.username}@${cfg.domain}";
|
||||||
"${cfg.domain}" = {
|
server = if cfg.dns.useStagingACME then "https://acme-staging-v02.api.letsencrypt.org/directory" else "https://acme-v02.api.letsencrypt.org/directory";
|
||||||
|
dnsPropagationCheck = if lib.elem cfg.dns.provider dnsPropagationCheckExceptions then false else true;
|
||||||
|
reloadServices = [ "nginx" ];
|
||||||
|
};
|
||||||
|
certs = lib.mkForce {
|
||||||
|
"wildcard-${cfg.domain}" = {
|
||||||
domain = "*.${cfg.domain}";
|
domain = "*.${cfg.domain}";
|
||||||
extraDomainNames = [ "${cfg.domain}" ];
|
|
||||||
group = "acmerecievers";
|
group = "acmerecievers";
|
||||||
dnsProvider = "cloudflare";
|
dnsProvider = lib.strings.toLower cfg.dns.provider;
|
||||||
credentialsFile = "/var/lib/cloudflare/Credentials.ini";
|
credentialsFile = "/var/lib/cloudflare/Credentials.ini";
|
||||||
};
|
};
|
||||||
|
"${cfg.domain}" = {
|
||||||
|
domain = cfg.domain;
|
||||||
|
group = "acmerecievers";
|
||||||
|
webroot = "/var/lib/acme/acme-challenge";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,6 @@ in
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"nginx-config-reload" = {
|
|
||||||
serviceConfig = {
|
|
||||||
After = [ "acme-${domain}.service" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
{ lib, fetchgit, buildGoModule, ... }:
|
|
||||||
buildGoModule rec {
|
|
||||||
pname = "alps";
|
|
||||||
version = "v1.0.0"; # latest available tag at the moment
|
|
||||||
|
|
||||||
src = fetchGit {
|
|
||||||
url = "https://git.selfprivacy.org/ilchub/selfprivacy-alps";
|
|
||||||
rev = "dc2109ca2fdabfbda5d924faa4947f5694d5d758";
|
|
||||||
};
|
|
||||||
|
|
||||||
vendorSha256 = "0bqg0qjam4mvh07wfil6l5spz32mk5a7kfxxnwfyva805pzmn6dk";
|
|
||||||
|
|
||||||
deleteVendor = false;
|
|
||||||
runVend = true;
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
go build ./cmd/alps
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp -r * $out/bin
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Webmail application for the dovecot/postfix mailserver";
|
|
||||||
homepage = "https://git.selfprivacy.org/ilchub/selfprivacy-alps";
|
|
||||||
license = licenses.mit;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
{ pkgs, config, lib, fetchgit, buildGoModule, ... }:
|
|
||||||
let domain = config.services.userdata.domain;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
nixpkgs.overlays =
|
|
||||||
[ (self: super: { alps = self.callPackage ./alps-package.nix { }; }) ];
|
|
||||||
|
|
||||||
systemd.services = {
|
|
||||||
alps = {
|
|
||||||
path = [ pkgs.alps pkgs.coreutils ];
|
|
||||||
serviceConfig = {
|
|
||||||
ExecStart =
|
|
||||||
"${pkgs.alps}/bin/alps -theme sourcehut imaps://${domain}:993 smtps://${domain}:465";
|
|
||||||
WorkingDirectory = "${pkgs.alps}/bin";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -6,16 +6,22 @@ in
|
||||||
imports = [
|
imports = [
|
||||||
(builtins.fetchTarball {
|
(builtins.fetchTarball {
|
||||||
# Pick a commit from the branch you are interested in
|
# Pick a commit from the branch you are interested in
|
||||||
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/5675b122/nixos-mailserver-5675b122.tar.gz";
|
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/6d0d9fb9/nixos-mailserver-6d0d9fb9.tar.gz";
|
||||||
|
|
||||||
# And set its hash
|
# And set its hash
|
||||||
sha256 = "1fwhb7a5v9c98nzhf3dyqf3a5ianqh7k50zizj8v5nmj3blxw4pi";
|
sha256 = "sha256:0h35al73p15z9v8zb6hi5nq987sfl5wp4rm5c8947nlzlnsjl61x";
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
services.dovecot2 = {
|
fileSystems = lib.mkIf cfg.useBinds {
|
||||||
enablePAM = lib.mkForce true;
|
"/var/vmail" = {
|
||||||
showPAMFailure = lib.mkForce true;
|
device = "/volumes/${cfg.email.location}/vmail";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
"/var/sieve" = {
|
||||||
|
device = "/volumes/${cfg.email.location}/sieve";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users = {
|
users.users = {
|
||||||
|
@ -34,11 +40,10 @@ in
|
||||||
loginAccounts = {
|
loginAccounts = {
|
||||||
"${cfg.username}@${cfg.domain}" = {
|
"${cfg.username}@${cfg.domain}" = {
|
||||||
hashedPassword = cfg.hashedMasterPassword;
|
hashedPassword = cfg.hashedMasterPassword;
|
||||||
catchAll = [ cfg.domain ];
|
|
||||||
sieveScript = ''
|
sieveScript = ''
|
||||||
require ["fileinto", "mailbox"];
|
require ["fileinto", "mailbox"];
|
||||||
if header :contains "Chat-Version" "1.0"
|
if header :contains "Chat-Version" "1.0"
|
||||||
{
|
{
|
||||||
fileinto :create "DeltaChat";
|
fileinto :create "DeltaChat";
|
||||||
stop;
|
stop;
|
||||||
}
|
}
|
||||||
|
@ -49,11 +54,10 @@ in
|
||||||
name = "${user.username}@${cfg.domain}";
|
name = "${user.username}@${cfg.domain}";
|
||||||
value = {
|
value = {
|
||||||
hashedPassword = user.hashedPassword;
|
hashedPassword = user.hashedPassword;
|
||||||
catchAll = [ cfg.domain ];
|
|
||||||
sieveScript = ''
|
sieveScript = ''
|
||||||
require ["fileinto", "mailbox"];
|
require ["fileinto", "mailbox"];
|
||||||
if header :contains "Chat-Version" "1.0"
|
if header :contains "Chat-Version" "1.0"
|
||||||
{
|
{
|
||||||
fileinto :create "DeltaChat";
|
fileinto :create "DeltaChat";
|
||||||
stop;
|
stop;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
fileSystems = lib.mkIf cfg.useBinds {
|
||||||
|
"/var/lib/nextcloud" = {
|
||||||
|
device = "/volumes/${cfg.nextcloud.location}/nextcloud";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
services.nextcloud = {
|
services.nextcloud = {
|
||||||
enable = cfg.nextcloud.enable;
|
enable = cfg.nextcloud.enable;
|
||||||
package = pkgs.nextcloud22;
|
package = pkgs.nextcloud25;
|
||||||
hostName = "cloud.${cfg.domain}";
|
hostName = "cloud.${cfg.domain}";
|
||||||
|
|
||||||
# Use HTTPS for links
|
# Use HTTPS for links
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.bitwarden_rs = {
|
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;
|
enable = cfg.bitwarden.enable;
|
||||||
dbBackend = "sqlite";
|
dbBackend = "sqlite";
|
||||||
backupDir = "/var/lib/bitwarden/backup";
|
backupDir = "/var/lib/bitwarden/backup";
|
||||||
|
environmentFile = "/var/lib/bitwarden/.env";
|
||||||
config = {
|
config = {
|
||||||
domain = "https://password.${cfg.domain}/";
|
domain = "https://password.${cfg.domain}/";
|
||||||
signupsAllowed = true;
|
signupsAllowed = true;
|
||||||
|
|
|
@ -22,9 +22,8 @@ config :pleroma, :media_proxy,
|
||||||
config :pleroma, Pleroma.Repo,
|
config :pleroma, Pleroma.Repo,
|
||||||
adapter: Ecto.Adapters.Postgres,
|
adapter: Ecto.Adapters.Postgres,
|
||||||
username: "pleroma",
|
username: "pleroma",
|
||||||
password: "$DB_PASSWORD",
|
|
||||||
database: "pleroma",
|
database: "pleroma",
|
||||||
hostname: "localhost",
|
socket_dir: "/run/postgresql",
|
||||||
pool_size: 10
|
pool_size: 10
|
||||||
|
|
||||||
#config :web_push_encryption, :vapid_details,
|
#config :web_push_encryption, :vapid_details,
|
||||||
|
@ -41,4 +40,4 @@ config :pleroma, :http_security,
|
||||||
|
|
||||||
#config :joken, default_signer: ""
|
#config :joken, default_signer: ""
|
||||||
|
|
||||||
config :pleroma, configurable_from_database: false
|
config :pleroma, configurable_from_database: true
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
{ config, options, lib, pkgs, stdenv, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.services.pleroma;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
services.pleroma = with lib; {
|
|
||||||
enable = mkEnableOption "pleroma";
|
|
||||||
|
|
||||||
package = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
default = pkgs.pleroma-otp;
|
|
||||||
description = "Pleroma package to use.";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pleroma";
|
|
||||||
description = "User account under which pleroma runs.";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pleroma";
|
|
||||||
description = "Group account under which pleroma runs.";
|
|
||||||
};
|
|
||||||
|
|
||||||
stateDir = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/var/lib/pleroma";
|
|
||||||
readOnly = true;
|
|
||||||
description = "Directory where the pleroma service will save the uploads and static files.";
|
|
||||||
};
|
|
||||||
|
|
||||||
configs = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
description = ''
|
|
||||||
Pleroma public configuration.
|
|
||||||
This list gets appended from left to
|
|
||||||
right into /etc/pleroma/config.exs. Elixir evaluates its
|
|
||||||
configuration imperatively, meaning you can override a
|
|
||||||
setting by appending a new str to this NixOS option list.
|
|
||||||
<emphasis>DO NOT STORE ANY PLEROMA SECRET
|
|
||||||
HERE</emphasis>, use
|
|
||||||
<link linkend="opt-services.pleroma.secretConfigFile">services.pleroma.secretConfigFile</link>
|
|
||||||
instead.
|
|
||||||
This setting is going to be stored in a file part of
|
|
||||||
the Nix store. The Nix store being world-readable, it's not
|
|
||||||
the right place to store any secret
|
|
||||||
Have a look to Pleroma section in the NixOS manual for more
|
|
||||||
informations.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
secretConfigFile = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/var/lib/pleroma/secrets.exs";
|
|
||||||
description = ''
|
|
||||||
Path to the file containing your secret pleroma configuration.
|
|
||||||
<emphasis>DO NOT POINT THIS OPTION TO THE NIX
|
|
||||||
STORE</emphasis>, the store being world-readable, it'll
|
|
||||||
compromise all your secrets.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
users = {
|
|
||||||
users."${cfg.user}" = {
|
|
||||||
description = "Pleroma user";
|
|
||||||
home = cfg.stateDir;
|
|
||||||
extraGroups = [ cfg.group ];
|
|
||||||
};
|
|
||||||
groups."${cfg.group}" = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package ];
|
|
||||||
|
|
||||||
environment.etc."/pleroma/config.exs".text = ''
|
|
||||||
${lib.concatMapStrings (x: "${x}") cfg.configs}
|
|
||||||
# The lau/tzdata library is trying to download the latest
|
|
||||||
# timezone database in the OTP priv directory by default.
|
|
||||||
# This directory being in the store, it's read-only.
|
|
||||||
# Setting that up to a more appropriate location.
|
|
||||||
config :tzdata, :data_dir, "/var/lib/pleroma/elixir_tzdata_data"
|
|
||||||
import_config "${cfg.secretConfigFile}"
|
|
||||||
'';
|
|
||||||
|
|
||||||
systemd.services.pleroma = {
|
|
||||||
description = "Pleroma social network";
|
|
||||||
after = [ "network-online.target" "postgresql.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ];
|
|
||||||
serviceConfig = {
|
|
||||||
User = cfg.user;
|
|
||||||
Group = cfg.group;
|
|
||||||
Type = "exec";
|
|
||||||
WorkingDirectory = "~";
|
|
||||||
StateDirectory = "pleroma pleroma/static pleroma/uploads";
|
|
||||||
StateDirectoryMode = "700";
|
|
||||||
|
|
||||||
# Checking the conf file is there then running the database
|
|
||||||
# migration before each service start, just in case there are
|
|
||||||
# some pending ones.
|
|
||||||
#
|
|
||||||
# It's sub-optimal as we'll always run this, even if pleroma
|
|
||||||
# has not been updated. But the no-op process is pretty fast.
|
|
||||||
# Better be safe than sorry migration-wise.
|
|
||||||
ExecStartPre =
|
|
||||||
let preScript = pkgs.writers.writeBashBin "pleromaStartPre"
|
|
||||||
"${cfg.package}/bin/pleroma_ctl migrate";
|
|
||||||
in "${preScript}/bin/pleromaStartPre";
|
|
||||||
|
|
||||||
ExecStart = "${cfg.package}/bin/pleroma start";
|
|
||||||
ExecStop = "${cfg.package}/bin/pleroma stop";
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
|
|
||||||
# Systemd sandboxing directives.
|
|
||||||
# Taken from the upstream contrib systemd service at
|
|
||||||
# pleroma/installation/pleroma.service
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectSystem = "full";
|
|
||||||
PrivateDevices = false;
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
CapabilityBoundingSet = "~CAP_SYS_ADMIN";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
meta.maintainers = with lib.maintainers; [ ninjatrappeur ];
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
{ lib
|
|
||||||
, stdenv
|
|
||||||
, autoPatchelfHook
|
|
||||||
, fetchurl
|
|
||||||
, file
|
|
||||||
, makeWrapper
|
|
||||||
, ncurses
|
|
||||||
, nixosTests
|
|
||||||
, openssl
|
|
||||||
, unzip
|
|
||||||
, zlib
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
pname = "pleroma-otp";
|
|
||||||
version = "2.3.0";
|
|
||||||
|
|
||||||
# To find the latest binary release stable link, have a look at
|
|
||||||
# the CI pipeline for the latest commit of the stable branch
|
|
||||||
# https://git.pleroma.social/pleroma/pleroma/-/tree/stable
|
|
||||||
src = {
|
|
||||||
aarch64-linux = fetchurl {
|
|
||||||
url = "https://git.pleroma.social/pleroma/pleroma/-/jobs/182392/artifacts/download";
|
|
||||||
sha256 = "1drpd6xh7m2damxi5impb8jwvjl6m3qv5yxynl12i8g66vi3rbwf";
|
|
||||||
};
|
|
||||||
x86_64-linux = fetchurl {
|
|
||||||
url = "https://git.pleroma.social/pleroma/pleroma/-/jobs/182388/artifacts/download";
|
|
||||||
sha256 = "1c6l04gga9iigm249ywwcrjg6wzy8iiid652mws3j9dnl71w2sim";
|
|
||||||
};
|
|
||||||
}."${stdenv.hostPlatform.system}";
|
|
||||||
|
|
||||||
nativeBuildInputs = [ unzip ];
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
autoPatchelfHook
|
|
||||||
file
|
|
||||||
makeWrapper
|
|
||||||
ncurses
|
|
||||||
openssl
|
|
||||||
zlib
|
|
||||||
];
|
|
||||||
|
|
||||||
# mkDerivation fails to detect the zip nature of $src due to the
|
|
||||||
# missing .zip extension.
|
|
||||||
# Let's unpack the archive explicitely.
|
|
||||||
unpackCmd = "unzip $curSrc";
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
cp -r * $out'';
|
|
||||||
|
|
||||||
# Pleroma is using the project's root path (here the store path)
|
|
||||||
# as its TMPDIR.
|
|
||||||
# Patching it to move the tmp dir to the actual tmpdir
|
|
||||||
postFixup = ''
|
|
||||||
wrapProgram $out/bin/pleroma --set-default RELEASE_TMP "/tmp"
|
|
||||||
wrapProgram $out/bin/pleroma_ctl --set-default RELEASE_TMP "/tmp"'';
|
|
||||||
|
|
||||||
passthru.tests = {
|
|
||||||
pleroma = nixosTests.pleroma;
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "ActivityPub microblogging server";
|
|
||||||
homepage = https://git.pleroma.social/pleroma/pleroma;
|
|
||||||
license = licenses.agpl3;
|
|
||||||
maintainers = with maintainers; [ ninjatrappeur ];
|
|
||||||
platforms = [ "x86_64-linux" "aarch64-linux" ];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,13 +1,18 @@
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.services.userdata;
|
cfg = config.services.userdata;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixpkgs.overlays = [
|
fileSystems = lib.mkIf cfg.useBinds {
|
||||||
(self: super: {
|
"/var/lib/pleroma" = {
|
||||||
pleroma-otp = self.callPackage ./pleroma-package.nix { };
|
device = "/volumes/${cfg.pleroma.location}/pleroma";
|
||||||
})
|
options = [ "bind" ];
|
||||||
];
|
};
|
||||||
|
"/var/lib/postgresql" = {
|
||||||
|
device = "/volumes/${cfg.pleroma.location}/postgresql";
|
||||||
|
options = [ "bind" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
services = {
|
services = {
|
||||||
pleroma = {
|
pleroma = {
|
||||||
enable = cfg.pleroma.enable;
|
enable = cfg.pleroma.enable;
|
||||||
|
@ -15,8 +20,8 @@ in
|
||||||
group = "pleroma";
|
group = "pleroma";
|
||||||
configs = [
|
configs = [
|
||||||
(builtins.replaceStrings
|
(builtins.replaceStrings
|
||||||
[ "$DOMAIN" "$LUSER" "$DB_PASSWORD" ]
|
[ "$DOMAIN" "$LUSER" ]
|
||||||
[ cfg.domain cfg.username cfg.databasePassword ]
|
[ cfg.domain cfg.username ]
|
||||||
(builtins.readFile ./config.exs))
|
(builtins.readFile ./config.exs))
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -24,10 +29,21 @@ in
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.postgresql_12;
|
package = pkgs.postgresql_12;
|
||||||
initialScript = "/etc/setup.psql";
|
initialScript = "/etc/setup.psql";
|
||||||
|
ensureDatabases = [
|
||||||
|
"pleroma"
|
||||||
|
];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "pleroma";
|
||||||
|
ensurePermissions = {
|
||||||
|
"DATABASE pleroma" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.etc."setup.psql".text = ''
|
environment.etc."setup.psql".text = ''
|
||||||
CREATE USER pleroma WITH ENCRYPTED PASSWORD '${cfg.databasePassword}';
|
CREATE USER pleroma;
|
||||||
CREATE DATABASE pleroma OWNER pleroma;
|
CREATE DATABASE pleroma OWNER pleroma;
|
||||||
\c pleroma;
|
\c pleroma;
|
||||||
--Extensions made by ecto.migrate that need superuser access
|
--Extensions made by ecto.migrate that need superuser access
|
||||||
|
@ -39,5 +55,6 @@ in
|
||||||
extraGroups = [ "postgres" ];
|
extraGroups = [ "postgres" ];
|
||||||
isNormalUser = false;
|
isNormalUser = false;
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
|
group = "pleroma";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,12 @@
|
||||||
},
|
},
|
||||||
"enableSwagger": {
|
"enableSwagger": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"skippedMigrations": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"$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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ in
|
||||||
value = {
|
value = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
hashedPassword = user.hashedPassword;
|
hashedPassword = user.hashedPassword;
|
||||||
openssh.authorizedKeys.keys = user.sshKeys;
|
openssh.authorizedKeys.keys = (if user ? sshKeys then user.sshKeys else [ ]);
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
cfg.users);
|
cfg.users);
|
||||||
|
|
|
@ -11,10 +11,6 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.userdata = {
|
options.services.userdata = {
|
||||||
enable = mkOption {
|
|
||||||
default = true;
|
|
||||||
type = types.nullOr types.bool;
|
|
||||||
};
|
|
||||||
# General server options
|
# General server options
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
description = "The hostname of the server.";
|
description = "The hostname of the server.";
|
||||||
|
@ -45,6 +41,13 @@ in
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
stateVersion = mkOption {
|
||||||
|
description = ''
|
||||||
|
State version of the server
|
||||||
|
'';
|
||||||
|
type = types.str;
|
||||||
|
default = "22.11";
|
||||||
|
};
|
||||||
########################
|
########################
|
||||||
# Server admin options #
|
# Server admin options #
|
||||||
########################
|
########################
|
||||||
|
@ -71,79 +74,75 @@ in
|
||||||
# API options #
|
# API options #
|
||||||
###############
|
###############
|
||||||
api = {
|
api = {
|
||||||
token = mkOption {
|
skippedMigrations = mkOption {
|
||||||
|
default = [ ];
|
||||||
description = ''
|
description = ''
|
||||||
API token used to authenticate with the server
|
List of migrations that should be skipped
|
||||||
'';
|
'';
|
||||||
type = types.nullOr types.str;
|
type = types.listOf types.str;
|
||||||
};
|
|
||||||
enableSwagger = mkOption {
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Enable Swagger UI
|
|
||||||
'';
|
|
||||||
type = types.bool;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#############
|
#############
|
||||||
# Secrets #
|
# Secrets #
|
||||||
#############
|
#############
|
||||||
backblaze = {
|
dns = {
|
||||||
|
provider = mkOption {
|
||||||
|
description = "DNS provider that was defined at the initial setup process. Default is ClOUDFLARE";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
};
|
||||||
|
useStagingACME = mkOption {
|
||||||
|
description = "Use staging ACME server. Default is false";
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
backup = {
|
||||||
bucket = mkOption {
|
bucket = mkOption {
|
||||||
description = "Bucket name used for userdata backups";
|
description = "Bucket name used for userdata backups";
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
};
|
};
|
||||||
accountId = mkOption {
|
|
||||||
description = "Backblaze B2 Account ID";
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
};
|
|
||||||
accountKey = mkOption {
|
|
||||||
description = "Backblaze B2 Account Key.";
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
cloudflare = {
|
server = {
|
||||||
apiKey = mkOption {
|
provider = mkOption {
|
||||||
description = "Cloudflare API Key.";
|
description = "Server provider that was defined at the initial setup process. Default is HETZNER";
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
##############
|
##############
|
||||||
# Services #
|
# Services #
|
||||||
##############
|
##############
|
||||||
databasePassword = mkOption {
|
|
||||||
description = ''
|
|
||||||
Password for the database
|
|
||||||
'';
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
};
|
|
||||||
bitwarden = {
|
bitwarden = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.nullOr types.bool;
|
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 = {
|
gitea = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
|
location = mkOption {
|
||||||
|
default = "sda1";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
nextcloud = {
|
nextcloud = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
default = true;
|
default = true;
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
databasePassword = mkOption {
|
location = mkOption {
|
||||||
description = ''
|
default = "sda1";
|
||||||
Password for the nextcloud database
|
|
||||||
'';
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
};
|
|
||||||
adminPassword = mkOption {
|
|
||||||
description = ''
|
|
||||||
Password for the nextcloud admin user
|
|
||||||
'';
|
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -152,6 +151,10 @@ in
|
||||||
default = false;
|
default = false;
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
|
location = mkOption {
|
||||||
|
default = "sda1";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
jitsi = {
|
jitsi = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
|
@ -165,15 +168,6 @@ in
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#############
|
|
||||||
# Backups #
|
|
||||||
#############
|
|
||||||
resticPassword = mkOption {
|
|
||||||
description = ''
|
|
||||||
Password for the restic
|
|
||||||
'';
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
};
|
|
||||||
#########
|
#########
|
||||||
# SSH #
|
# SSH #
|
||||||
#########
|
#########
|
||||||
|
@ -193,7 +187,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
Password authentication for SSH
|
Password authentication for SSH
|
||||||
'';
|
'';
|
||||||
default = true;
|
default = false;
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -207,5 +201,19 @@ in
|
||||||
type = types.nullOr (types.listOf (types.attrsOf types.anything));
|
type = types.nullOr (types.listOf (types.attrsOf types.anything));
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
##############
|
||||||
|
# Volumes #
|
||||||
|
##############
|
||||||
|
volumes = mkOption {
|
||||||
|
description = ''
|
||||||
|
Volumes that will be created on the server
|
||||||
|
'';
|
||||||
|
type = types.nullOr (types.listOf (types.attrsOf types.anything));
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
useBinds = mkOption {
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,65 @@
|
||||||
{ pkgs, ... }:
|
{ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
jsonData = builtins.fromJSON (builtins.readFile ./userdata/userdata.json);
|
||||||
|
in
|
||||||
{
|
{
|
||||||
services = {
|
services.userdata = {
|
||||||
userdata = builtins.fromJSON (builtins.readFile ./userdata/userdata.json);
|
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 = {
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ in
|
||||||
services.jitsi-meet = {
|
services.jitsi-meet = {
|
||||||
enable = config.services.userdata.jitsi.enable;
|
enable = config.services.userdata.jitsi.enable;
|
||||||
hostName = "meet.${domain}";
|
hostName = "meet.${domain}";
|
||||||
nginx.enable = false;
|
nginx.enable = true;
|
||||||
interfaceConfig = {
|
interfaceConfig = {
|
||||||
SHOW_JITSI_WATERMARK = false;
|
SHOW_JITSI_WATERMARK = false;
|
||||||
SHOW_WATERMARK_FOR_GUESTS = false;
|
SHOW_WATERMARK_FOR_GUESTS = false;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fileSystems = { } // builtins.listToAttrs (builtins.map
|
||||||
|
(volume: {
|
||||||
|
name = "${volume.mountPoint}";
|
||||||
|
value = {
|
||||||
|
device = "${volume.device}";
|
||||||
|
fsType = "${volume.fsType}";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
cfg.volumes);
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ in
|
||||||
isNormalUser = false;
|
isNormalUser = false;
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
extraGroups = [ "ocserv" "acmerecievers" ];
|
extraGroups = [ "ocserv" "acmerecievers" ];
|
||||||
|
group = "ocserv";
|
||||||
};
|
};
|
||||||
services.ocserv = {
|
services.ocserv = {
|
||||||
enable = config.services.userdata.ocserv.enable;
|
enable = config.services.userdata.ocserv.enable;
|
||||||
|
|
|
@ -1,32 +1,72 @@
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, config, lib, ... }:
|
||||||
let
|
let
|
||||||
domain = config.services.userdata.domain;
|
domain = config.services.userdata.domain;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableReload = true;
|
|
||||||
recommendedGzipSettings = true;
|
recommendedGzipSettings = true;
|
||||||
recommendedOptimisation = true;
|
recommendedOptimisation = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
|
sslProtocols = lib.mkForce "TLSv1.2 TLSv1.3";
|
||||||
|
sslCiphers = lib.mkForce "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:!SHA1:!SHA256:!SHA384:!DSS:!aNULL";
|
||||||
clientMaxBodySize = "1024m";
|
clientMaxBodySize = "1024m";
|
||||||
|
commonHttpConfig = ''
|
||||||
|
map $scheme $hsts_header {
|
||||||
|
https "max-age=31536000; includeSubdomains; preload";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
"${domain}" = {
|
"${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
enableACME = true;
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
|
||||||
forceSSL = true;
|
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 = {
|
||||||
|
"/" = {
|
||||||
|
root = "/var/www/root";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
"vpn.${domain}" = {
|
"vpn.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
forceSSL = true;
|
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}" = {
|
"git.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
forceSSL = true;
|
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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
|
@ -34,54 +74,39 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"cloud.${domain}" = {
|
"cloud.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
forceSSL = true;
|
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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
proxyPass = "http://127.0.0.1:80/";
|
proxyPass = "http://127.0.0.1:80/";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"meet.${domain}" = {
|
|
||||||
forceSSL = true;
|
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
|
||||||
root = pkgs.jitsi-meet;
|
|
||||||
extraConfig = ''
|
|
||||||
ssi on;
|
|
||||||
'';
|
|
||||||
locations = {
|
|
||||||
"@root_path" = {
|
|
||||||
extraConfig = ''
|
|
||||||
rewrite ^/(.*)$ / break;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"~ ^/([^/\\?&:'\"]+)$" = {
|
|
||||||
tryFiles = "$uri @root_path";
|
|
||||||
};
|
|
||||||
"=/http-bind" = {
|
|
||||||
proxyPass = "http://localhost:5280/http-bind";
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"=/external_api.js" = {
|
|
||||||
alias = "${pkgs.jitsi-meet}/libs/external_api.min.js";
|
|
||||||
};
|
|
||||||
"=/config.js" = {
|
|
||||||
alias = "${pkgs.jitsi-meet}/config.js";
|
|
||||||
};
|
|
||||||
"=/interface_config.js" = {
|
|
||||||
alias = "${pkgs.jitsi-meet}/interface_config.js";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
"password.${domain}" = {
|
"password.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
forceSSL = true;
|
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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
proxyPass = "http://127.0.0.1:8222";
|
proxyPass = "http://127.0.0.1:8222";
|
||||||
|
@ -89,28 +114,53 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"api.${domain}" = {
|
"api.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
forceSSL = true;
|
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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
proxyPass = "http://127.0.0.1:5050";
|
proxyPass = "http://127.0.0.1:5050";
|
||||||
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"social.${domain}" = {
|
"social.${domain}" = {
|
||||||
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
root = "/var/www/social.${domain}";
|
root = "/var/www/social.${domain}";
|
||||||
forceSSL = true;
|
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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
proxyPass = "http://127.0.0.1:4000";
|
proxyPass = "http://127.0.0.1:4000";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
};
|
||||||
client_max_body_size 1024m;
|
"meet.${domain}" = {
|
||||||
'';
|
sslCertificate = "/var/lib/acme/wildcard-${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/wildcard-${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "wildcard-${domain}";
|
||||||
|
enableACME = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue