selfprivacy_fork/static/server.sh

352 lines
12 KiB
Bash

#!/bin/bash
# Collecting authentification data
InstallDependencies()
{
packagesNeeded='curl jq pwgen nano dnsutils'
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 curl jq whois pwgen # 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 sudo nix-env -iA $packagesNeeded # NixOS
elif [ -x "$(command -v pkg)" ]; then sudo pkg install $packagesNeeded # FreeBSD
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
wget https://selfprivacy.org/goss.nix
wget https://selfprivacy.org/goss.yaml
wget https://selfprivacy.org/restic.nix
wget https://selfprivacy.org/mkpasswd
wget https://selfprivacy.org/s3cli
chmod +x s3cli
chmod +x mkpasswd
export PASSWORD=$( ./mkpasswd -m sha-512 "$PASSWORD" )
}
CollectData()
{
read -p "Please, paste your Hetzner API token here: " HETZNER_TOKEN
read -p "Please, paste your CloudFlare Token: " CLOUDFLARE_TOKEN
read -p "Please, paste your AWS Secret Access Key: " AWS_TOKEN
read -p "Please, paste your AWS Access Key ID: " AWS_TOKEN_ID
read -p "Please, define your domain there: " DOMAIN
read -p "Please, define your mail username: " USER
read -p "Please, define your password: " 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()
{
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()
{
# Mailserver
sed -i '17s/.*/ fqdn = "'$DOMAIN'";/' mailserver.nix
sed -i '18s/.*/ domains = [ "'"$DOMAIN"'" ];/' mailserver.nix
sed -i '23s/.*/\t"'$USER'@'$DOMAIN'" = {/' mailserver.nix
sed -i "24s,.*,\t\ hashedPassword = \"${PASSWORD}\";," mailserver.nix
sed -i '33s/.*/\t\t"'"$DOMAIN"'"/' mailserver.nix
sed -i '50s/.*/\t "admin@'"$DOMAIN"'" = "'"$USER"'@'"$DOMAIN"'";/' mailserver.nix
sed -i '72s/.*/ email = "'"$USER"'@'"$DOMAIN"'";/' mailserver.nix
# System Configuration
sed -i "16s,.*,\t\"${sshKey}\"," configuration.nix
# Restic
sed -i '14s/.*/\t\tEnvironment = [ "AWS_ACCESS_KEY_ID='$AWS_TOKEN_ID'" "AWS_SECRET_ACCESS_KEY='$AWS_TOKEN'" ];/' restic.nix
sed -i "17s,.*,\t restic -r s3:s3.amazonaws.com/${AWS_BUCKET_NAME} backup /var/vmail /var/vmail ," restic.nix
nano mailserver.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
}
CreateS3BucketRaw()
{
local date="$(date -u '+%a, %e %b %Y %H:%M:%S +0000')"
local string_to_sign
local MD5=""
printf -v string_to_sign "%s\n%s\n\n%s\n%s" "PUT" "$MD5" "$date" "$path"
signature=$(echo -n "$string_to_sign" | openssl sha1 -binary -hmac "${AWS_SECRET_ACCESS_KEY}" | openssl base64)
curl -s \
-X PUT \
-H "Host: $AWS_TOKEN_ID.s3-control.us-east-2.amazonaws.com" \
-H "Content-Length: 0" \
-H "Date: $(date +'%a, %d %b %Y %H:%M:%S %Z')" \
-H "Authorization: AWS $AWS_TOKEN_ID:$signature"
}
CreateS3Bucket()
{
if test -z $(./s3cli -e http://s3.us-east-2.amazonaws.com --ak "$AWS_TOKEN_ID" --sk "$AWS_TOKEN" --region us-east-2 bucket ls | grep backup)
then
export AWS_BUCKET_NAME=$(pwgen -1 --no-capitalize 6)-backup
./s3cli -e http://s3.us-east-2.amazonaws.com --ak "$AWS_TOKEN_ID" --sk "$AWS_TOKEN" --region us-east-2 bucket create $AWS_BUCKET_NAME
else
read -p "Restore from backup? y/n " RESTORE_MAILBACKUP
fi
}
# 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.nix "root@$machineip:/root"
scp -i ~/.nix-ms/id_rsa restic.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
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/goss.nix /etc/nixos/goss.nix
ssh -i ~/.nix-ms/id_rsa "root@$machineip" cp /root/restic.nix /etc/nixos/restic.nix
sleep 3
ssh -i ~/.nix-ms/id_rsa "root@$machineip" nixos-rebuild switch
}
RestoreBackup()
{
export AWS_BUCKET_NAME=$(./s3cli -e http://s3.us-east-2.amazonaws.com --ak "$AWS_TOKEN_ID" --sk "$AWS_TOKEN" --region us-east-2 bucket ls | grep backup)
ssh -i ~/.nix-ms/id_rsa "root@$machineip" restic -r s3:s3.amazonaws/$AWS_BUCKET_NAME restore latest --target /var/vmail /var/dkim
}
# 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 ~/.ssh/known_hosts
rm configuration.nix
rm goss.nix
rm goss.yaml
rm mailserver.nix
rm restic.nix
rm s3cli
rm .dns_records.json
rm .records
rm mkpasswd
exit 0
}
# 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/"$//' )
}
#Purge DNS records
PurgeDNSRecords()
{
curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" > .dns_records.json
for i in {0..24}
do
jq '.result['$i'].id' .dns_records.json
done | grep -v null | sed 's/"//g' > .records
export recordIDs=()
while IFS= read -r line
do
recordIDs+=("$line")
done < .records
for recordid in "${recordIDs[@]}"
do
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$recordid" \
-H "Authorization: Bearer $CLOUDFLARE_TOKEN" \
-H "Content-Type: application/json" > /dev/null
done
}
WaitDNSPropagation()
{
printf "Waiting for DNS Record to propagate..."
while [[ $( dig $DOMAIN a +short ) != $machineip ]]
do
sleep 1
done
printf "done"
}
# 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" restic -r s3:s3.amazonaws.com/$AWS_BUCKET_NAME init
ssh -i ~/.nix-ms/id_rsa "root@$machineip" restic -r s3:s3.amazonaws.com/$AWS_BUCKET_NAME forget --prune --keep-hourly 2 --keep-daily 7 --keep-weekly 4
}
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
}
RunPreFlightChecks()
{
curl -H "Authorization: Bearer $HETZNER_TOKEN" 'https://api.hetzner.cloud/v1/servers' > .hetzner_test.json
jq 'if .error != null then "Preflight checks failed" else "Success" end' .hetzner_test.json | if [ "Preflight checks failed" ]
then
echo "Hetzner Authorization failed"
exit -1
fi
}
if test -z "$HETZNER_TOKEN" || test -z "$CLOUDFLARE_TOKEN" || test -z "$PASSWORD"
then
CollectData
if [ ${#HETZNER_TOKEN} != 64 ]
then
echo "Hetzner Token is incorrect. Please double check your input"
exit -1
elif [ ${#CLOUDFLARE_TOKEN} != 40 ]
then
echo "Cloudflare Token is incorrect. Please double check your input"
exit -1
elif [[ ${DOMAIN} != *.* ]]
then
echo "Got unexpected domain. Possibly wrong input"
exit -1
fi
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 280
CreateS3Bucket
GetMachineIP
read -p "ALL YOUR EXISTING DNS RECORDS ON CLOUDFLARE WILL BE REMOVED!!! ARE YOU SURE(y/N) " CREATEDNS
if [ $CREATEDNS != "y" || $CREATEDNS == "Y" ]
then
exit -1
fi
printf "Purging records..."
GetZoneID
PurgeDNSRecords
printf "done"
CreateARecord
WaitDNSPropagation
ApplyConfig
if [ $RESTORE_MAILBACKUP == "y" ]
then
RestoreBackup
fi
GetDKIM
echo "Beginning CloudFlare configuration"
GetZoneID
printf "Creating records..."
CreateMXRecord
CreateDMARCRecord
CreateSPFRecord
CreateDKIMRecord
printf "done\n"
PostInstallation
printf "Clearing temporary files..."
ClearTempFiles
printf "done\n"