diff --git a/nixos-infect b/nixos-infect index c711be9..0214d5b 100755 --- a/nixos-infect +++ b/nixos-infect @@ -5,28 +5,16 @@ 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, < /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.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 ]; - }; - nameservers = [ "1.1.1.1" "1.0.0.1" ]; + if isEFI; then + bootcfg=$(cat << EOF + boot.loader.grub = { + efiSupport = true; + efiInstallAsRemovable = true; + device = "nodev"; }; - 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; - }; - }; -} + fileSystems."/boot" = { device = "$esp"; fsType = "vfat"; }; EOF - # If you rerun this later, be sure to prune the filesSystems attr - cat > /etc/nixos/hardware-configuration.nix << EOF -{ ... }: -{ - imports = [ ]; +) + else + bootcfg=$(cat << EOF boot.loader.grub.device = "$grubdev"; - fileSystems = { - "/" = { device = "$rootfsdev"; fsType = "ext4"; }; - "/var" = { device = "/dev/sdb"; fsType = "ext4"; }; - }; -} EOF +) + fi - cat > /etc/nixos/files.nix << EOF -{ pkgs, ... }: + # If you rerun this later, be sure to prune the filesSystems attr + cat > /etc/nixos/hardware-configuration.nix << EOF +{ modulesPath, ... }: { - 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/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 = "$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.nextcloud22; - hostName = "cloud.$DOMAIN"; - - # Use HTTPS for links - https = true; - - # Auto-update Nextcloud Apps - autoUpdateApps.enable = true; - # Set what time makes sense for you - autoUpdateApps.startAt = "05:00:00"; - - config = { - # Further forces Nextcloud to use HTTPS - overwriteProtocol = "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 {}, 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 = "568add06c6d622d417582ce55e3cc960686721ed"; - }; - 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 = 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 ]; - 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 - -cisco-client-compat = true - - ''; - }; -} -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. - DO NOT STORE ANY PLEROMA SECRET - HERE, use - services.pleroma.secretConfigFile - 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. - DO NOT POINT THIS OPTION TO THE NIX - STORE, 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; - }; + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; +$bootcfg + boot.initrd.kernelModules = [ "nvme" ]; + fileSystems."/" = { device = "$rootfsdev"; fsType = "$rootfstype"; }; } EOF @@ -1160,7 +84,10 @@ EOF extraRules1="" fi - readarray nameservers < <(grep ^nameserver /etc/resolv.conf | sed -r 's/^nameserver[[:space:]]+([0-9.a-fA-F]+).*/"\1"/') + readarray nameservers < <(grep ^nameserver /etc/resolv.conf | sed -r \ + -e 's/^nameserver[[:space:]]+([0-9.a-fA-F:]+).*/"\1"/' \ + -e 's/127[0-9.]+/8.8.8.8/' \ + -e 's/::1/8.8.8.8/' ) if [[ "$eth0_name" = eth* ]]; then predictable_inames="usePredictableInterfaceNames = lib.mkForce false;" @@ -1186,7 +113,7 @@ EOF $a"; done) ]; ipv4.routes = [ { address = "${gateway}"; prefixLength = 32; } ]; - ipv6.routes = [ { address = "${gateway6}"; prefixLength = 32; } ]; + ipv6.routes = [ { address = "${gateway6}"; prefixLength = 128; } ]; }; $interfaces1 }; @@ -1197,6 +124,49 @@ EOF ''; } EOF + +cat > /etc/nixos/userdata/userdata.json << EOF +{ + "api": { + "token": "$API_TOKEN" + }, + "backblaze": { + "accountId": "$BACKBLAZE_KEY_ID", + "accountKey": "$BACKBLAZE_ACCOUNT_KEY", + "bucket": "$BACKBLAZE_BUCKET_NAME" + }, + "bitwarden": { + "enable": true + }, + "cloudflare": { + "apiKey": "$CF_TOKEN" + }, + "databasePassword": "$DB_PASSWORD", + "domain": "$DOMAIN", + "hashedMasterPassword": "$HASHED_PASSWORD", + "hostname": "$DOMAIN", + "nextcloud": { + "enable": true, + "adminPassword": "$PASSWORD", + "databasePassword": "$PASSWORD" + }, + "gitea": { + "enable": true + }, + "jitsi": { + "enable": true + }, + "ocserv": { + "enable": true + }, + "pleroma": { + "enable": true + }, + "timezone": "Europe/Uzhgorod", + "resticPassword": "$PASSWORD", + "username": "$LUSER" +} +EOF } makeSwap() { @@ -1213,13 +183,36 @@ removeSwap() { rm -vf /tmp/nixos-infect.*.swp } +isEFI() { + [ -d /sys/firmware/efi ] +} + +findESP() { + esp="" + for d in /boot/EFI /boot/efi /boot; do + [[ ! -d "$d" ]] && continue + [[ "$d" == "$(df "$d" --output=target | sed 1d)" ]] \ + && esp="$(df "$d" --output=source | sed 1d)" \ + && break + done + [[ -z "$esp" ]] && { echo "ERROR: No ESP mount point found"; return 1; } + for uuid in /dev/disk/by-uuid/*; do + [[ $(readlink -f "$uuid") == "$esp" ]] && echo $uuid && return 0 + done +} + prepareEnv() { - # $grubdev is used in makeConf() - for grubdev in /dev/vda /dev/sda; do [[ -e $grubdev ]] && break; done + # $esp and $grubdev are used in makeConf() + if isEFI; then + esp="$(findESP)" + else + for grubdev in /dev/vda /dev/sda /dev/nvme0n1 ; do [[ -e $grubdev ]] && break; done + fi # Retrieve root fs block device # (get root mount) (get partition or logical volume) rootfsdev=$(mount | grep "on / type" | awk '{print $1;}') + rootfstype=$(df $rootfsdev --output=fstype | sed 1d) # DigitalOcean doesn't seem to set USER while running user data export USER="root" @@ -1264,9 +257,11 @@ req() { } checkEnv() { + [[ "$(whoami)" == "root" ]] || { echo "ERROR: Must run as root"; return 1; } + # 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 dnf && dnf install -y perl-Digest-SHA) || true # Fedora 24 which bzcat || (which yum && yum install -y bzip2) \ || (which apt-get && apt-get update && apt-get install -y bzip2) \ || true @@ -1277,16 +272,14 @@ checkEnv() { || (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; } + 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 || req df || { echo "ERROR: Missing coreutils (cut, df)"; return 1; } } infect() { @@ -1305,7 +298,7 @@ infect() { # shellcheck disable=SC1090 source ~/.nix-profile/etc/profile.d/nix.sh - [[ -z "$NIX_CHANNEL" ]] && NIX_CHANNEL="nixos-19.09" + [[ -z "$NIX_CHANNEL" ]] && NIX_CHANNEL="nixos-21.05" nix-channel --remove nixpkgs nix-channel --add "https://nixos.org/channels/$NIX_CHANNEL" nixos nix-channel --update @@ -1332,21 +325,23 @@ infect() { echo root/.nix-defexpr/channels >> /etc/NIXOS_LUSTRATE rm -rf /boot.bak + isEFI && umount "$esp" mv -v /boot /boot.bak + if isEFI; then + mkdir /boot + mount "$esp" /boot + find /boot -depth ! -path /boot -exec rm -rf {} + + fi /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 -cat > /etc/resolv.conf << EOF -nameserver 1.1.1.1 -nameserver 1.0.0.1 -EOF +apt install git tar wget curl +checkEnv prepareEnv makeSwap # smallest (512MB) droplet needs extra memory! -checkEnv makeConf infect removeSwap