mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect.git
synced 2024-11-05 03:03:11 +00:00
1348 lines
36 KiB
Bash
1348 lines
36 KiB
Bash
#! /usr/bin/env bash
|
|
|
|
# More info at: https://github.com/elitak/nixos-infect
|
|
|
|
set -e -o pipefail
|
|
|
|
makeConf() {
|
|
export HASHED_PASSWORD=$( mkpasswd -m sha-512 "$PASSWORD" )
|
|
# Skip everything if main config already present
|
|
[[ -e /etc/nixos/configuration.nix ]] && return 0
|
|
# NB <<"EOF" quotes / $ ` in heredocs, <<EOF does not
|
|
mkdir /etc/nixos
|
|
mkdir -p /etc/nixos/mailserver/system
|
|
mkdir /etc/nixos/mailserver/userdata
|
|
mkdir /etc/nixos/api
|
|
mkdir /etc/nixos/social
|
|
mkdir /etc/nixos/letsencrypt
|
|
mkdir /etc/nixos/backup
|
|
mkdir /etc/nixos/passmgr
|
|
mkdir /etc/nixos/webserver
|
|
mkdir /etc/nixos/git
|
|
mkdir /etc/nixos/nextcloud
|
|
mkdir /etc/nixos/resources
|
|
mkdir /etc/nixos/videomeet
|
|
mkdir /etc/nixos/vpn
|
|
|
|
# Prevent grep for sending error code 1 (and halting execution) when no lines are selected : https://www.unix.com/man-page/posix/1P/grep
|
|
local IFS=$'\n'
|
|
for trypath in /root/.ssh/authorized_keys $HOME/.ssh/authorized_keys; do
|
|
[[ -r "$trypath" ]] \
|
|
&& keys=$(sed -E 's/^.*((ssh|ecdsa)-[^[:space:]]+)[[:space:]]+([^[:space:]]+)([[:space:]]*.*)$/\1 \3\4/' "$trypath") \
|
|
&& break
|
|
done
|
|
local network_import=""
|
|
|
|
[[ -n "$doNetConf" ]] && network_import="./networking.nix # generated at runtime by nixos-infect"
|
|
cat > /etc/nixos/configuration.nix << EOF
|
|
{ pkgs, lib, ... }:
|
|
{
|
|
imports = [
|
|
./hardware-configuration.nix
|
|
$network_import
|
|
$NIXOS_IMPORT
|
|
./files.nix
|
|
./users.nix
|
|
./mailserver/system/mailserver.nix
|
|
./mailserver/system/alps.nix
|
|
./vpn/ocserv.nix
|
|
./api/api.nix
|
|
./api/api-module.nix
|
|
#./social/pleroma-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 = "$(hostname)";
|
|
firewall = {
|
|
allowedTCPPorts = lib.mkForce [ 22 25 80 143 443 465 587 993 8443 ];
|
|
allowedUDPPorts = lib.mkForce [ 8443 ];
|
|
};
|
|
};
|
|
time.timeZone = "Europe/Uzhgorod";
|
|
i18n.defaultLocale = "en_GB.UTF-8";
|
|
users.users.root.openssh.authorizedKeys.keys = [$(while read -r line; do echo -n "
|
|
\"$line\" "; done <<< "$keys")
|
|
];
|
|
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 = "$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;
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
# If you rerun this later, be sure to prune the filesSystems attr
|
|
cat > /etc/nixos/hardware-configuration.nix << EOF
|
|
{ ... }:
|
|
{
|
|
imports = [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> ];
|
|
boot.loader.grub.device = "$grubdev";
|
|
fileSystems = {
|
|
"/" = { device = "$rootfsdev"; fsType = "ext4"; };
|
|
"/var" = { device = "/dev/sdb"; fsType = "ext4"; };
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/files.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
systemd.tmpfiles.rules =
|
|
let
|
|
nextcloudDBPass = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$PASSWORD
|
|
'';
|
|
nextcloudAdminPass = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$PASSWORD
|
|
'';
|
|
resticPass = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$PASSWORD
|
|
'';
|
|
domain = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$DOMAIN
|
|
'';
|
|
cloudflareCredentials = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
CF_API_KEY=$CF_TOKEN
|
|
CLOUDFLARE_DNS_API_TOKEN=$CF_TOKEN
|
|
CLOUDFLARE_ZONE_API_TOKEN=$CF_TOKEN
|
|
'';
|
|
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}"
|
|
];
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/users.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
users.mutableUsers = false;
|
|
users = {
|
|
users = {
|
|
#begin
|
|
"$LUSER" = {
|
|
isNormalUser = true;
|
|
hashedPassword = "$HASHED_PASSWORD";
|
|
};
|
|
#end
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/mailserver/system/mailserver.nix << EOF
|
|
{ config, pkgs, lib, ... }:
|
|
{
|
|
imports = [
|
|
(builtins.fetchTarball {
|
|
# Pick a commit from the branch you are interested in
|
|
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/99f843de/nixos-mailserver-99f843de.tar.gz";
|
|
|
|
# And set its hash
|
|
sha256 = "1af7phs8a2j26ywsm5mfhzvqmy0wdsph7ajs9s65c4r1bfq646fw";
|
|
})
|
|
];
|
|
|
|
services.dovecot2 = {
|
|
enablePAM = lib.mkForce true;
|
|
showPAMFailure = lib.mkForce true;
|
|
};
|
|
|
|
users.users = {
|
|
virtualMail = {
|
|
isNormalUser = false;
|
|
};
|
|
};
|
|
|
|
mailserver = {
|
|
enable = true;
|
|
fqdn = "$DOMAIN";
|
|
domains = [ "$DOMAIN" ];
|
|
|
|
# A list of all login accounts. To create the password hashes, use
|
|
# mkpasswd -m sha-512 "super secret password"
|
|
loginAccounts = {
|
|
"$LUSER@$DOMAIN" = {
|
|
hashedPassword = "$HASHED_PASSWORD";
|
|
catchAll = [ "$DOMAIN" ];
|
|
sieveScript = ''
|
|
require ["fileinto", "mailbox"];
|
|
if header :contains "Chat-Version" "1.0"
|
|
{
|
|
fileinto :create "DeltaChat";
|
|
stop;
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
|
|
extraVirtualAliases = {
|
|
"admin@$DOMAIN" = "$LUSER@$DOMAIN";
|
|
};
|
|
|
|
certificateScheme = 1;
|
|
certificateFile = "/var/lib/acme/$DOMAIN/fullchain.pem";
|
|
keyFile = "/var/lib/acme/$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;
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/letsencrypt/acme.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
users.groups.acmerecievers = {
|
|
members = [ "nginx" "dovecot2" "postfix" "virtualMail" "ocserv" ];
|
|
};
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
email = "$LUSER@$DOMAIN";
|
|
certs = {
|
|
"$DOMAIN" = {
|
|
domain = "*.$DOMAIN";
|
|
extraDomainNames = [ "$DOMAIN" ];
|
|
group = "acmerecievers";
|
|
dnsProvider = "cloudflare";
|
|
credentialsFile = "/var/cloudflareCredentials.ini";
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
cat > /etc/nixos/letsencrypt/resolve.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
systemd = {
|
|
services = {
|
|
"acme-$DOMAIN" = {
|
|
serviceConfig = {
|
|
StartLimitBurst = 5;
|
|
StartLimitIntervalSec = 5;
|
|
Restart = "on-failure";
|
|
};
|
|
};
|
|
"nginx-config-reload" = {
|
|
serviceConfig = {
|
|
After = [ "acme-$DOMAIN.service" ];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/backup/restic.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.restic.backups = {
|
|
options = {
|
|
passwordFile = "/etc/restic/resticPasswd";
|
|
repository = "s3:s3.anazonaws.com/$S3_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 = ''
|
|
$PASSWORD
|
|
'';
|
|
environment.etc."restic/s3Passwd".text = ''
|
|
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
|
|
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
|
|
'';
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/passmgr/bitwarden.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.bitwarden_rs = {
|
|
enable = true;
|
|
dbBackend = "sqlite";
|
|
backupDir = "/var/bitwarden/backup";
|
|
config = {
|
|
domain = "https://password.$DOMAIN/";
|
|
signupsAllowed = true;
|
|
rocketPort = 8222;
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/webserver/nginx.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
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;
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/webserver/memcached.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services = {
|
|
memcached = {
|
|
enable = true;
|
|
user = "memcached";
|
|
listen = "127.0.0.1";
|
|
port = "11211";
|
|
maxMemory = 64;
|
|
maxConnections = 1024;
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/nextcloud/nextcloud.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.nextcloud = {
|
|
enable = true;
|
|
package = pkgs.nextcloud21;
|
|
hostName = "cloud.$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";
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/git/gitea.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services = {
|
|
gitea = {
|
|
enable = true;
|
|
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.$DOMAIN";
|
|
rootUrl = "https://$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;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/resources/limits.nix << EOF
|
|
{ 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;
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/videomeet/jitsi.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.jitsi-meet = {
|
|
enable = false;
|
|
hostName = "meet.$DOMAIN";
|
|
nginx.enable = false;
|
|
interfaceConfig = {
|
|
SHOW_JITSI_WATERMARK = false;
|
|
SHOW_WATERMARK_FOR_GUESTS = false;
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/api/api.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.selfprivacy-api = {
|
|
enable = true;
|
|
};
|
|
|
|
users.users."selfprivacy-api" = {
|
|
isNormalUser = false;
|
|
isSystemUser = true;
|
|
extraGroups = [ "opendkim" ];
|
|
};
|
|
users.groups."selfprivacy-api" = {
|
|
members = [ "selfprivacy-api" ];
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/api/api-package.nix << EOF
|
|
{ nixpkgs ? import <nixpkgs> {}, pythonPkgs ? nixpkgs.pkgs.python37Packages }:
|
|
|
|
let
|
|
inherit (nixpkgs) pkgs;
|
|
inherit pythonPkgs;
|
|
|
|
selfprivacy-api = { buildPythonPackage, flask, flask-restful, pandas }:
|
|
buildPythonPackage rec {
|
|
pname = "selfprivacy-api";
|
|
version = "1.0";
|
|
src = builtins.fetchGit {
|
|
url = "https://git.selfprivacy.org/ilchub/selfprivacy-rest-api.git";
|
|
rev = "2885fe4356cf257ba5d64b9bad091aceba104883";
|
|
};
|
|
propagatedBuildInputs = [ flask flask-restful pandas ];
|
|
meta = {
|
|
description = ''
|
|
SelfPrivacy Server Management API
|
|
'';
|
|
};
|
|
};
|
|
drv = pythonPkgs.callPackage selfprivacy-api {};
|
|
in
|
|
if pkgs.lib.inNixShell then drv.env else drv
|
|
EOF
|
|
|
|
cat > /etc/nixos/api/api-module.nix << EOF
|
|
{ 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 = {
|
|
PYTHONUNBUFFERED = "1";
|
|
};
|
|
path = [ "/var/" "/var/dkim/" pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gzip pkgs.gitMinimal pkgs.config.nix.package.out ];
|
|
after = [ "network-online.target" ];
|
|
wantedBy = [ "network-online.target" ];
|
|
serviceConfig = {
|
|
User = "root";
|
|
ExecStart = "\${selfprivacy-api}/bin/main.py";
|
|
Restart = "always";
|
|
RestartSec = "5";
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/vpn/ocserv.nix << EOF
|
|
{ pkgs, ...}:
|
|
{
|
|
users.groups.ocserv = {
|
|
members = [ "ocserv" ];
|
|
};
|
|
users.users.ocserv = {
|
|
isNormalUser = false;
|
|
isSystemUser = true;
|
|
extraGroups = [ "ocserv" "acmerecievers" ];
|
|
};
|
|
services.ocserv = {
|
|
enable = true;
|
|
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
|
|
'';
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/social/pleroma-package.nix << EOF
|
|
{ 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" ];
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/social/pleroma-module.nix << EOF
|
|
{ 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 ];
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/social/pleroma.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
nixpkgs.overlays = [(self: super: {
|
|
pleroma-otp = self.callPackage ./pleroma-package.nix {};
|
|
})];
|
|
services = {
|
|
pleroma = {
|
|
enable = true;
|
|
user = "pleroma";
|
|
group = "pleroma";
|
|
configs = [
|
|
(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 '$DB_PASSWORD';
|
|
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" ];
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/social/config.exs << EOF
|
|
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
|
|
|
|
EOF
|
|
|
|
cat > /etc/nixos/mailserver/system/alps.nix << EOF
|
|
{ pkgs, lib, fetchgit, buildGoModule, ... }: {
|
|
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";
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/mailserver/system/alps-package.nix << EOF
|
|
{ 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;
|
|
};
|
|
}
|
|
EOF
|
|
|
|
[[ -n "$doNetConf" ]] && makeNetworkingConf || true
|
|
}
|
|
|
|
makeNetworkingConf() {
|
|
# XXX It'd be better if we used procfs for all this...
|
|
local IFS=$'\n'
|
|
eth0_name=$(ip address show | grep '^2:' | awk -F': ' '{print $2}')
|
|
eth0_ip4s=$(ip address show dev "$eth0_name" | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')
|
|
eth0_ip6s=$(ip address show dev "$eth0_name" | grep 'inet6 ' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|' || '')
|
|
gateway=$(ip route show dev "$eth0_name" | grep default | sed -r 's|default via ([0-9.]+).*|\1|')
|
|
gateway6=$(ip -6 route show dev "$eth0_name" | grep default | sed -r 's|default via ([0-9a-f:]+).*|\1|' || true)
|
|
ether0=$(ip address show dev "$eth0_name" | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|')
|
|
|
|
eth1_name=$(ip address show | grep '^3:' | awk -F': ' '{print $2}')||true
|
|
if [ -n "$eth1_name" ];then
|
|
eth1_ip4s=$(ip address show dev "$eth1_name" | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|')
|
|
eth1_ip6s=$(ip address show dev "$eth1_name" | grep 'inet6 ' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|' || '')
|
|
ether1=$(ip address show dev "$eth1_name" | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|')
|
|
interfaces1=<< EOF
|
|
$eth1_name = {
|
|
ipv4.addresses = [$(for a in "${eth1_ip4s[@]}"; do echo -n "
|
|
$a"; done)
|
|
];
|
|
ipv6.addresses = [$(for a in "${eth1_ip6s[@]}"; do echo -n "
|
|
$a"; done)
|
|
];
|
|
EOF
|
|
extraRules1="ATTR{address}==\"${ether1}\", NAME=\"${eth1_name}\""
|
|
else
|
|
interfaces1=""
|
|
extraRules1=""
|
|
fi
|
|
|
|
readarray nameservers < <(grep ^nameserver /etc/resolv.conf | sed -r 's/^nameserver[[:space:]]+([0-9.a-fA-F]+).*/"\1"/')
|
|
|
|
if [[ "$eth0_name" = eth* ]]; then
|
|
predictable_inames="usePredictableInterfaceNames = lib.mkForce false;"
|
|
else
|
|
predictable_inames="usePredictableInterfaceNames = lib.mkForce true;"
|
|
fi
|
|
cat > /etc/nixos/networking.nix << EOF
|
|
{ lib, ... }: {
|
|
# This file was populated at runtime with the networking
|
|
# details gathered from the active system.
|
|
networking = {
|
|
nameservers = [ ${nameservers[@]} ];
|
|
defaultGateway = "${gateway}";
|
|
defaultGateway6 = "${gateway6}";
|
|
dhcpcd.enable = false;
|
|
$predictable_inames
|
|
interfaces = {
|
|
$eth0_name = {
|
|
ipv4.addresses = [$(for a in "${eth0_ip4s[@]}"; do echo -n "
|
|
$a"; done)
|
|
];
|
|
ipv6.addresses = [$(for a in "${eth0_ip6s[@]}"; do echo -n "
|
|
$a"; done)
|
|
];
|
|
ipv4.routes = [ { address = "${gateway}"; prefixLength = 32; } ];
|
|
ipv6.routes = [ { address = "${gateway6}"; prefixLength = 32; } ];
|
|
};
|
|
$interfaces1
|
|
};
|
|
};
|
|
services.udev.extraRules = ''
|
|
ATTR{address}=="${ether0}", NAME="${eth0_name}"
|
|
$extraRules1
|
|
'';
|
|
}
|
|
EOF
|
|
}
|
|
|
|
makeSwap() {
|
|
# TODO check currently available swapspace first
|
|
swapFile=$(mktemp /tmp/nixos-infect.XXXXX.swp)
|
|
dd if=/dev/zero "of=$swapFile" bs=1M count=$((1*1024))
|
|
chmod 0600 "$swapFile"
|
|
mkswap "$swapFile"
|
|
swapon -v "$swapFile"
|
|
}
|
|
|
|
removeSwap() {
|
|
swapoff -a
|
|
rm -vf /tmp/nixos-infect.*.swp
|
|
}
|
|
|
|
prepareEnv() {
|
|
# $grubdev is used in makeConf()
|
|
for grubdev in /dev/vda /dev/sda; do [[ -e $grubdev ]] && break; done
|
|
|
|
# Retrieve root fs block device
|
|
# (get root mount) (get partition or logical volume)
|
|
rootfsdev=$(mount | grep "on / type" | awk '{print $1;}')
|
|
|
|
# DigitalOcean doesn't seem to set USER while running user data
|
|
export USER="root"
|
|
export HOME="/root"
|
|
|
|
# Nix installer tries to use sudo regardless of whether we're already uid 0
|
|
#which sudo || { sudo() { eval "$@"; }; export -f sudo; }
|
|
# shellcheck disable=SC2174
|
|
mkdir -p -m 0755 /nix
|
|
}
|
|
|
|
fakeCurlUsingWget() {
|
|
# Use adapted wget if curl is missing
|
|
which wget && { \
|
|
curl() {
|
|
eval "wget $(
|
|
(local isStdout=1
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
"-o")
|
|
echo "-O";
|
|
isStdout=0
|
|
;;
|
|
"-O")
|
|
isStdout=0
|
|
;;
|
|
"-L")
|
|
;;
|
|
*)
|
|
echo "$arg"
|
|
;;
|
|
esac
|
|
done;
|
|
[[ $isStdout -eq 1 ]] && echo "-O-"
|
|
)| tr '\n' ' '
|
|
)"
|
|
}; export -f curl; }
|
|
}
|
|
|
|
req() {
|
|
type "$1" > /dev/null 2>&1 || which "$1" > /dev/null 2>&1
|
|
}
|
|
|
|
checkEnv() {
|
|
# Perform some easy fixups before checking
|
|
# TODO prevent multiple calls to apt-get update
|
|
which dnf && dnf install -y perl-Digest-SHA # Fedora 24
|
|
which bzcat || (which yum && yum install -y bzip2) \
|
|
|| (which apt-get && apt-get update && apt-get install -y bzip2) \
|
|
|| true
|
|
which xzcat || (which yum && yum install -y xz-utils) \
|
|
|| (which apt-get && apt-get update && apt-get install -y xz-utils) \
|
|
|| true
|
|
which curl || fakeCurlUsingWget \
|
|
|| (which apt-get && apt-get update && apt-get install -y curl) \
|
|
|| true
|
|
|
|
[[ "$(whoami)" == "root" ]] || { echo "ERROR: Must run as root"; return 1; }
|
|
|
|
req curl || req wget || { echo "ERROR: Missing both curl and wget"; return 1; }
|
|
req bzcat || { echo "ERROR: Missing bzcat"; return 1; }
|
|
req xzcat || { echo "ERROR: Missing xzcat"; return 1; }
|
|
req groupadd || { echo "ERROR: Missing groupadd"; return 1; }
|
|
req useradd || { echo "ERROR: Missing useradd"; return 1; }
|
|
req ip || { echo "ERROR: Missing ip"; return 1; }
|
|
req awk || { echo "ERROR: Missing awk"; return 1; }
|
|
req cut || { echo "ERROR: Missing cut"; return 1; }
|
|
}
|
|
|
|
infect() {
|
|
# Add nix build users
|
|
# FIXME run only if necessary, rather than defaulting true
|
|
groupadd nixbld -g 30000 || true
|
|
for i in {1..10}; do
|
|
useradd -c "Nix build user $i" -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(which nologin)" "nixbld$i" || true
|
|
done
|
|
# TODO use addgroup and adduser as fallbacks
|
|
#addgroup nixbld -g 30000 || true
|
|
#for i in {1..10}; do adduser -DH -G nixbld nixbld$i || true; done
|
|
|
|
curl -L https://nixos.org/nix/install | $SHELL
|
|
|
|
# shellcheck disable=SC1090
|
|
source ~/.nix-profile/etc/profile.d/nix.sh
|
|
|
|
[[ -z "$NIX_CHANNEL" ]] && NIX_CHANNEL="nixos-19.09"
|
|
nix-channel --remove nixpkgs
|
|
nix-channel --add "https://nixos.org/channels/$NIX_CHANNEL" nixos
|
|
nix-channel --update
|
|
|
|
export NIXOS_CONFIG=/etc/nixos/configuration.nix
|
|
|
|
nix-env --set \
|
|
-I nixpkgs=$HOME/.nix-defexpr/channels/nixos \
|
|
-f '<nixpkgs/nixos>' \
|
|
-p /nix/var/nix/profiles/system \
|
|
-A system
|
|
|
|
# Remove nix installed with curl | bash
|
|
rm -fv /nix/var/nix/profiles/default*
|
|
/nix/var/nix/profiles/system/sw/bin/nix-collect-garbage
|
|
|
|
# Reify resolv.conf
|
|
[[ -L /etc/resolv.conf ]] && mv -v /etc/resolv.conf /etc/resolv.conf.lnk && cat /etc/resolv.conf.lnk > /etc/resolv.conf
|
|
|
|
# Stage the Nix coup d'état
|
|
touch /etc/NIXOS
|
|
echo etc/nixos > /etc/NIXOS_LUSTRATE
|
|
echo etc/resolv.conf >> /etc/NIXOS_LUSTRATE
|
|
echo root/.nix-defexpr/channels >> /etc/NIXOS_LUSTRATE
|
|
|
|
rm -rf /boot.bak
|
|
mv -v /boot /boot.bak
|
|
/nix/var/nix/profiles/system/bin/switch-to-configuration boot
|
|
}
|
|
|
|
[ "$PROVIDER" = "digitalocean" ] && doNetConf=y # digitalocean requires detailed network config to be generated
|
|
|
|
apt update
|
|
apt install -y git whois
|
|
prepareEnv
|
|
makeSwap # smallest (512MB) droplet needs extra memory!
|
|
checkEnv
|
|
makeConf
|
|
infect
|
|
removeSwap
|
|
|
|
if [[ -z "$NO_REBOOT" ]]; then
|
|
reboot
|
|
fi
|