#!/bin/bash set -euo pipefail ###################################################################################### #### Version 3.2 #### #### For questions or comments contact@mylinux.work #### #### Author : Phil Connor #### #### #### #### Notes : #### #### This script is a simple "helper" to install and configure Maria, #### #### PowerDNS and PowerAdmin on Linux servers. #### #### Supported: Ubuntu, Debian, RHEL/CentOS/Rocky/Alma, Fedora, openSUSE #### #### There is no silver bullet. Don't expect the perfect setup, #### #### review comments and adapt the parameters to your application usage. #### #### #### #### Use this script at your OWN risk. There is no guarantee whatsoever. #### #### #### #### Usage chmod 755 then ./PdnsInstall.sh or bash PdnsInstall.sh #### ###################################################################################### ######################## #### User Variables #### ######################## MYSQL_PASS="${MYSQL_PASS:-}" # <-- Set via env var MYSQL_PASS or you will be prompted MY_PDNS_USR=pdns # <-- The username for your PowerDNS connect to DB MY_PDNS_DB=powerdns # <-- The name for your PowerDNS DB MY_PDNS_PW="${MY_PDNS_PW:-}" # <-- Set via env var MY_PDNS_PW or you will be prompted MY_PDNS_HOST=localhost # <-- The default here is localhost, but can be set to a remote host if you have configured that DEL_MY_CNF=Y # <-- Place a Capital Y for yes or N for no here to delete /root/.my.cnf when db_install function is done WEB_HOST_NAME=test1.myserver.com # <-- The FQDN of your server goes here EMAIL=admin@$WEB_HOST_NAME # <-- This is the email you want to use for Let's Encrypt registrations HTTP=nginx # <-- Choose apache or nginx --> The apache Config is in BETA TESTING please only choose nginx unless you know what your doing ########################## #### System Variables #### ########################## ip4=$(ip -o -4 route get 8.8.8.8 | awk '{print $7; exit}') host=$(hostname -f) OS=$({ grep PRETTY_NAME /etc/os-release || true; } | sed 's/PRETTY_NAME=//g' | tr -d '="' | awk '{print $1}' | tr '[:upper:]' '[:lower:]') OSVER=$({ grep VERSION_ID /etc/os-release || true; } | sed 's/VERSION_ID=//g' | tr -d '="' | awk -F. '{print $1}') # OS family: debian (ubuntu, debian), rhel (centos, red, oracle, rocky, alma), fedora, suse (opensuse) OS_FAMILY="" ########################################################### #### Detect Package Manager from OS and OSVer Variables #### ########################################################### if [[ "${OS}" = ubuntu || "${OS}" = debian ]]; then OS_FAMILY="debian" PAKMGR="apt -y" elif [[ "${OS}" = centos || "${OS}" = red || "${OS}" = oracle || "${OS}" = rocky || "${OS}" = alma ]]; then OS_FAMILY="rhel" PAKMGR="dnf -y" elif [[ "${OS}" = fedora ]]; then OS_FAMILY="rhel" PAKMGR="dnf -y" elif [[ "${OS}" = opensuse ]]; then OS_FAMILY="suse" PAKMGR="zypper -n install" else echo "Unsupported OS: ${OS}" echo "Supported: Ubuntu, Debian, CentOS, RHEL, Oracle, Rocky, Alma, Fedora, openSUSE" exit 1 fi ########################## #### Detect Root User #### ########################## check_RootUser() { if [[ "$(id -u)" != "0" ]]; then echo "You dont have permission to run $0 as non-root user. Use sudo su -" exit 1 fi } ############################ #### Prompt for secrets #### ############################ prompt_secrets() { if [[ -z "${MYSQL_PASS}" ]]; then read -rsp "Enter MySQL root password: " MYSQL_PASS echo fi if [[ -z "${MY_PDNS_PW}" ]]; then read -rsp "Enter PowerDNS DB password: " MY_PDNS_PW echo fi } ############################## #### Validate user inputs #### ############################## validate_inputs() { if [[ "${HTTP}" != "apache" && "${HTTP}" != "nginx" ]]; then echo "Invalid HTTP value '${HTTP}'. Must be 'apache' or 'nginx'." exit 1 fi } #################### #### Code Start #### #################### ######################### #### Install MariaDB #### ######################### install_mysql() { if ! command -v mysql &>/dev/null; then if [[ "${OS_FAMILY}" = "debian" ]]; then ${PAKMGR} update ${PAKMGR} install mariadb-client mariadb-server elif [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} mariadb mariadb-client else ${PAKMGR} install mariadb mariadb-server fi fi systemctl enable --now mariadb } ###################### #### Secure MySQL #### ###################### secure_mysql() { if ! command -v expect &>/dev/null; then if [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} expect else ${PAKMGR} install expect fi fi expect -f - <<-EOF set timeout 10 spawn mysql_secure_installation expect "Enter current password for root (enter for none):" send -- "\r" expect "Set root password?" send -- "y\r" expect "New password:" send -- "${MYSQL_PASS}\r" expect "Re-enter new password:" send -- "${MYSQL_PASS}\r" expect "Remove anonymous users?" send -- "y\r" expect "Disallow root login remotely?" send -- "y\r" expect "Remove test database and access to it?" send -- "y\r" expect "Reload privilege tables now?" send -- "y\r" expect eof EOF } ################################### #### Install PowerDNS DataBase #### ################################### pdns_db_install() { if [[ ! -f /root/.my.cnf ]]; then { echo '[mysql]' echo 'user=root' echo "password=${MYSQL_PASS}" } >/root/.my.cnf chmod 600 /root/.my.cnf fi mysql -e "CREATE DATABASE ${MY_PDNS_DB} /*\!40100 DEFAULT CHARACTER SET utf8 */;" mysql -e "CREATE USER ${MY_PDNS_USR}@localhost IDENTIFIED BY '${MY_PDNS_PW}';" mysql -e "GRANT ALL PRIVILEGES ON ${MY_PDNS_DB}.* TO '${MY_PDNS_USR}'@'localhost';" mysql -e "FLUSH PRIVILEGES;" OUTFILE="/tmp/pdns.sql" cat > "${OUTFILE}" << 'EOF' CREATE TABLE domains ( id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL, master VARCHAR(128) DEFAULT NULL, last_check INT DEFAULT NULL, type VARCHAR(6) NOT NULL, notified_serial INT UNSIGNED DEFAULT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX name_index ON domains(name); CREATE TABLE records ( id BIGINT AUTO_INCREMENT, domain_id INT DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(10) DEFAULT NULL, content VARCHAR(64000) DEFAULT NULL, ttl INT DEFAULT NULL, prio INT DEFAULT NULL, disabled TINYINT(1) DEFAULT 0, ordername VARCHAR(255) BINARY DEFAULT NULL, auth TINYINT(1) DEFAULT 1, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX nametype_index ON records(name,type); CREATE INDEX domain_id ON records(domain_id); CREATE INDEX ordername ON records (ordername); CREATE TABLE supermasters ( ip VARCHAR(64) NOT NULL, nameserver VARCHAR(255) NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (ip, nameserver) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE TABLE comments ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(10) NOT NULL, modified_at INT NOT NULL, account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, comment TEXT CHARACTER SET 'utf8' NOT NULL, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX comments_name_type_idx ON comments (name, type); CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); CREATE TABLE domainmetadata ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, kind VARCHAR(32), content TEXT, PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind); CREATE TABLE cryptokeys ( id INT AUTO_INCREMENT, domain_id INT NOT NULL, flags INT NOT NULL, active BOOL, published BOOL DEFAULT 1, content TEXT, PRIMARY KEY(id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE INDEX domainidindex ON cryptokeys(domain_id); CREATE TABLE tsigkeys ( id INT AUTO_INCREMENT, name VARCHAR(255), algorithm VARCHAR(50), secret VARCHAR(255), PRIMARY KEY (id) ) Engine=InnoDB CHARACTER SET 'latin1'; CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); EOF if [[ "${DEL_MY_CNF}" != "N" ]]; then rm -f /root/.my.cnf fi mysql -D "${MY_PDNS_DB}" < "${OUTFILE}" rm -f "${OUTFILE}" } #################################### #### Install/Configure PowerDNS #### #################################### pdns_app_install() { if [[ "${OS_FAMILY}" = "debian" ]]; then if systemctl is-enabled systemd-resolved &>/dev/null; then systemctl disable --now systemd-resolved systemctl mask systemd-resolved sed -i 's/nameserver /#nameserver /g' /etc/resolv.conf echo -e 'nameserver 8.8.8.8 \nnameserver 8.8.4.4' >> /etc/resolv.conf fi DEBIAN_FRONTEND=noninteractive ${PAKMGR} install pdns-backend-mysql fpdns bind9utils elif [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} pdns pdns-backend-mysql bind-utils else ${PAKMGR} install epel-release || true if [[ "${OS}" != "fedora" ]]; then ${PAKMGR} install "http://rpms.remirepo.net/enterprise/remi-release-${OSVER}.rpm" || true fi ${PAKMGR} install pdns-backend-mysql pdns bind-utils fi echo "" >/etc/pdns/pdns.conf cat >/etc/pdns/pdns.conf <' echo " ServerAdmin admin@${WEB_HOST_NAME}" echo " ServerName ${WEB_HOST_NAME}" echo " DocumentRoot /var/www/html/${WEB_HOST_NAME}" echo ' #DirectoryIndex index.php' echo " #ErrorLog /var/log/httpd/${WEB_HOST_NAME}-error.log" echo " #CustomLog /var/log/httpd/${WEB_HOST_NAME}-access.log combined" echo '' echo ' ' if [[ "${OS_FAMILY}" = "debian" ]]; then echo ' SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost"' elif [[ "${OS_FAMILY}" = "suse" ]]; then echo ' SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"' else echo ' SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"' fi echo ' ' echo '' } > "${path}" if [[ "${OS_FAMILY}" = "debian" ]]; then if ! apachectl configtest; then echo -e '\e[01;31m An Error was detected with apache2, please check the configuration\e[0m' >&2 exit 1 fi systemctl enable --now php*-fpm a2dissite 000-default a2ensite "${WEB_HOST_NAME}" a2enmod proxy_fcgi setenvif systemctl enable apache2 systemctl reload apache2 elif [[ "${OS_FAMILY}" = "suse" ]]; then if ! apachectl configtest; then echo -e '\e[01;31m An Error was detected with apache2, please check the configuration\e[0m' >&2 exit 1 fi systemctl enable --now php-fpm systemctl enable --now apache2 else if ! httpd -t; then echo -e '\e[01;31m An Error was detected with httpd, please check the configuration\e[0m' >&2 exit 1 fi chcon -R -t httpd_sys_content_t "/var/www/html/${WEB_HOST_NAME}" systemctl enable --now php-fpm systemctl enable --now httpd fi } _install_nginx() { # Install PHP for nginx if [[ "${OS_FAMILY}" = "debian" ]]; then ${PAKMGR} install php php-cli php-fpm php-gd php-intl php-mysql php-xml php-mbstring php-curl gettext systemctl disable --now apache2 || true systemctl mask apache2 || true elif [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} php8 php8-fpm php8-cli php8-mysql php8-intl php8-mbstring php8-curl systemctl disable --now apache2 || true systemctl mask apache2 || true else ${PAKMGR} install php php-fpm php-cli php-mysqlnd php-intl php-mbstring php-curl chown apache:apache /var/lib/php/sessions systemctl disable --now httpd || true systemctl mask httpd || true fi # Install nginx if [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} nginx else ${PAKMGR} install nginx fi if [[ "${OS_FAMILY}" = "rhel" ]]; then if ! grep -q "listen = /run/php-fpm/www.sock" /etc/php-fpm.d/www.conf; then sed -i '/listen = */c\listen = \/run\/php-fpm\/www.sock' /etc/php-fpm.d/www.conf fi fi local path if [[ "${OS_FAMILY}" = "debian" ]]; then path="/etc/nginx/sites-available/${WEB_HOST_NAME}.conf" else path="/etc/nginx/conf.d/${WEB_HOST_NAME}.conf" fi # shellcheck disable=SC2016 { echo 'server {' echo " server_name ${WEB_HOST_NAME};" echo ' listen 80;' echo '' echo " root /var/www/html/${WEB_HOST_NAME};" echo " #access_log /var/log/nginx/${WEB_HOST_NAME}-access_log;" echo " #error_log /var/log/nginx/${WEB_HOST_NAME}-error_log;" echo '' echo ' index index.php;' echo '' echo ' location / {' echo ' try_files $uri $uri/ /index.php?query_string;' echo ' }' echo '' echo ' location ~ \.php$ {' echo ' fastcgi_index index.php;' echo ' fastcgi_split_path_info ^(.+\.php)(.*)$;' echo ' fastcgi_keep_conn on;' echo ' include /etc/nginx/fastcgi_params;' if [[ "${OS_FAMILY}" = "debian" ]]; then echo ' fastcgi_pass unix:/run/php/php-fpm.sock;' else echo ' fastcgi_pass unix:/run/php-fpm/www.sock;' fi echo ' fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;' echo ' }' echo '' echo ' location ~ /\.ht {' echo ' deny all;' echo ' }' echo '' echo '}' } > "${path}" if ! nginx -t; then echo -e '\e[01;31m An Error was detected with nginx, please check the configuration\e[0m' >&2 exit 1 fi if [[ "${OS_FAMILY}" = "debian" ]]; then rm -f /etc/nginx/sites-enabled/default ln -sf "/etc/nginx/sites-available/${WEB_HOST_NAME}.conf" "/etc/nginx/sites-enabled/${WEB_HOST_NAME}" elif [[ "${OS_FAMILY}" = "rhel" ]]; then chcon -R -t httpd_sys_content_t "/var/www/html/${WEB_HOST_NAME}" fi systemctl enable --now php-fpm systemctl enable --now nginx } ############################ #### Install PowerAdmin #### ############################ pdns_admin_install() { if [[ ! -d "/var/www/html/${WEB_HOST_NAME}" ]]; then mkdir -p "/var/www/html/${WEB_HOST_NAME}" fi if [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} git else ${PAKMGR} install git fi cd "/var/www/html/${WEB_HOST_NAME}" || exit git clone https://github.com/poweradmin/poweradmin.git mv poweradmin/* . rm -rf poweradmin/ find "/var/www/html/${WEB_HOST_NAME}/" -type d -exec chmod 755 {} \; find "/var/www/html/${WEB_HOST_NAME}/" -type f -exec chmod 644 {} \; local web_user if [[ "${OS_FAMILY}" = "debian" ]]; then web_user="www-data" elif [[ "${OS_FAMILY}" = "suse" ]]; then web_user="wwwrun" else web_user="apache" fi chown -R "${web_user}:${web_user}" "/var/www/html/${WEB_HOST_NAME}/" } ########################################## #### Install Certbot and request Cert #### ########################################## install_certbot() { if [[ "${HTTP}" = "apache" ]]; then if [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} python3-certbot python3-certbot-apache else ${PAKMGR} install python3-certbot-apache fi if [[ "${OS_FAMILY}" = "rhel" ]]; then systemctl enable --now httpd else systemctl enable --now apache2 fi elif [[ "${HTTP}" = "nginx" ]]; then if [[ "${OS_FAMILY}" = "suse" ]]; then ${PAKMGR} python3-certbot python3-certbot-nginx else ${PAKMGR} install python3-certbot-nginx fi systemctl enable --now nginx fi ################################################################################################# #### Be sure that your domain has the proper dns entry or this will not work. #### #### #### #### If your domain is not properly configured and you know it, or you just wanna #### #### test that you can get a cert uncomment this line #### #### #### #### certbot certonly --redirect --agree-tos --nginx -d $WEB_HOST_NAME -m "$EMAIL" --dry-run #### #### and comment out this line #### #### certbot --non-interactive --redirect --agree-tos -d $WEB_HOST_NAME -m "$EMAIL" #### ################################################################################################# if [[ "${HTTP}" = "apache" ]]; then certbot certonly --redirect --agree-tos --apache -d "${WEB_HOST_NAME}" -m "${EMAIL}" --dry-run -v #certbot --non-interactive --redirect --agree-tos --apache -d "${WEB_HOST_NAME}" -m "${EMAIL}" if [[ "${OS_FAMILY}" = "rhel" ]]; then systemctl restart httpd else systemctl restart apache2 fi elif [[ "${HTTP}" = "nginx" ]]; then certbot certonly --redirect --agree-tos --nginx -d "${WEB_HOST_NAME}" -m "${EMAIL}" --dry-run -v #certbot --non-interactive --redirect --agree-tos --nginx -d "${WEB_HOST_NAME}" -m "${EMAIL}" systemctl restart nginx fi # Set up auto-renewal via cron/systemd timer if ! grep -q "certbot" /etc/crontab 2>/dev/null; then echo "0 */12 * * * root certbot -q renew" >> /etc/crontab fi } ####################### #### Final Message #### ####################### install_complete() { if [[ ! -d "/etc/letsencrypt/live/${WEB_HOST_NAME}" ]]; then echo -e '\e[01;37m -----------------------------------------------------------------------------------------------------------' echo -e "\e[01;32m You should now be able to complete the Poweradmin setup by accessing it here http://${host}/install/ or by ip http://${ip4}/install/" echo -e '\e[01;37m -----------------------------------------------------------------------------------------------------------\e[0m' else echo -e '\e[01;37m -----------------------------------------------------------------------------------------------------------' echo -e "\e[01;32m You should now be able to complete the Poweradmin setup by accessing it here https://${host}/install/ or by ip https://${ip4}/install/" echo -e '\e[01;37m -----------------------------------------------------------------------------------------------------------\e[0m' fi } ################## #### Code End #### ################## check_RootUser prompt_secrets validate_inputs install_mysql secure_mysql pdns_db_install pdns_app_install webserver_install pdns_admin_install install_certbot install_complete