#!/bin/bash # Collecting authentification data InstallDependencies() { packagesNeeded='curl jq' if [ -x "$(command -v apk)" ]; then sudo apk add --no-cache $packagesNeeded # Alpine Linux elif [ -x "$(command -v apt-get)" ]; then sudo apt-get install $packagesNeeded # Debian/Ubuntu Linux elif [ -x "$(command -v dnf)" ]; then sudo dnf install $packagesNeeded # Fedora Linux elif [ -x "$(command -v rpm-ostree)" ]; then sudo rpm-ostree install $packagesNeeded # Fedora Linux Silverblue elif [ -x "$(command -v zypper)" ]; then sudo zypper install $packagesNeeded # openSUSE Linux elif [ -x "$(command -v pacman)" ]; then sudo pacman -S $packagesNeeded # Arch/Manjaro Linux elif [ -x "$(command -v emerge)" ]; then sudo emerge --ask $packagesNeeded # Gentoo Linux elif [ -x "$(command -v nix-env)" ]; then nix-env -iA $packagesNeeded # NixOS else echo "FAILED TO INSTALL PACKAGE: Package manager not found. You must manually install: $packagesNeeded">&2; fi wget https://selfprivacy.org/configuration.nix wget https://selfprivacy.org/mailserver.nix } CollectData() { read -p "Please, paste your Hetzner API token here: " HETZNER_TOKEN echo $HETZNER_TOKEN read -p "Please paste your CloudFlare Token: " CLOUDFLARE_TOKEN echo $CLOUDFLARE_TOKEN read -p "Please define your domain there: " DOMAIN echo $DOMAIN read -p "Please define your mail username: " USERNAME echo $USERNAME read -p "Please define your password: " PASSWORD && PASSWORD=$( mkpasswd -m sha-512 "$PASSWORD" ) } # Generate SSH key GenerateSSHKey() { echo "Generating SSH keys..." mkdir ~/.nix-ms ssh-keygen -f ~/.nix-ms/id_rsa > /dev/null export sshKey=$( cat ~/.nix-ms/id_rsa.pub ) } # Add SSH key to Hetzner AddSSHKey() { echo "Adding SSH keys to Hetzner..." curl -s \ -X POST \ -H "Authorization: Bearer $HETZNER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"nixosms","public_key":"'"${sshKey}"'","labels":{}}' \ 'https://api.hetzner.cloud/v1/ssh_keys' > /dev/null } # Create NixOS config file MakeConfig() { sed -i '15s/.*/ fqdn = "'$DOMAIN'";/' mailserver.nix sed -i '16s/.*/ domains = [ "'"$DOMAIN"'" ];/' mailserver.nix sed -i '21s/.*/\t"'$USERNAME'@'$DOMAIN'" = {/' mailserver.nix sed -i '22s/.*/\t hashedPassword = "'"$PASSWORD"'";/' mailserver.nix sed -i '31s/.*/\t\t"'"$DOMAIN"'"/' mailserver.nix sed -i '41s/.*/\t "admin@'"$DOMAIN"'" = "'"$USERNAME"'@'"$DOMAIN"'";/' mailserver.nix sed -i '63s/.*/ email = "'"$USERNAME"'@'"$DOMAIN"'";/' mailserver.nix sed -i "16s,.*,\t\"${sshKey}\"," configuration.nix } MakeServer() { echo "Creating Server..." curl -s \ -X POST \ -H "Authorization: Bearer $HETZNER_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"nixos-mailserver","server_type":"cx11","start_after_create":true,"image":"ubuntu-20.04","ssh_keys":["nixosms"],"volumes":[],"networks":[],"user_data":"#cloud-config\nruncmd:\n- curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-20.03 bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":false}' \ 'https://api.hetzner.cloud/v1/servers' > /dev/null } # Get machine IP GetMachineIP() { curl -s \ -H "Authorization: Bearer $HETZNER_TOKEN" \ 'https://api.hetzner.cloud/v1/servers' > .machine.json export machineip=$( for i in {0..24}; do jq 'if .servers['$i'].name == "nixos-mailserver" then .servers['$i'].public_net.ipv4.ip else null end' .machine.json; done | grep -v null | sed 's/"//' | sed 's/"//' ) } # Copy and apply mailserver config ApplyConfig() { ssh -i ~/.nix-ms/id_rsa "root@$machineip" echo "Authentificated" scp -i ~/.nix-ms/id_rsa mailserver.nix "root@$machineip:/root" scp -i ~/.nix-ms/id_rsa configuration.nix "root@$machineip:/root" scp -i ~/.nix-ms/id_rsa goss.yaml "root@$machineip:/root" ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/mailserver.nix /etc/nixos/mailserver.nix ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/configuration.nix /etc/nixos/configuration.nix sleep 3 ssh -i ~/.nix-ms/id_rsa "root@$machineip" nixos-rebuild switch } # Get DKIM keys from remote machine GetDKIM() { scp -i ~/.nix-ms/id_rsa "root@$machineip:/var/dkim/$DOMAIN.selector.txt" . sed -i '1d' $DOMAIN.selector.txt sed -i 's/ ) ; ----- DKIM key selector for '$DOMAIN'//g' $DOMAIN.selector.txt export dkim=$( cat $DOMAIN.selector.txt ) } ClearTempFiles() { rm .machine.json rm .cloudflare.json rm $DOMAIN.selector.txt rm -rf ~/.nix-ms/ rm ~/.ssh/known_hosts } # Cloudflare configuration # Get zone ID GetZoneID() { curl -s -X GET "https://api.cloudflare.com/client/v4/zones" \ -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \ -H "Content-Type: application/json" > .cloudflare.json export zoneid=$( for i in {0..24}; do jq 'if .result['$i'].name == "'$DOMAIN'" then .result['$i'].id else null end' .cloudflare.json; done | grep -v null | sed -e 's/^"//' -e 's/"$//' ) } # Create records CreateARecord() { curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \ -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \ -H "Content-Type: application/json" \ --data '{"type":"A","name":"'$DOMAIN'","content":"'$machineip'","ttl":3600,"priority":10,"proxied":false}' > /dev/null } CreateMXRecord() { curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \ -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \ -H "Content-Type: application/json" \ --data '{"type":"MX","name":"@","content":"'$DOMAIN'","ttl":3600,"priority":10,"proxied":false}' > /dev/null } CreateDMARCRecord() { curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \ -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \ -H "Content-Type: application/json" \ --data '{"type":"TXT","name":"_dmarc","content":"v=DMARC1; p=none","ttl":18000,"priority":10,"proxied":false}' > /dev/null } CreateSPFRecord() { curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \ -H "Authorization: Bearer $CLOUDFLARE_TOKEN" \ -H "Content-Type: application/json" \ --data '{"type":"TXT","name":"'$DOMAIN'","content":"v=spf1 a mx ip4:'$machineip' -all","ttl":18000,"priority":10,"proxied":false}' > /dev/null } CreateDKIMRecord() { export dkim=$( echo $dkim | sed -e 's/^"//' -e 's/"$//' ) curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" -H "Authorization: Bearer $CLOUDFLARE_TOKEN" -H "Content-Type: application/json" --data '{"type":"TXT","name":"selector._domainkey","content":"v=DKIM1; '$dkim'","ttl":18000,"priority":10,"proxied":false}' > /dev/null } PostInstallation() { ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/result/bin/goss /root/ ssh -i ~/.nix-ms/id_rsa "root@$machineip" /root/goss serve --format json & } PerformTests() { curl $machineip:8080/healthz > .healthz.json for i in {0..24}; do jq 'if .results['$i'].err != null then "FAIL" else "OK" end' .healthz.json; done } if test -z "$HETZNER_TOKEN" || test -z "$CLOUDFLARE_TOKEN" || test -z "$PASSWORD" then CollectData fi InstallDependencies GenerateSSHKey printf "Importing SSH key into your Hetzner account..." AddSSHKey printf "done\n" printf "Generating config file..." MakeConfig printf "done\n" printf "Waiting for the server to create...\n" MakeServer sleep 30 printf "Waiting for nixos-infect to replace system files(this may take some time)...\n" sleep 200 GetMachineIP ApplyConfig GetDKIM echo "Beginning CloudFlare configuration" GetZoneID printf "Creating records..." CreateARecord CreateMXRecord CreateDMARCRecord CreateSPFRecord CreateDKIMRecord printf "done\n" PostInstallation PerformTests #while ! ping -c1 192.168.0.107 &>/dev/null # do echo "Ping Fail - `date`" #done #echo "Host Found - `date`" printf "Clearing temporary files..." ClearTempFiles printf "done\n"