mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect.git
synced 2024-11-25 13:01:28 +00:00
902 lines
24 KiB
Bash
Executable file
902 lines
24 KiB
Bash
Executable file
#! /usr/bin/env bash
|
|
|
|
# More info at: https://github.com/elitak/nixos-infect
|
|
|
|
set -e -o pipefail
|
|
|
|
makeConf() {
|
|
# 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/letsencrypt
|
|
mkdir /etc/nixos/backup
|
|
mkdir /etc/nixos/passmgr
|
|
mkdir /etc/nixos/nginx
|
|
mkdir /etc/nixos/git
|
|
mkdir /etc/nixos/nextcloud
|
|
mkdir /etc/nixos/resources
|
|
mkdir /etc/nixos/videomeet
|
|
mkdir /etc/nixos/openconnect
|
|
|
|
# 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
|
|
./mailserver/system/mailserver.nix
|
|
./openconnect/shadowsocks.nix
|
|
./api/api.nix
|
|
./api/api-service.nix
|
|
./letsencrypt/acme.nix
|
|
./backup/restic.nix
|
|
./passmgr/bitwarden.nix
|
|
./nginx/nginx.nix
|
|
./nextcloud/nextcloud.nix
|
|
./resources/limits.nix
|
|
./videomeet/jitsi.nix
|
|
./git/gitea.nix
|
|
];
|
|
|
|
boot.cleanTmpDir = true;
|
|
networking = {
|
|
hostName = "$(hostname)";
|
|
firewall = {
|
|
allowedTCPPorts = lib.mkForce [ 22 443 80 143 587 8388 ];
|
|
allowedUDPPorts = lib.mkForce [ 22 443 80 143 587 8388 ];
|
|
};
|
|
};
|
|
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; [
|
|
letsencrypt
|
|
mkpasswd
|
|
git
|
|
wget
|
|
curl
|
|
restic
|
|
pwgen
|
|
tmux
|
|
sudo
|
|
python3
|
|
] ++ (with python38Packages; [
|
|
pip
|
|
flask
|
|
pandas
|
|
]);
|
|
environment.variables = {
|
|
DOMAIN = "$DOMAIN";
|
|
AWS_ACCESS_KEY_ID = "$AWS_ACCESS_KEY_ID";
|
|
AWS_SECRET_ACCESS_KEY = "$AWS_SECRET_ACCESS_KEY";
|
|
};
|
|
system.autoUpgrade.enable = true;
|
|
system.autoUpgrade.allowReboot = false;
|
|
system.autoUpgrade.channel = https://nixos.org/channels/nixos-20.09-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;
|
|
wheelNeedsPassword = 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"; };
|
|
}
|
|
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
|
|
'';
|
|
shadowsocksPass = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$PASSWORD
|
|
'';
|
|
domain = builtins.replaceStrings [ "\n" "\"" "\\\" ] [ "\\\n" "\\\\\"" "\\\\\\\\" ] ''
|
|
$DOMAIN
|
|
'';
|
|
in
|
|
[
|
|
"d /var/restic 0660 restic - - -"
|
|
"d /var/bitwarden 0777 bitwarden_rs bitwarden_rs -"
|
|
"d /var/bitwarden/backup 0777 bitwarden_rs bitwarden_rs -"
|
|
"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/shadowsocks-password 0440 nobody nobody - \${shadowsocksPass}"
|
|
];
|
|
}
|
|
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;
|
|
};
|
|
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 = {
|
|
"$USER@$DOMAIN" = {
|
|
hashedPassword = "$HASHED_PASSWORD";
|
|
|
|
#aliases = [
|
|
# "mail@example.com"
|
|
#];
|
|
|
|
# Make this user the catchAll address for domains blah.com and
|
|
# example2.com
|
|
catchAll = [
|
|
"$DOMAIN"
|
|
];
|
|
sieveScript = ''
|
|
require ["fileinto", "mailbox"];
|
|
if header :contains "Chat-Version" "1.0"
|
|
{
|
|
fileinto :create "DeltaChat";
|
|
stop;
|
|
}
|
|
'';
|
|
};
|
|
|
|
};
|
|
|
|
# Extra virtual aliases. These are email addresses that are forwarded to
|
|
# loginAccounts addresses.
|
|
extraVirtualAliases = {
|
|
# address = forward address;
|
|
"admin@$DOMAIN" = "$USER@$DOMAIN";
|
|
};
|
|
|
|
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
|
|
# down nginx and opens port 80.
|
|
certificateScheme = 3;
|
|
|
|
# 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" "bitwarden_rs" "nextcloud" ];
|
|
};
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
email = "$USER@$DOMAIN";
|
|
certs = {
|
|
"$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
"git.$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
"cloud.$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
"password.$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
"api.$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
"meet.$DOMAIN" = {
|
|
group = "acmerecievers";
|
|
webroot = "/var/lib/acme/acme-challenge";
|
|
};
|
|
};
|
|
};
|
|
}
|
|
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;
|
|
};
|
|
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/nginx/nginx.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.nginx = {
|
|
enable = true;
|
|
recommendedGzipSettings = true;
|
|
recommendedOptimisation = true;
|
|
recommendedProxySettings = true;
|
|
recommendedTlsSettings = true;
|
|
|
|
virtualHosts = {
|
|
|
|
"$DOMAIN" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
};
|
|
"git.$DOMAIN" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://127.0.0.1:3000";
|
|
extraConfig = ''
|
|
proxy_headers_hash_max_size 512;
|
|
proxy_headers_hash_bucket_size 128;
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
"cloud.$DOMAIN" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://127.0.0.1:80/";
|
|
extraConfig = ''
|
|
proxy_headers_hash_max_size 512;
|
|
proxy_headers_hash_bucket_size 128;
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
"password.$DOMAIN" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://127.0.0.1:8222";
|
|
extraConfig = ''
|
|
proxy_headers_hash_max_size 512;
|
|
proxy_headers_hash_bucket_size 128;
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
"api.$DOMAIN" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://127.0.0.1:5050";
|
|
extraConfig = ''
|
|
proxy_headers_hash_max_size 512;
|
|
proxy_headers_hash_bucket_size 128;
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/nextcloud/nextcloud.nix << EOF
|
|
{ pkgs, ... }:
|
|
{
|
|
services.nextcloud = {
|
|
enable = true;
|
|
package = pkgs.nextcloud20;
|
|
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 = true;
|
|
hostName = "meet.$DOMAIN";
|
|
nginx.enable = true;
|
|
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;
|
|
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 = "d7a6b3ca12d936165a4fc1c6265a2dfc3fd6229e";
|
|
};
|
|
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-service.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/" ];
|
|
after = [ "network-online.target" ];
|
|
wantedBy = [ "network-online.target" ];
|
|
serviceConfig = {
|
|
User = "root";
|
|
PrivateDevices = "true";
|
|
ProtectKernelTunables = "true";
|
|
ProtectKernelModules = "true";
|
|
LockPersonality = "true";
|
|
RestrictRealtime = "true";
|
|
SystemCallFilter = "@system-service @network-io @signal";
|
|
SystemCallErrorNumber = "EPERM";
|
|
ExecStart = "\${selfprivacy-api}/bin/main.py";
|
|
Restart = "always";
|
|
RestartSec = "5";
|
|
};
|
|
};
|
|
};
|
|
}
|
|
EOF
|
|
|
|
cat > /etc/nixos/openconnect/shadowsocks.nix << EOF
|
|
{ pkgs, ...}:
|
|
{
|
|
services = {
|
|
shadowsocks = {
|
|
enable = true;
|
|
localAddress = [ "[::0]" "0.0.0.0" ];
|
|
port = 8388;
|
|
passwordFile = "/var/shadowsocks-password";
|
|
mode = "tcp_and_udp";
|
|
fastOpen = true;
|
|
encryptionMethod = "chacha20-ietf-poly1305";
|
|
};
|
|
};
|
|
}
|
|
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
|
|
prepareEnv
|
|
makeSwap # smallest (512MB) droplet needs extra memory!
|
|
checkEnv
|
|
makeConf
|
|
infect
|
|
removeSwap
|
|
|
|
if [[ -z "$NO_REBOOT" ]]; then
|
|
reboot
|
|
fi
|