Postalinstall.sh
#!/usr/bin/env bash
echo "Hello, Lets install some prerequisites (git, curl, jq and docker-compose)."
sleep 0.2s
echo -e
yum -y install git curl jq nethserver-firewall-base-ui nethserver-docker php-pecl-memcached php-imap php-mysql php-mcrypt php-pecl-redis php-pecl-apcu php-smbclient php-ldap php-mbstring
wait
echo -e
echo "now lets open up the necessary firewall ports"
echo -e
config set rabbitmq service status enabled TCPPorts 5672 UDPPorts 5672 access red,green
config set postalweb service status enabled TCPPorts 5000 UDPPorts 5000 access red,green
config set dnspostal service status enabled UDPPorts 53 access red,green
config set smtps service status enabled TCPPorts 465 UDPPorts 465 access red,green ##change to port you want if it conflicts
config set imap service status enabled TCPPorts 143 UDPPorts 143 access red,green ##change to port you want if it conflicts
config set imaps service status enabled TCPPorts 993 UDPPorts 993 access red,green ##change to port you want if it conflicts
config set postal-mariadb service status enabled TCPPorts 3307 UDPPorts 3307 access red,green
signal-event firewall-adjust
wait
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
echo -e
echo "Please wait while I build docker-compose from source."
echo -e
sleep 0.2s
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
wait
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
echo -e
echo "Now I'll setup the helper repository."
sleep 0.2s
echo -e
git clone https://postalserver.io/start/install /opt/postal/install
sudo ln -s /opt/postal/install/bin/postal /usr/bin/postal
wait
echo "<VirtualHost *:443>
ServerName postal.$domain
RewriteEngine On
SSLEngine On
ProxyPassMatch ^/.well-known/acme-challenge/ !
RequestHeader set X-Forwarded-Proto "https"
ProxyPass / http://172.17.0.1:5000/
ProxyPassReverse / http://172.17.0.1:5000/
ProxyPreserveHost On
ProxyErrorOverride Off
</VirtualHost>
<VirtualHost *:80>
ServerName postal.$domain
RewriteEngine On
ProxyPassMatch ^/.well-known/acme-challenge/ !
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{SERVER_NAME}$1 [R,L]
</VirtualHost>" > /etc/httpd/conf.d/postal.conf
systemctl restart httpd
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
head /dev/urandom | tr -dc A-Za-z0-9 | head -c10 >> ~/pass.txt
echo -e
echo "Thank you now I'll install the rabbitmq instance on docker."
echo -e
sleep 0.2s
docker run -d \
--name postal-rabbitmq \
-p 127.0.0.1:5672:5672 \
--restart always \
-e RABBITMQ_DEFAULT_USER=postal \
-e RABBITMQ_DEFAULT_PASS=$(cat ~/pass.txt) \
-e RABBITMQ_DEFAULT_VHOST=postal \
rabbitmq:3.8
wait
echo -e
echo "Thank you please wait while I create your database and credentials this may take a moment"
echo -e
sleep 0.2s
docker run -d \
--name postal-mariadb \
-p 127.0.0.1:3307:3306 \
--restart always \
-e MARIADB_DATABASE=postal \
-e MARIADB_ROOT_PASSWORD=$(cat ~/pass.txt) \
mariadb
wait
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
echo -e
echo "What is your domain?"
echo -e
read -r domain
sleep 0.2s
postal bootstrap postal.$domain
wait
echo -e
echo "Thank you please wait while I initialize your postal this may take a moment"
echo -e
sleep 0.2s
sed -i '4s/ reverse_proxy .*/ reverse_proxy 172.17.0.1:5000/' /opt/postal/config/Caddyfile;
sed -i '3s/ use_ip_pools: .*/ use_ip_pools: true/' /opt/postal/config/postal.yml;
sed -i '13s/ bind_address: .*/ bind_address: 172.17.0.1/' /opt/postal/config/postal.yml;
sed -i '18s/ port: .*/ port: 465/' /opt/postal/config/postal.yml;
sed -i "41s/host: .*/host: $(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' `docker ps -aqf "name=postal-rabbitmq"`)/g" /opt/postal/config/postal.yml;
sed -i "26s/host: .*/host: $(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' `docker ps -aqf "name=postal-mariadb"`)/g" /opt/postal/config/postal.yml;
sed -i '52s/smtp_server_hostname: .*/smtp_server_hostname: '"postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i "34s/host: .*/host: $(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' `docker ps -aqf "name=postal-mariadb"`)/g" /opt/postal/config/postal.yml;
sed -i '56s/track_domain: .*/track_domain: '"track.postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i '55s/route_domain: .*/route_domain: '"routes.postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i '54s/return_path: .*/return_path: '"return.postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i '53s/spf_include: .*/spf_include: '"spf.postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i '51s/ - .*/ - '"postal.$domain"'/g' /opt/postal/config/postal.yml;
sed -i "43s/password: .*/password: $(cat ~/pass.txt)/g" /opt/postal/config/postal.yml;
sed -i "28s/password: .*/password: $(cat ~/pass.txt)/g" /opt/postal/config/postal.yml;
sed -i "36s/password: .*/password: $(cat ~/pass.txt)/g" /opt/postal/config/postal.yml;
postal initialize
wait
postal make-user
wait
echo -e
echo "Database setup, initialised and user setup successfully please wait while I start Postal"
echo -e
sleep 0.2s
postal start
wait
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
echo -e
echo "Now I'll create a script to clean and automate the start of Postal on reboot"
echo -e
sleep 0.2s
echo "#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=/usr/local/lib
/usr/bin/postal status | grep Exit && date >> ~/logpostal.log
/usr/bin/postal status | grep Exit && /usr/bin/postal start" > ~/postalCheck.sh
echo -e
echo "Ok Done, now lets make the script executable."
echo -e
sleep 0.2s
chmod +x ~/postalCheck.sh
echo -e
echo "Ok Done, now I'll add it to crontab."
echo -e
sleep 0.2s
echo "@reboot sleep 60 && ~/postalCheck.sh" >> /etc/crontab
echo -e
echo "Ok Done."
echo -e
sleep 0.2s
echo -e
echo "Thank you for your patience, please open a web browser to https://postal.$domain"
echo "Please take note of your mariadb and rabbitmq passwd $(cat pass.txt) and press enter so it can be deleted for security"
wait
echo "the password file will now be deleted"
rm -f ~/pass.txt
heres a script to automate creating all the records required for postal with cloudflare
cfdnsrecords.sh
#!/usr/bin/env bash
echo -e
echo "What is your API token ?"
echo -e
read -r token
sleep 0.2s
echo -e
echo "What is the domain name?"
echo -e
read -r domain
echo -e
echo "What is Public IP address?"
echo -e
read -r IP
wait
postal default-dkim-record > ~/dkim.txt
curl -X GET "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
| python -c $'import sys,json\ndata=json.loads(sys.stdin.read())\nif data["success"]:\n\tfor dict in data["result"]:print("Zone ID: " + dict["id"])\nelse:print("ERROR(" + str(data["errors"][0]["code"]) + "): " + data["errors"][0]["message"])' > zoneid.txt
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"A"'","name":"'"postal.$domain"'","content":"'"$IP"'","proxied":'"false"',"ttl":'"1"'}' \
| python -m json.tool;
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"MX"'","name":"'"@"'","content":"'"postal.$domain"'","priority":'"10"',"ttl":'"1"'}' \
| python -m json.tool;
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"TXT"'","name":"'"spf.postal.$domain"'","content":"'"v=spf1 ip4:$IP ~all"'","ttl":'"1"'}' \
| python -m json.tool;
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"A"'","name":"'"rp.postal.$domain"'","content":"'"$IP"'","proxied":'"false"',"ttl":'"1"'}' \
| python -m json.tool;
wait
# curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
# -H "Authorization: Bearer $token" \
#-H "Content-Type: application/json" \
# --data '{"type":"'"TXT"'","name":"'"rp.postal.$domain"'","content":"'" v=spf1 a mx include:spf.postal.$domain ~all"'","ttl":'"1"'}' \
#| python -m json.tool;
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"TXT"'","name":"'"rp.postal.$domain"'","content":"'"v=spf1 a mx include:spf.postal.$domain ~all"'","ttl":'"1"'}' \
| python -m json.tool;
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
# --data '{"type":"'"TXT"'","name":"'"postal._domainkey.rp.postal.$domain"'","content":"'"'$(cat ~/dkim.txt)'"'"1"'}' \
--data '{"type":"'"TXT"'","name":"'"postal._domainkey.rp.postal.$domain"'","content":"'"$(cat dkim.txt)"'","ttl":'"1"'}' \
| python -m json.tool;
wait
curl -X POST "https://api.cloudflare.com/client/v4/zones/$(sed 's/Zone ID: //' zoneid.txt)/dns_records/" \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
--data '{"type":"'"MX"'","name":"'"postal.$domain"'","content":"'"routes.postal.$domain"'","priority":'"10"',"ttl":'"1"'}' \
| python -m json.tool;