aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-01-17 20:14:10 +0000
committerMatthew Lemon <y@yulqen.org>2024-01-17 20:14:10 +0000
commitd5bb061c65466229ebc268ab2b65eaf78bc7fb94 (patch)
tree39dcb1a7a2194611c96a5488492ec22b3cbd1f09
parent8b12b1f7f96677a1df0a1c563305985b1c210a9a (diff)
Adds Derek Sivers server setup script
-rw-r--r--derek_sivers_openbsd_setup_script.sh568
1 files changed, 568 insertions, 0 deletions
diff --git a/derek_sivers_openbsd_setup_script.sh b/derek_sivers_openbsd_setup_script.sh
new file mode 100644
index 0000000..0b78fc4
--- /dev/null
+++ b/derek_sivers_openbsd_setup_script.sh
@@ -0,0 +1,568 @@
+#!/bin/sh
+# by Derek Sivers
+# Updated: 2023-11-07
+# INSTALL: cd /root ; ftp https://sive.rs/ti.sh ; sh ti.sh
+# README: https://sive.rs/ti
+
+if [[ $(id -u) -ne 0 || $(uname) != "OpenBSD" ]]; then
+ echo "must be run as root on OpenBSD"
+ exit 1
+fi
+
+
+# tiny files where your answers are saved, so you can run this again and not answer again
+# to add another user, do `rm /root/my/user*` then run this script again
+mkdir -p /root/my
+function my {
+ echo "/root/my/$1"
+}
+
+
+# INITIAL SETUP
+if [ ! -f /usr/local/bin/curl ]; then
+ echo "updating..."
+ syspatch
+ # disable IPv6 and sound
+ rcctl disable slaacd sndiod
+ # shorten motd for future logins
+ cat /etc/motd | head -3 | grep -v '^$' > /tmp/motd
+ mv /tmp/motd /etc/motd
+ # install needed software
+ pkg_add curl rsync--iconv radicale-2.1.12p5 links mutt--sasl dovecot
+fi
+# download config files
+set -A a pf.conf httpd.conf relayd.conf acme-client.conf .muttrc .mailcap smtpd.conf dovecot.conf hello.txt hello.pdf derek.jpg guitar.mp3 ymap.mp4
+for x in "${a[@]}"; do
+ if [ ! -f $x ]; then
+ ftp https://sive.rs/file/$x
+ fi
+done
+if [ -f pf.conf ]; then
+ mv pf.conf /etc/pf.conf
+ pfctl -f /etc/pf.conf
+fi
+
+
+# DOMAIN?
+if [ -f $(my domain) ]; then
+ domain=$(cat $(my domain))
+else
+ printf "Your domain name? "
+ read ui
+ # strip whitespace, convert to lowercase, and remove 'www.' prefix
+ domain=$(echo "$ui" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/^www\.//')
+ # save to a file for next time
+ echo $domain > $(my domain)
+fi
+
+
+# USERNAME?
+if [ -f $(my user) ]; then
+ user=$(cat $(my user))
+else
+ printf "Your user name? (one lowercase word, no spaces): "
+ read ui
+ # strip whitespace, convert to lowercase, and remove all but a-z and 0-9
+ user=$(echo "$ui" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g')
+ # save to a file for next time
+ echo $user > $(my user)
+fi
+
+
+# DOMAIN AND USER OK?
+if [ ! -f $(my userok) ]; then
+ echo "Email and login will be $user@$domain"
+ printf "Does that look right? (y/n) "
+ read ui
+ # strip whitespace, convert to lowercase, get just first letter
+ yn=$(echo "$ui" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | cut -c1-1)
+ if [ $yn == "y" ]; then
+ # touch file for next time
+ touch $(my userok)
+ else
+ rm $(my domain) $(my user)
+ echo "Please run this script again."
+ exit 1
+ fi
+fi
+
+
+# FULL NAME?
+if [ -f $(my userfullname) ]; then
+ name=$(cat $(my userfullname))
+else
+ printf "Your full name? "
+ read name
+ # save to a file for next time
+ echo "$name" > $(my userfullname)
+fi
+
+
+# IP ADDRESS?
+if [ -f $(my ip) ]; then
+ ip=$(cat $(my ip))
+else
+ ip=$(ifconfig vio0 | grep inet | awk '/inet/ {print $2}')
+ # alternate: curl -s icanhazip.com
+ # save to a file for next time
+ echo $ip > $(my ip)
+fi
+echo "IP address is $ip"
+
+
+# ADD USER
+if [[ ! -d /home/$user ]]; then
+ echo "Create a secret password for $user, for login and email:"
+ groupadd $user
+ useradd -b /home -g $user -k /etc/skel -L staff -s /bin/ksh -d /home/$user -m -c "$name" $user
+ passwd $user
+ cat /root/.ssh/authorized_keys >> /home/$user/.ssh/authorized_keys
+ echo "permit persist $user" >> /etc/doas.conf
+ printf "\n\n#############################\n"
+ echo "TEST #1: LOG IN"
+ echo "Open a NEW terminal window on your computer, and type this:"
+ echo "ssh $user@$ip"
+ echo ""
+ echo "It should say 'OpenBSD 7.4 (GENERIC.MP)' and 'Welcome to OpenBSD'."
+ echo "After that works, come back to this terminal window."
+ printf "I'll wait"
+ loggedin=""
+ while [[ $loggedin == "" ]]; do
+ printf "."
+ sleep 3
+ loggedin=$(w|grep ^$user)
+ done
+ echo "YOU DID IT! Logging out that user now, because it's time for..."
+ # find new user's SSH session and kill it to log them out
+ pid=$(ps aux|grep sshd|grep ^$user|tail -1|awk '{print $2}')
+ kill -HUP $pid
+ echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
+ rcctl restart sshd
+ printf "\n\n#############################\n"
+ echo "TEST #2: LOG IN WITHOUT A PASSWORD"
+ echo "Because I just disabled passwords, for super-security, make sure you can"
+ echo "log in with your SSH public key."
+ echo "Back in that other terminal window on your computer, login again like this:"
+ echo "ssh $user@$ip"
+ echo ""
+ echo "Again, it should say 'OpenBSD 7.4 (GENERIC.MP)' and 'Welcome to OpenBSD'."
+ echo ""
+ # if trouble:
+ # sed -i "s/PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
+ # rcctl restart sshd
+ echo "If it doesn't work, hit Ctrl-C here and use root user to copy the contents"
+ echo "of your SSH public key (id_ed25519.pub) into /home/$user/.ssh/authorized_keys"
+ printf "Waiting"
+ loggedin=""
+ while [[ $loggedin == "" ]]; do
+ printf "."
+ sleep 3
+ loggedin=$(w|grep ^$user)
+ done
+ echo "YOU DID IT! Logging out that user again."
+ # find new user's SSH session and kill it to log them out
+ pid=$(ps aux|grep sshd|grep ^$user|tail -1|awk '{print $2}')
+ kill -HUP $pid
+ # SECURE LOGIN
+ sed -i "s/RootLogin yes/RootLogin no/g" /etc/ssh/sshd_config
+ rcctl restart sshd
+ echo "I have disabled the root user, for security, so never log in as 'root' again."
+ echo "Only log in as $user from now on."
+ echo "To run a super-user (root) command, just type 'doas' before it."
+fi
+
+
+# VULTR API KEY?
+# file contains their previous answer
+if [ -f $(my vultr) ]; then
+ vultrapi=$(cat $(my vultr))
+else
+ printf "\n\n#############################\n"
+ echo "YOU NEED TO DO THIS NOW:"
+ echo "1. Log in to your account at vultr.com"
+ echo ""
+ echo "2. Go to https://my.vultr.com/settings/#settingsapi"
+ echo "(Or to get there: on the far left, click 'Account'"
+ echo "then to the right of it, click 'API' 3rd from bottom.)"
+ echo ""
+ echo "3. Under 'Access Control', under 'Enter your IPv4', add this:"
+ echo "$ip / 32"
+ echo "... then click the [Add] button"
+ echo ""
+ printf "4. Under 'Personal Access Token', copy your API key and paste it here: "
+ # Repeat until correct API and Access Control
+ apiok=""
+ while [[ $apiok != "200" ]]; do
+ read ui
+ # strip whitespace
+ vultrapi=$(echo "$ui" | tr -d '[:space:]')
+ # if API key works, gets "200" HTTP response code
+ apiok=$(curl -o /dev/null -s -w '%{http_code}' "https://api.vultr.com/v2/domains" -X GET -H "Authorization: Bearer $vultrapi")
+ if [[ $apiok == "200" ]]; then
+ echo "API works!"
+ # save to a file for next time
+ echo $vultrapi > $(my vultr)
+ # ADD DOMAIN NOW
+ domainadded=$(curl -o /dev/null -s -w '%{http_code}' "https://api.vultr.com/v2/domains/$domain" -X GET -H "Authorization: Bearer $vultrapi")
+ # if domain is in DNS already, the API returns "200" HTTP response code
+ if [[ $domainadded == "200" ]]; then
+ echo "$domain is in Vultr DNS already."
+ echo "Assuming this is from a previous installation, I'll delete the previous entries now and start fresh, OK?"
+ echo "Hit [enter] if this is OK, or hit Ctrl-C now to stop and re-start the script."
+ read ui
+ res=$(curl -s "https://api.vultr.com/v2/domains/$domain" -X DELETE -H "Authorization: Bearer $vultrapi")
+ fi
+ echo "Adding $domain to Vultr DNS. A, CNAME, and MX to $ip."
+ res=$(curl -s "https://api.vultr.com/v2/domains" -X POST -H "Authorization: Bearer $vultrapi" -H "Content-Type: application/json" --data "{\"domain\":\"$domain\", \"ip\":\"$ip\"}")
+ else
+ echo "Sorry. It's not authorizing. See steps 3 and 4, above."
+ echo "Under 'Access Control', make sure it says $ip/32"
+ printf "And copy+paste your long API key here: "
+ fi
+ done
+fi
+
+
+# WHICH INSTANCE ID? ("instance" is Vultr's name for this server)
+if [ -f $(my instance) ]; then
+ instance=$(cat $(my instance))
+else
+ # JSON, so put each { on new line, grep for line with this IP address, then awk to extract "id":"id-is-here"
+ instance=$(curl -s "https://api.vultr.com/v2/instances" -X GET -H "Authorization: Bearer $vultrapi" | perl -pe 's/{/\n{/g' | grep $ip | awk -F'"id":"|"' '/"id":"/ {print $2}')
+ echo "Instance ID $instance, but you don't need this info."
+ echo $instance > $(my instance)
+ # SET REVERSE DNS: ($ip = $domain)
+ res=$(curl -s "https://api.vultr.com/v2/instances/$instance/ipv4/reverse" -X POST -H "Authorization: Bearer $vultrapi" -H "Content-Type: application/json" --data "{\"ip\":\"$ip\", \"reverse\":\"$domain\"}")
+fi
+
+
+# STORAGE:
+if [ ! -f $(my storageno) ]; then
+ # check each time in case they added new storage
+ sd1=$(disklabel sd1 2>&1)
+ if [[ $sd1 == *"Device not configured"* ]]; then
+ echo "You do not have 'Block Storage' attached to this server."
+ printf "Do you want encrypted file storage? (y/n) "
+ read ui
+ yn=$(echo "$ui" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | cut -c1-1)
+ if [ $yn == "n" ]; then
+ touch $(my storageno)
+ else
+ # Find unattached block: (separate JSON, grep for empty instance, awk to get ID)
+ bid=$(curl -s "https://api.vultr.com/v2/blocks" -X GET -H "Authorization: Bearer $vultrapi" | perl -pe 's/{/\n{/g' | grep '"attached_to_instance":""' | head -1 | awk -F'"id":"|"' '/"id":"/ {print $2}')
+ if [[ $bid == "" ]]; then
+ echo "You don't have any available Block Storage. See https://sive.rs/ti"
+ echo "Deploy Block Storage at https://my.vultr.com/blockstorage/ then run this script again."
+ exit 1
+ else
+ echo "Block ID $bid. Instance ID $instance. You don't need this info."
+ res=$(curl -s "https://api.vultr.com/v2/blocks/$bid/attach" -X POST -H "Authorization: Bearer $vultrapi" -H "Content-Type: application/json" --data "{\"instance_id\":\"$instance\", \"live\":true}")
+ # Prompt then reboot
+ printf "\n\n#############################\n"
+ echo "COME BACK TO CONTINUE:"
+ echo "Storage attached, but now it needs to reboot, since it looks for storage at boot time."
+ echo "After it reboots, wait a minute then type this to continue:"
+ echo "ssh $user@$ip"
+ echo "doas su"
+ echo "cd"
+ echo "sh ti.sh"
+ echo "# OK? Hit [enter] now to let it reboot."
+ read ui
+ touch $(my rebooted)
+ reboot
+ exit 0
+ fi
+ fi
+ elif [[ $sd1 == *"duid: 0000000000000"* ]]; then
+ echo 'RAID *' | disklabel -wAT- sd1
+ echo "Make a password for your encrypted storage:"
+ bioctl -c C -l sd1a softraid0
+ echo '/ *' | disklabel -wAT- sd2
+ newfs sd2a
+ mount /dev/sd2a /mnt
+ chown -R $user:$user /mnt
+ chmod 770 /mnt
+ fi
+fi
+
+
+# TEST STORAGE
+if [[ ! -f $(my storageno) && ! -f $(my storageok) ]]; then
+ echo '#!/bin/sh\ndoas bioctl -c C -l sd1a softraid0\ndoas mount /dev/sd2a /mnt\nls -l /mnt' > /usr/local/sbin/m
+ echo '#!/bin/sh\ndoas umount /mnt\ndoas bioctl -d sd2\necho "unmounted"' > /usr/local/sbin/m-x
+ chmod 755 /usr/local/sbin/m /usr/local/sbin/m-x
+ echo "Testing that your encrypted storage works."
+ # if not mounted already, mount it
+ res=$(df|grep '/mnt$')
+ if [[ $res == "" ]]; then
+ echo "Your encrypted storage password:"
+ bioctl -c C -l sd1a softraid0
+ mount /dev/sd2a /mnt
+ chown -R $user:$user /mnt
+ fi
+ uploaded=$(ls /mnt)
+ if [[ $uploaded != "" ]]; then
+ echo "You've already uploaded to /mnt so we're good."
+ else
+ printf "Now upload anything to $user@$ip:/mnt/ while I wait"
+ while [[ $uploaded == "" ]]; do
+ printf "."
+ sleep 3
+ uploaded=$(ls /mnt)
+ done
+ echo "YOU DID IT!"
+ fi
+ echo "Unmounting encrypted storage now."
+ umount /mnt
+ bioctl -d sd2
+ touch $(my storageok)
+fi
+
+if [ ! -f $(my rebooted) ]; then
+ echo "Your server needs to reboot now, to apply the initial syspatch."
+ echo "AFTER IT REBOOTS, TYPE THIS FROM YOUR TERMINAL TO LOG IN AGAIN:"
+ echo "ssh $user@$ip"
+ echo ""
+ echo "AFTER LOGGING IN, TYPE:"
+ echo "doas su"
+ echo "cd"
+ echo "sh ti.sh"
+ echo ""
+ echo "... so we can continue, OK? Hit [enter] now to reboot."
+ read ui
+ touch $(my rebooted)
+ reboot
+ exit 0
+fi
+
+# NAMESERVERS HERE?
+ns=$(nslookup -type=NS $domain)
+if [[ $ns == *ns1.vultr.com* && $ns == *ns2.vultr.com* ]]; then
+ echo "$domain nameservers are set to vultr.com."
+elif [[ $ns == *SERVFAIL* ]]; then
+ echo "$domain nslookup returning mysterious 'SERVFAIL'"
+ echo "Next steps might or might not work! If not, try again later."
+else
+ printf "\n\n#############################\n"
+ echo "YOU NEED TO DO THIS NOW:"
+ echo "1. Log in to the website where you registered your $domain domain name."
+ echo "(Example: godaddy.com namecheap.com porkbun.com bookmyname.com)"
+ echo ""
+ echo "2. Edit the DNS Name Servers (NS)"
+ echo "They are currently set to:"
+ echo "$ns" | awk -F'nameserver = ' '/nameserver = / {print $2}' | grep -v '^$'
+ echo ""
+ echo "3. Erase those and replace them with:"
+ echo "ns1.vultr.com"
+ echo "ns2.vultr.com"
+ echo ""
+ echo "4. Wait a while (1-24 hours) and run this script again."
+ exit 0
+fi
+
+
+# WEB
+if [ ! -f $(my webok) ]; then
+ echo "Setting up https://$domain/ web server and secure certificate."
+ sed -i s/example.com/$domain/g httpd.conf relayd.conf acme-client.conf
+ cp httpd.conf relayd.conf acme-client.conf /etc/
+ rcctl enable httpd
+ rcctl start httpd
+ acme-client -v $domain
+ rcctl enable relayd
+ rcctl start relayd
+ html=$(printf '<!doctype html>\n<title>%s</title>\n<h1>%s</h1>\n<p>%s<br>\n<a href="mailto:%s@%s">%s@%s</a>\n</p>\n<p>Test <a href="/pub/">public files</a></p>' $domain $domain "$name" $user $domain $user $domain)
+ echo $html > /var/www/htdocs/index.html
+ rm -rf /var/www/htdocs/bgplg
+ mkdir -p /var/www/htdocs/pub
+ cp hello.txt hello.pdf derek.jpg guitar.mp3 ymap.mp4 /var/www/htdocs/pub/
+ chown -R $user:$user /var/www/htdocs
+ # add acme-client to crontab if not there already
+ res=$(crontab -l|grep acme-client)
+ if [[ $res == "" ]]; then
+ (crontab -l 2>/dev/null; echo "11\t3\t*\t*\t5\tacme-client $domain \&\& rcctl reload relayd") | crontab -
+ fi
+ printf "\n\n#############################\n"
+ echo "TEST THIS NOW:"
+ echo "Go to https://$domain/ now to verify the index.html placeholder."
+ echo "It should say $domain with your name and $user@$domain."
+ echo "Hit [enter] here if it's good, or Ctrl-C to quit and try again."
+ read ui
+ touch $(my webok)
+fi
+
+
+# RADICALE PER-USER
+if [ ! -d /var/db/radicale/collections/collection-root/$user ]; then
+ sed -i 's/#type = none/type = htpasswd/g' /etc/radicale/config
+ echo "Setting up Contacts and Calendar for user $user."
+ echo "For Contacts and Calendar only, make a new password that’s easy to type on your phone."
+ htpasswd /etc/radicale/users $user
+ chown _radicale /etc/radicale/users
+ rcctl enable radicale
+ rcctl restart radicale
+ echo '#!/bin/sh\ncp -r /var/db/radicale /home/$user/\nchown -R $user /home/$user' > /usr/local/sbin/radbak
+ chmod 700 /usr/local/sbin/radbak
+ # add Radicale backup to crontab if not there already
+ res=$(crontab -l|grep radbak)
+ if [[ $res == "" ]]; then
+ (crontab -l 2>/dev/null; echo "9\t3\t*\t*\t*\t/usr/local/sbin/radbak") | crontab -
+ fi
+ # create for user
+ mkdir -p /var/db/radicale/collections/collection-root/$user/{calendar,contacts}
+ prop=$(printf '{"C:supported-calendar-component-set": "VEVENT", "D:displayname": "%s", "tag": "VCALENDAR"}' $domain)
+ echo $prop > /var/db/radicale/collections/collection-root/$user/calendar/.Radicale.props
+ prop=$(printf '{"D:displayname": "%s", "tag": "VADDRESSBOOK"}' $domain)
+ echo $prop > /var/db/radicale/collections/collection-root/$user/contacts/.Radicale.props
+ chown -R _radicale:_radicale /var/db/radicale
+ chmod 600 /var/db/radicale/collections/collection-root/$user/calendar/.Radicale.props
+ chmod 600 /var/db/radicale/collections/collection-root/$user/contacts/.Radicale.props
+ printf "\n\n#############################\n"
+ echo "YOU NEED TO DO THIS NOW:"
+ echo "On your phone, manually add a CalDAV account for calendar."
+ echo "Server: dav.$domain"
+ echo "Username: $user"
+ echo "Password: the one you just created"
+ echo "Then, manually add a CardDAV account for contacts. Same info:"
+ echo "Server: dav.$domain"
+ echo "Username: $user"
+ echo "Password: the one you just created"
+ echo ""
+ echo "AFTER THAT, TEST THE CALENDAR:"
+ echo "On your phone, add a new (fake/test) calendar event to your $domain calendar."
+ printf "I will tell you when I see it here"
+ found=""
+ while [[ $found == "" ]]; do
+ printf "."
+ sleep 3
+ found=$(find /var/db/radicale/collections/collection-root/$user/calendar/ -maxdepth 1 -type f -name '*.ics')
+ done
+ echo ""
+ echo "Calendar entry added!"
+ echo "NOW TEST THE CONTACTS:"
+ echo "On your phone, add a new (fake/test) person to your $domain contacts."
+ printf "I will tell you when I see it here"
+ found=""
+ while [[ $found == "" ]]; do
+ printf "."
+ sleep 3
+ found=$(find /var/db/radicale/collections/collection-root/$user/contacts/ -maxdepth 1 -type f -name '*.vcf')
+ done
+ echo ""
+ echo "Contact added! Both work. Congratulations."
+fi
+
+
+# EMAIL
+# if conf files are here, email hasn't been set up yet
+if [ -f smtpd.conf ]; then
+ sed -i s/example.com/$domain/g smtpd.conf
+ mv smtpd.conf /etc/mail/
+ touch /etc/mail/secrets
+ rcctl restart smtpd
+fi
+if [ -f dovecot.conf ]; then
+ sed -i s/example.com/$domain/g dovecot.conf
+ rm -rf /etc/dovecot/*
+ mv dovecot.conf /etc/dovecot/
+ rcctl enable dovecot
+ rcctl start dovecot
+fi
+
+
+# MAILJET SMTP AUTH CREDENTIALS
+if [[ ! -f $(my smtpapi) || ! -f $(my smtpsecret) ]]; then
+ printf "\n\n#############################\n"
+ echo "YOU NEED TO DO THIS NOW:"
+ echo "1. Sign up at https://www.mailjet.com/"
+ echo "Click [Get Started] and use your existing (gmail, etc) email not this."
+ echo ""
+ echo "2. Once logged in, get to https://app.mailjet.com/account/apikeys via:"
+ echo " [Quick setup] → SMTP setup"
+ echo " [See all API credentials]"
+ echo " [Generate secret key]"
+ echo ""
+ printf "3. Copy the API Key and paste it here: "
+ read ui
+ smtpapi=$(echo "$ui" | tr -d '[:space:]')
+ echo $smtpapi > $(my smtpapi)
+ printf "4. Copy the Secret Key and paste it here: "
+ read ui
+ smtpsecret=$(echo "$ui" | tr -d '[:space:]')
+ echo $smtpsecret > $(my smtpsecret)
+ res=$(curl -s -X POST --user "$smtpapi:$smtpsecret" https://api.mailjet.com/v3/REST/sender --data "Email=*@$domain&EmailType=transactional&IsDefaultSender=true&Name=$domain")
+ json=$(curl -s -X GET --user "$smtpapi:$smtpsecret" https://api.mailjet.com/v3/REST/dns/$domain)
+ # extract DNS values to prove to Mailjet that you control this domain
+ txthost=$(echo $json | perl -ne 'if(/"OwnerShipTokenRecordName"\s*:\s*"([^"]+)"/) { print $1 }')
+ txthost="${txthost%?}" # remove final "."
+ txtvalue=$(echo $json | perl -ne 'if(/"OwnerShipToken"\s*:\s*"([^"]+)"/) { print $1 }')
+ data=$(printf '{"type":"TXT", "name":"%s", "data":"%s"}' $txthost "$txtvalue")
+ cmd=$(printf 'curl -s "https://api.vultr.com/v2/domains/%s/records" -X POST -H "Authorization: Bearer %s" -H "Content-Type: application/json" --data '\''%s'\''' $domain $vultrapi "$data")
+ eval "$cmd"
+ echo ""
+ # DKIM
+ txthost="mailjet._domainkey.$domain"
+ txtvalue=$(echo $json | perl -ne 'if(/"DKIMRecordValue"\s*:\s*"([^"]+)"/) { print $1 }')
+ data=$(printf '{"type":"TXT", "name":"%s", "data":"%s"}' $txthost "$txtvalue")
+ cmd=$(printf 'curl -s "https://api.vultr.com/v2/domains/%s/records" -X POST -H "Authorization: Bearer %s" -H "Content-Type: application/json" --data '\''%s'\''' $domain $vultrapi "$data")
+ eval "$cmd"
+ echo ""
+ # SPF is same for everyone:
+ curl -s "https://api.vultr.com/v2/domains/$domain/records" -X POST -H "Authorization: Bearer $vultrapi" -H "Content-Type: application/json" --data '{"type":"TXT", "name":"@", "data":"v=spf1 include:spf.mailjet.com ?all"}'
+ echo ""
+ # Validate
+ res=$(curl -s -X POST --user "$smtpapi:$smtpsecret" https://api.mailjet.com/v3/REST/sender/*@$domain/validate)
+ # SMTP RELAY:
+ echo "mailjet $smtpapi:$smtpsecret" > /etc/mail/secrets
+ chmod 640 /etc/mail/secrets
+ chown root:_smtpd /etc/mail/secrets
+ rcctl restart smtpd
+ sed -i s/API1/$smtpapi/g .muttrc
+ sed -i s/API2/$smtpsecret/g .muttrc
+fi
+
+# user account:
+if [[ ! -d /home/$user/Maildir ]]; then
+ mkdir -p /home/$user/Maildir/{cur,new,tmp}
+ chmod -R 700 /home/$user/Maildir
+ cat .muttrc | sed "s/USER/$user/g" > /home/$user/.muttrc
+ cp .mailcap /home/$user/
+ chown -R $user:$user /home/$user
+ printf "\n\n#############################\n"
+ echo "TEST EMAIL NOW:"
+ echo "From an external email account (gmail, etc) send an email to $user@$domain"
+ printf "I will tell you when I see it here"
+ found=""
+ while [[ $found == "" ]]; do
+ printf "."
+ sleep 2
+ found=$(find /home/$user/Maildir/new -type f)
+ done
+ echo "Got the email!"
+ echo ""
+ printf "\n\n#############################\n"
+ echo "YOUR IMAP SETTINGS: (to check email from any device)"
+ echo "Account type: IMAP"
+ echo "Email address: $user@$domain"
+ echo "Username: $user"
+ echo "Password: the original secret user password you made"
+ echo "Incoming mail server: $domain"
+ echo "Outgoing mail server: $domain"
+ echo "Connection security: SSL"
+ echo "Authentication type: Basic authentication"
+ echo ""
+ echo "Alternatively, SSH into this server as $user and type:"
+ echo "mutt"
+ echo ""
+fi
+
+printf "\n\n#############################\n"
+echo "For updates and help, please see https://sive.rs/ti"
+echo "When your server is set up, please email me your URL."
+echo "(I worked hard on this, so I like to know it helped.)"
+echo "Or ask any questions, or give any suggestions."
+echo ""
+echo "Derek Sivers"
+echo "https://sive.rs/contact"
+printf "#############################\n\n"
+