297 lines
11 KiB
Bash
Executable File
297 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Collecting authentification data
|
|
|
|
InstallDependencies()
|
|
{
|
|
packagesNeeded='curl jq expect pwgen'
|
|
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
|
|
wget https://selfprivacy.org/goss.nix
|
|
wget https://selfprivacy.org/restic.nix
|
|
wget https://selfprivacy.org/restic.yaml
|
|
wget https://selfprivacy.org/s3cli
|
|
}
|
|
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: " 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()
|
|
{
|
|
# Mailserver
|
|
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
|
|
|
|
# System Configuration
|
|
sed -i "15s,.*,\t\"${sshKey}\"," configuration.nix
|
|
sed -i "16s,.*,\t restic -r s3:s3.amazonaws.com/${AWS_BUCKET_NAME} backup /var/vmail /var/vmail ," restic.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()
|
|
{
|
|
mkdir ~/.aws
|
|
touch ~/.aws/credentials
|
|
echo "[default]" >> ~/.aws/credentials
|
|
echo "aws_access_key_id=$AWS_TOKEN_ID" >> ~/.aws/credentials
|
|
echo "aws_secret_access_key=$AWS_TOKEN" >> ~/.aws/credentials
|
|
if [[ -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
|
|
read "AWS S3 bucket found in your account. Do you want to restore backup from there? (y/n) " RESTORE_MAILBACKUP
|
|
else
|
|
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
|
|
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 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
|
|
sleep 3
|
|
ssh -i ~/.nix-ms/id_rsa "root@$machineip" nixos-rebuild switch
|
|
ssh -i ~/.nix-ms/id_rsa "root@$machineip" export AWS_ACCESS_KEY_ID=$AWS_TOKEN_ID
|
|
ssh -i ~/.nix-ms/id_rsa "root@$machineip" export AWS_SECRET_ACCESS_KEY=$AWS_TOKEN
|
|
}
|
|
|
|
RestoreBackup()
|
|
{
|
|
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 -rf ~/.nix-ms/
|
|
rm ~/.ssh/known_hosts
|
|
rm .healthz.json
|
|
rm .hetzner_machines.json
|
|
}
|
|
|
|
# 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" 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
|
|
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
|
|
}
|
|
|
|
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
|
|
#RunPreFlightChecks
|
|
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 240
|
|
CreateS3Bucket
|
|
GetMachineIP
|
|
ApplyConfig
|
|
if [$RESTORE_MAILBACKUP == "y"]; then
|
|
RestoreBackup
|
|
fi
|
|
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"
|