mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-config.git
synced 2024-11-21 19:41:26 +00:00
Initial commit
This commit is contained in:
commit
85aaf52635
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
userdata/userdata.json
|
||||||
|
hardware-configuration.nix
|
||||||
|
networking.nix
|
43
api/api-module.nix
Normal file
43
api/api-module.nix
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
selfprivacy-api = pkgs.callPackage ./api-package.nix { };
|
||||||
|
cfg = config.services.selfprivacy-api;
|
||||||
|
directionArg =
|
||||||
|
if cfg.direction == ""
|
||||||
|
then ""
|
||||||
|
else "--direction=${cfg.direction}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.selfprivacy-api = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Enable SelfPrivacy API service
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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";
|
||||||
|
} // 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 ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "network-online.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
User = "root";
|
||||||
|
ExecStart = "${selfprivacy-api}/bin/app.py";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
24
api/api-package.nix
Normal file
24
api/api-package.nix
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{ nixpkgs ? import <nixpkgs> { }, pythonPkgs ? nixpkgs.pkgs.python39Packages }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (nixpkgs) pkgs;
|
||||||
|
inherit pythonPkgs;
|
||||||
|
|
||||||
|
selfprivacy-api = { buildPythonPackage, flask, flask-restful, setuptools }:
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "selfprivacy-api";
|
||||||
|
version = "1.1";
|
||||||
|
src = builtins.fetchGit {
|
||||||
|
url = "https://git.selfprivacy.org/ilchub/selfprivacy-rest-api.git";
|
||||||
|
rev = "dbb4c1095654bba88d4f0c91b7b195d5262976b6";
|
||||||
|
};
|
||||||
|
propagatedBuildInputs = [ flask flask-restful setuptools ];
|
||||||
|
meta = {
|
||||||
|
description = ''
|
||||||
|
SelfPrivacy Server Management API
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
drv = pythonPkgs.callPackage selfprivacy-api { };
|
||||||
|
in
|
||||||
|
if pkgs.lib.inNixShell then drv.env else drv
|
15
api/api.nix
Normal file
15
api/api.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
services.selfprivacy-api = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users."selfprivacy-api" = {
|
||||||
|
isNormalUser = false;
|
||||||
|
isSystemUser = true;
|
||||||
|
extraGroups = [ "opendkim" ];
|
||||||
|
};
|
||||||
|
users.groups."selfprivacy-api" = {
|
||||||
|
members = [ "selfprivacy-api" ];
|
||||||
|
};
|
||||||
|
}
|
35
backup/restic.nix
Normal file
35
backup/restic.nix
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{ 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}
|
||||||
|
'';
|
||||||
|
}
|
82
configuration.nix
Normal file
82
configuration.nix
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix
|
||||||
|
|
||||||
|
./variables-module.nix
|
||||||
|
./variables.nix
|
||||||
|
./vscode.nix
|
||||||
|
./files.nix
|
||||||
|
./users.nix
|
||||||
|
./mailserver/system/mailserver.nix
|
||||||
|
./mailserver/system/alps.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
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.cleanTmpDir = true;
|
||||||
|
networking = {
|
||||||
|
hostName = config.services.userdata.hostname;
|
||||||
|
firewall = {
|
||||||
|
allowedTCPPorts = lib.mkForce [ 22 25 80 143 443 465 587 993 8443 ];
|
||||||
|
allowedUDPPorts = lib.mkForce [ 8443 ];
|
||||||
|
};
|
||||||
|
nameservers = [ "1.1.1.1" "1.0.0.1" ];
|
||||||
|
};
|
||||||
|
time.timeZone = "Europe/Uzhgorod";
|
||||||
|
i18n.defaultLocale = "en_GB.UTF-8";
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = config.services.userdata.rootSshKeys;
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
passwordAuthentication = true;
|
||||||
|
permitRootLogin = "yes";
|
||||||
|
openFirewall = false;
|
||||||
|
};
|
||||||
|
programs.ssh = {
|
||||||
|
pubkeyAcceptedKeyTypes = [ "ssh-ed25519" ];
|
||||||
|
hostKeyAlgorithms = [ "ssh-ed25519" ];
|
||||||
|
};
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
];
|
||||||
|
environment.variables = {
|
||||||
|
DOMAIN = config.services.userdata.domain;
|
||||||
|
};
|
||||||
|
system.autoUpgrade.enable = true;
|
||||||
|
system.autoUpgrade.allowReboot = false;
|
||||||
|
system.autoUpgrade.channel = https://nixos.org/channels/nixos-21.05-small;
|
||||||
|
nix = {
|
||||||
|
optimise.automatic = true;
|
||||||
|
gc = {
|
||||||
|
automatic = true;
|
||||||
|
options = "--delete-older-than 7d";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
boot.kernel.sysctl = {
|
||||||
|
"net.ipv4.ip_forward" = 1;
|
||||||
|
};
|
||||||
|
swapDevices = [
|
||||||
|
{
|
||||||
|
device = "/swapfile";
|
||||||
|
priority = 0;
|
||||||
|
size = 2048;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
security = {
|
||||||
|
sudo = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
30
files.nix
Normal file
30
files.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.tmpfiles.rules =
|
||||||
|
let
|
||||||
|
nextcloudDBPass = builtins.replaceStrings [ "\n" "\"" "\\" ] [ "\\n" "\\\"" "\\\\" ] cfg.nextcloud.databasePassword;
|
||||||
|
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}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
[
|
||||||
|
"d /var/restic 0660 restic - - -"
|
||||||
|
"d /var/bitwarden 0777 bitwarden_rs bitwarden_rs -"
|
||||||
|
"d /var/bitwarden/backup 0777 bitwarden_rs bitwarden_rs -"
|
||||||
|
"d /var/lib/pleroma 0600 pleroma pleroma - -"
|
||||||
|
"f /var/lib/pleroma/secrets.exs 0755 pleroma pleroma - -"
|
||||||
|
"f /var/domain 0444 selfprivacy-api selfprivacy-api - ${domain}"
|
||||||
|
"f /var/restic/restic-repo-password 0660 restic - - ${resticPass}"
|
||||||
|
"f /var/nextcloud-db-pass 0440 nextcloud nextcloud - ${nextcloudDBPass}"
|
||||||
|
"f /var/nextcloud-admin-pass 0440 nextcloud nextcloud - ${nextcloudAdminPass}"
|
||||||
|
"f /var/cloudflareCredentials.ini 0440 nginx acmerecievers - ${cloudflareCredentials}"
|
||||||
|
];
|
||||||
|
}
|
57
git/gitea.nix
Normal file
57
git/gitea.nix
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services = {
|
||||||
|
gitea = {
|
||||||
|
enable = cfg.gitea.enable;
|
||||||
|
stateDir = "/var/lib/gitea";
|
||||||
|
log = {
|
||||||
|
rootPath = "/var/lib/gitea/log";
|
||||||
|
level = "Warn";
|
||||||
|
};
|
||||||
|
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://${cfg.domain}/";
|
||||||
|
httpAddress = "0.0.0.0";
|
||||||
|
httpPort = 3000;
|
||||||
|
cookieSecure = true;
|
||||||
|
settings = {
|
||||||
|
mailer = {
|
||||||
|
ENABLED = false;
|
||||||
|
};
|
||||||
|
ui = {
|
||||||
|
DEFAULT_THEME = "arc-green";
|
||||||
|
};
|
||||||
|
picture = {
|
||||||
|
DISABLE_GRAVATAR = true;
|
||||||
|
};
|
||||||
|
admin = {
|
||||||
|
ENABLE_KANBAN_BOARD = true;
|
||||||
|
};
|
||||||
|
repository = {
|
||||||
|
FORCE_PRIVATE = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
22
letsencrypt/acme.nix
Normal file
22
letsencrypt/acme.nix
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users.groups.acmerecievers = {
|
||||||
|
members = [ "nginx" "dovecot2" "postfix" "virtualMail" "ocserv" ];
|
||||||
|
};
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
email = "${cfg.username}@${cfg.domain}";
|
||||||
|
certs = {
|
||||||
|
"${cfg.domain}" = {
|
||||||
|
domain = "*.${cfg.domain}";
|
||||||
|
extraDomainNames = [ "${cfg.domain}" ];
|
||||||
|
group = "acmerecievers";
|
||||||
|
dnsProvider = "cloudflare";
|
||||||
|
credentialsFile = "/var/cloudflareCredentials.ini";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
22
letsencrypt/resolve.nix
Normal file
22
letsencrypt/resolve.nix
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
domain = config.services.userdata.domain;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd = {
|
||||||
|
services = {
|
||||||
|
"acme-${domain}" = {
|
||||||
|
serviceConfig = {
|
||||||
|
StartLimitBurst = 5;
|
||||||
|
StartLimitIntervalSec = 5;
|
||||||
|
Restart = "on-failure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"nginx-config-reload" = {
|
||||||
|
serviceConfig = {
|
||||||
|
After = [ "acme-${domain}.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
30
mailserver/system/alps-package.nix
Normal file
30
mailserver/system/alps-package.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{ 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;
|
||||||
|
};
|
||||||
|
}
|
18
mailserver/system/alps.nix
Normal file
18
mailserver/system/alps.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{ 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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
85
mailserver/system/mailserver.nix
Normal file
85
mailserver/system/mailserver.nix
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(builtins.fetchTarball {
|
||||||
|
# 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";
|
||||||
|
|
||||||
|
# And set its hash
|
||||||
|
sha256 = "1fwhb7a5v9c98nzhf3dyqf3a5ianqh7k50zizj8v5nmj3blxw4pi";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
services.dovecot2 = {
|
||||||
|
enablePAM = lib.mkForce true;
|
||||||
|
showPAMFailure = lib.mkForce true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users = {
|
||||||
|
virtualMail = {
|
||||||
|
isNormalUser = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mailserver = {
|
||||||
|
enable = true;
|
||||||
|
fqdn = cfg.domain;
|
||||||
|
domains = [ cfg.domain ];
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
catchAll = [ cfg.domain ];
|
||||||
|
sieveScript = ''
|
||||||
|
require ["fileinto", "mailbox"];
|
||||||
|
if header :contains "Chat-Version" "1.0"
|
||||||
|
{
|
||||||
|
fileinto :create "DeltaChat";
|
||||||
|
stop;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
} // builtins.listToAttrs (builtins.map
|
||||||
|
(user: {
|
||||||
|
name = "${user.username}@${cfg.domain}";
|
||||||
|
value = {
|
||||||
|
hashedPassword = user.hashedPassword;
|
||||||
|
catchAll = [ cfg.domain ];
|
||||||
|
sieveScript = ''
|
||||||
|
require ["fileinto", "mailbox"];
|
||||||
|
if header :contains "Chat-Version" "1.0"
|
||||||
|
{
|
||||||
|
fileinto :create "DeltaChat";
|
||||||
|
stop;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
})
|
||||||
|
cfg.users);
|
||||||
|
};
|
||||||
|
|
||||||
|
extraVirtualAliases = {
|
||||||
|
"admin@${cfg.domain}" = "${cfg.username}@${cfg.domain}";
|
||||||
|
};
|
||||||
|
|
||||||
|
certificateScheme = 1;
|
||||||
|
certificateFile = "/var/lib/acme/${cfg.domain}/fullchain.pem";
|
||||||
|
keyFile = "/var/lib/acme/${cfg.domain}/key.pem";
|
||||||
|
|
||||||
|
# Enable IMAP and POP3
|
||||||
|
enableImap = true;
|
||||||
|
enableImapSsl = true;
|
||||||
|
enablePop3 = false;
|
||||||
|
enablePop3Ssl = false;
|
||||||
|
dkimSelector = "selector";
|
||||||
|
|
||||||
|
# Enable the ManageSieve protocol
|
||||||
|
enableManageSieve = true;
|
||||||
|
|
||||||
|
virusScanning = false;
|
||||||
|
};
|
||||||
|
}
|
34
nextcloud/nextcloud.nix
Normal file
34
nextcloud/nextcloud.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.nextcloud = {
|
||||||
|
enable = cfg.nextcloud.enable;
|
||||||
|
package = pkgs.nextcloud21;
|
||||||
|
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 = "http";
|
||||||
|
|
||||||
|
# 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/nextcloud-db-pass";
|
||||||
|
|
||||||
|
adminpassFile = "/var/nextcloud-admin-pass";
|
||||||
|
adminuser = "admin";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
16
passmgr/bitwarden.nix
Normal file
16
passmgr/bitwarden.nix
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.bitwarden_rs = {
|
||||||
|
enable = cfg.bitwarden.enable;
|
||||||
|
dbBackend = "sqlite";
|
||||||
|
backupDir = "/var/bitwarden/backup";
|
||||||
|
config = {
|
||||||
|
domain = "https://password.${cfg.domain}/";
|
||||||
|
signupsAllowed = true;
|
||||||
|
rocketPort = 8222;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
48
resources/limits.nix
Normal file
48
resources/limits.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
systemd.services = {
|
||||||
|
dovecot2 = {
|
||||||
|
serviceConfig = {
|
||||||
|
cpuAccounting = true;
|
||||||
|
cpuQuota = "20%";
|
||||||
|
memoryAccounting = true;
|
||||||
|
memoryMax = "256M";
|
||||||
|
startLimitIntervalSec = 500;
|
||||||
|
startLimitBurst = 5;
|
||||||
|
blockIOWeigth = 25;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
postfix = {
|
||||||
|
serviceConfig = {
|
||||||
|
cpuAccounting = true;
|
||||||
|
cpuQuota = "20%";
|
||||||
|
memoryAccounting = true;
|
||||||
|
memoryMax = "256M";
|
||||||
|
startLimitIntervalSec = 500;
|
||||||
|
startLimitBurst = 5;
|
||||||
|
blockIOWeigth = 25;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ocserv = {
|
||||||
|
serviceConfig = {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
44
social/config.exs
Normal file
44
social/config.exs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import Config
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Web.Endpoint,
|
||||||
|
url: [host: "social.$DOMAIN", scheme: "https", port: 443],
|
||||||
|
http: [ip: {127, 0, 0, 1}, port: 4000]
|
||||||
|
#secret_key_base: "",
|
||||||
|
#signing_salt: ""
|
||||||
|
|
||||||
|
config :pleroma, :instance,
|
||||||
|
name: "social.$DOMAIN",
|
||||||
|
email: "$LUSER@$DOMAIN",
|
||||||
|
notify_email: "$LUSER@$DOMAIN",
|
||||||
|
limit: 5000,
|
||||||
|
upload_limit: 1073741824,
|
||||||
|
registrations_open: true
|
||||||
|
|
||||||
|
config :pleroma, :media_proxy,
|
||||||
|
enabled: false,
|
||||||
|
redirect_on_failure: true
|
||||||
|
#base_url: "https://cache.pleroma.social"
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.Repo,
|
||||||
|
adapter: Ecto.Adapters.Postgres,
|
||||||
|
username: "pleroma",
|
||||||
|
password: "$DB_PASSWORD",
|
||||||
|
database: "pleroma",
|
||||||
|
hostname: "localhost",
|
||||||
|
pool_size: 10
|
||||||
|
|
||||||
|
#config :web_push_encryption, :vapid_details,
|
||||||
|
#subject: "",
|
||||||
|
#public_key: "",
|
||||||
|
#private_key: ""
|
||||||
|
|
||||||
|
config :pleroma, :database, rum_enabled: false
|
||||||
|
config :pleroma, :instance, static_dir: "/var/lib/pleroma/static"
|
||||||
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
||||||
|
|
||||||
|
config :pleroma, :http_security,
|
||||||
|
sts: true
|
||||||
|
|
||||||
|
#config :joken, default_signer: ""
|
||||||
|
|
||||||
|
config :pleroma, configurable_from_database: false
|
133
social/pleroma-module.nix
Normal file
133
social/pleroma-module.nix
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
{ 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 ];
|
||||||
|
}
|
69
social/pleroma-package.nix
Normal file
69
social/pleroma-package.nix
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
{ 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" ];
|
||||||
|
};
|
||||||
|
}
|
41
social/pleroma.nix
Normal file
41
social/pleroma.nix
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(self: super: {
|
||||||
|
pleroma-otp = self.callPackage ./pleroma-package.nix { };
|
||||||
|
})
|
||||||
|
];
|
||||||
|
services = {
|
||||||
|
pleroma = {
|
||||||
|
enable = cfg.pleroma.enable;
|
||||||
|
user = "pleroma";
|
||||||
|
group = "pleroma";
|
||||||
|
configs = [
|
||||||
|
builtins.replaceStrings
|
||||||
|
[ "$DOMAIN" "$LUSER" "$DB_PASSWORD" ]
|
||||||
|
[ cfg.domain cfg.username cfg.databasePassword ]
|
||||||
|
(builtins.readFile ./config.exs)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
postgresql = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.postgresql_12;
|
||||||
|
initialScript = "/etc/setup.psql";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environment.etc."setup.psql".text = ''
|
||||||
|
CREATE USER pleroma WITH ENCRYPTED PASSWORD '${cfg.databasePassword}';
|
||||||
|
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" ];
|
||||||
|
};
|
||||||
|
}
|
142
userdata/schema.json
Normal file
142
userdata/schema.json
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema#",
|
||||||
|
"$id": "https://git.selfprivacy.org/inex/selfprivacy-nixos-config/raw/branch/master/userdata/schema.json",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hostname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hashedMasterPassword": {
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"rootSshKeys": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
12
users.nix
Normal file
12
users.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
{
|
||||||
|
users.mutableUsers = false;
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
"${config.services.userdata.username}" = {
|
||||||
|
isNormalUser = true;
|
||||||
|
hashedPassword = config.services.userdata.hashedMasterPassword;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
153
variables-module.nix
Normal file
153
variables-module.nix
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.userdata;
|
||||||
|
directionArg =
|
||||||
|
if cfg.direction == ""
|
||||||
|
then ""
|
||||||
|
else "--direction=${cfg.direction}";
|
||||||
|
userDef = {
|
||||||
|
options = {
|
||||||
|
username = mkOption {
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
hashedPassword = mkOption {
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
sshKeys = mkOption {
|
||||||
|
type = types.nullOr types.listOf types.string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.userdata = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = true;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
hostname = mkOption {
|
||||||
|
description = "The hostname of the server.";
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
domain = mkOption {
|
||||||
|
description = ''
|
||||||
|
Domain used by the server
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
username = mkOption {
|
||||||
|
description = ''
|
||||||
|
Username that was defined at the initial setup process
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
hashedMasterPassword = mkOption {
|
||||||
|
description = ''
|
||||||
|
Hash of the password that was defined at the initial setup process
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
backblaze = {
|
||||||
|
bucket = mkOption {
|
||||||
|
description = "Bucket name used for userdata backups";
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
accountId = mkOption {
|
||||||
|
description = "Backblaze B2 Account ID";
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
accountKey = mkOption {
|
||||||
|
description = "Backblaze B2 Account Key.";
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
cloudflare = {
|
||||||
|
apiKey = mkOption {
|
||||||
|
description = "Cloudflare API Key.";
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
databasePassword = mkOption {
|
||||||
|
description = ''
|
||||||
|
Password for the database
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
bitwarden = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
gitea = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nextcloud = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = true;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
databasePassword = mkOption {
|
||||||
|
description = ''
|
||||||
|
Password for the nextcloud database
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
adminPassword = mkOption {
|
||||||
|
description = ''
|
||||||
|
Password for the nextcloud admin user
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
pleroma = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
jitsi = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ocserv = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = true;
|
||||||
|
type = types.nullOr types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
resticPassword = mkOption {
|
||||||
|
description = ''
|
||||||
|
Password for the restic
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
};
|
||||||
|
rootSshKeys = mkOption {
|
||||||
|
description = ''
|
||||||
|
Root SSH Keys
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.listOf types.string;
|
||||||
|
};
|
||||||
|
timezone = mkOption {
|
||||||
|
description = ''
|
||||||
|
Timezone used by the server
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.string;
|
||||||
|
default = "Europe/Uzhgorod";
|
||||||
|
};
|
||||||
|
users = mkOption {
|
||||||
|
description = ''
|
||||||
|
Users that will be created on the server
|
||||||
|
'';
|
||||||
|
type = with types; nullOr listOf attrsOf (submodule userDef);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
6
variables.nix
Normal file
6
variables.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
services = {
|
||||||
|
userdata = builtins.fromJSON (builtins.readFile "./userdata/userdata.json");
|
||||||
|
};
|
||||||
|
}
|
15
videomeet/jitsi.nix
Normal file
15
videomeet/jitsi.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
domain = config.services.userdata.domain;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.jitsi-meet = {
|
||||||
|
enable = config.services.userdata.jitsi.enable;
|
||||||
|
hostName = "meet.${domain}";
|
||||||
|
nginx.enable = false;
|
||||||
|
interfaceConfig = {
|
||||||
|
SHOW_JITSI_WATERMARK = false;
|
||||||
|
SHOW_WATERMARK_FOR_GUESTS = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
51
vpn/ocserv.nix
Normal file
51
vpn/ocserv.nix
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
domain = config.services.userdata.domain;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users.groups.ocserv = {
|
||||||
|
members = [ "ocserv" ];
|
||||||
|
};
|
||||||
|
users.users.ocserv = {
|
||||||
|
isNormalUser = false;
|
||||||
|
isSystemUser = true;
|
||||||
|
extraGroups = [ "ocserv" "acmerecievers" ];
|
||||||
|
};
|
||||||
|
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
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
13
webserver/memcached.nix
Normal file
13
webserver/memcached.nix
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
services = {
|
||||||
|
memcached = {
|
||||||
|
enable = true;
|
||||||
|
user = "memcached";
|
||||||
|
listen = "127.0.0.1";
|
||||||
|
port = 11211;
|
||||||
|
maxMemory = 64;
|
||||||
|
maxConnections = 1024;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
117
webserver/nginx.nix
Normal file
117
webserver/nginx.nix
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
{ pkgs, config, ... }:
|
||||||
|
let
|
||||||
|
domain = config.services.userdata.domain;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
enableReload = true;
|
||||||
|
recommendedGzipSettings = true;
|
||||||
|
recommendedOptimisation = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
recommendedTlsSettings = true;
|
||||||
|
clientMaxBodySize = "1024m";
|
||||||
|
|
||||||
|
virtualHosts = {
|
||||||
|
"${domain}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
};
|
||||||
|
"vpn.${domain}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
};
|
||||||
|
"git.${domain}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
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;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
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}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8222";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"api.${domain}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
forceSSL = true;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:5050";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"social.${domain}" = {
|
||||||
|
sslCertificate = "/var/lib/acme/${domain}/fullchain.pem";
|
||||||
|
sslCertificateKey = "/var/lib/acme/${domain}/key.pem";
|
||||||
|
root = "/var/www/social.${domain}";
|
||||||
|
forceSSL = true;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:4000";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
extraConfig = ''
|
||||||
|
client_max_body_size 1024m;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue