#!/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 <<EOF
        # Autogenerated configuration file template

        #################################
        # ignore-unknown-settings       Configuration settings to ignore if they are unknown
        #
        # ignore-unknown-settings=

        #################################
        # 8bit-dns      Allow 8bit dns queries
        #
        # 8bit-dns=no

        #################################
        # allow-axfr-ips        Allow zonetransfers only to these subnets
        #
        # allow-axfr-ips=127.0.0.0/8,::1
        

        #################################
        # allow-dnsupdate-from  A global setting to allow DNS updates from these IP ranges.
        #
        # allow-dnsupdate-from=127.0.0.0/8,::1

        #################################
        # allow-notify-from     Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.
        #
        # allow-notify-from=0.0.0.0/0,::/0

        #################################
        # allow-unsigned-autoprimary    Allow autoprimaries to create zones without TSIG signed NOTIFY
        #
        # allow-unsigned-autoprimary=yes

        #################################
        # allow-unsigned-notify Allow unsigned notifications for TSIG secured zones
        #
        # allow-unsigned-notify=yes

        #################################
        # allow-unsigned-autoprimary    Allow autoprimaries to create zones without TSIG signed NOTIFY (formerly allow-unsigned-supermaster)
        #
        # allow-unsigned-autoprimary=yes

        #################################
        # also-notify   When notifying a zone, also notify these nameservers
        #
        # also-notify=

        #################################
        # any-to-tcp    Answer ANY queries with tc=1, shunting to TCP
        #
        # any-to-tcp=yes

        #################################
        # api   Enable/disable the REST API (including HTTP listener)
        #
        # api=no

        #################################
        # api-key       Static pre-shared authentication key for access to the REST API
        #
        # api-key=

        #################################
        # autosecondary Act as an autosecondary (formerly superslave)
        #
        # autosecondary=no

        #################################
        # axfr-fetch-timeout    Maximum time in seconds for inbound AXFR to start or be idle after starting
        #
        # axfr-fetch-timeout=10

        #################################
        # axfr-lower-serial     Also AXFR a zone from a primary with a lower serial
        #
        # axfr-lower-serial=no

        #################################
        # cache-ttl     Seconds to store packets in the PacketCache
        #
        # cache-ttl=20

        #################################
        # carbon-instance       If set overwrites the instance name default
        #
        # carbon-instance=auth

        #################################
        # carbon-interval       Number of seconds between carbon (graphite) updates
        #
        # carbon-interval=30

        #################################
        # carbon-namespace      If set overwrites the first part of the carbon string
        #
        # carbon-namespace=pdns

        #################################
        # carbon-ourname        If set, overrides our reported hostname for carbon stats
        #
        # carbon-ourname=

        #################################
        # carbon-server If set, send metrics in carbon (graphite) format to this server IP address
        #
        # carbon-server=

        #################################
        # chroot        If set, chroot to this directory for more security
        #
        # chroot=

        #################################
        # config-dir    Location of configuration directory (pdns.conf)
        #
        config-dir=/etc/pdns

        #################################
        # config-name   Name of this virtual configuration - will rename the binary image
        #
        # config-name=

        #################################
        # consistent-backends   Assume individual zones are not divided over backends. Send only ANY lookup operations to the backend to reduce the number of lookups
        #
        # consistent-backends=yes

        #################################
        # control-console       Debugging switch - don't use
        #
        # control-console=no

        #################################
        # daemon        Operate as a daemon
        #
        daemon=yes

        #################################
        # default-api-rectify   Default API-RECTIFY value for zones
        #
        # default-api-rectify=yes

        #################################
        # default-ksk-algorithm Default KSK algorithm
        #
        # default-ksk-algorithm=ecdsa256

        #################################
        # default-ksk-size      Default KSK size (0 means default)
        #
        # default-ksk-size=0

        #################################
        # default-publish-cdnskey       Default value for PUBLISH-CDNSKEY
        #
        # default-publish-cdnskey=

        #################################
        # default-publish-cds   Default value for PUBLISH-CDS
        #
        # default-publish-cds=

        #################################
        # default-soa-content   Default SOA content
        #
        # default-soa-content=a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600

        #################################
        # default-soa-edit      Default SOA-EDIT value
        #
        # default-soa-edit=

        #################################
        # default-soa-edit-signed       Default SOA-EDIT value for signed zones
        #
        # default-soa-edit-signed=

        #################################
        # default-ttl   Seconds a result is valid if not set otherwise
        #
        # default-ttl=3600

        #################################
        # default-zsk-algorithm Default ZSK algorithm
        #
        # default-zsk-algorithm=

        #################################
        # default-zsk-size      Default ZSK size (0 means default)
        #
        # default-zsk-size=0

        #################################
        # direct-dnskey Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis
        #
        # direct-dnskey=no

        #################################
        # disable-axfr  Disable zonetransfers but do allow TCP queries
        #
        disable-axfr=no

        #################################
        # disable-axfr-rectify  Disable the rectify step during an outgoing AXFR. Only required for regression testing.
        #
        # disable-axfr-rectify=no

        #################################
        # disable-syslog        Disable logging to syslog, useful when running inside a supervisor that logs stdout
        #
        # disable-syslog=no

        #################################
        # distributor-threads   Default number of Distributor (backend) threads to start
        #
        # distributor-threads=3

        #################################
        # dname-processing      If we should support DNAME records
        #
        # dname-processing=no

        #################################
        # dnssec-key-cache-ttl  Seconds to cache DNSSEC keys from the database
        #
        # dnssec-key-cache-ttl=30

        #################################
        # dnsupdate     Enable/Disable DNS update (RFC2136) support. Default is no.
        #
        # dnsupdate=no

        #################################
        # domain-metadata-cache-ttl     Seconds to cache zone metadata from the database
        #
        # domain-metadata-cache-ttl=

        #################################
        # edns-subnet-processing        If we should act on EDNS Subnet options
        #
        # edns-subnet-processing=no

        #################################
        # enable-lua-records    Process LUA records for all zones (metadata overrides this)
        #
        # enable-lua-records=no

        #################################
        # entropy-source        If set, read entropy from this file
        #
        # entropy-source=/dev/urandom

        #################################
        # expand-alias  Expand ALIAS records
        #
        # expand-alias=no

        #################################
        # forward-dnsupdate     A global setting to allow DNS update packages that are for a secondary zone, to be forwarded to the primary.
        #
        # forward-dnsupdate=yes

        #################################
        # forward-notify        IP addresses to forward received notifications to regardless of primary or secondary settings
        #
        # forward-notify=

        #################################
        # guardian      Run within a guardian process
        #
        guardian=yes

        #################################
        # include-dir   Include *.conf files from this directory
        #
        # include-dir=

        #################################
        # launch        Which backends to launch and order to query them in
        #
        #launch=bindi
        launch=gmysql
        gmysql-dnssec
        gmysql-host=$MY_PDNS_HOST
        gmysql-user=$MY_PDNS_USR
        gmysql-password=$MY_PDNS_PW
        gmysql-dbname=$MY_PDNS_DB

        #################################
        # load-modules  Load this module - supply absolute or relative path
        #
        # load-modules=

        #################################
        # local-address Local IP addresses to which we bind
        #
        # local-address=0.0.0.0, ::

        #################################
        # local-address-nonexist-fail   Fail to start if one or more of the local-address's do not exist on this server
        #
        # local-address-nonexist-fail=yes

        #################################
        # local-port    The port on which we listen
        #
        # local-port=53

        #################################
        # log-dns-details       If PDNS should log DNS non-erroneous details
        #
        # log-dns-details=no

        #################################
        # log-dns-queries       If PDNS should log all incoming DNS queries
        #
        # log-dns-queries=no

        #################################
        # log-timestamp Print timestamps in log lines
        #
        # log-timestamp=yes

        #################################
        # logging-facility      Log under a specific facility
        #
        # logging-facility=

        #################################
        # loglevel      Amount of logging. Higher is more. Do not set below 3
        #
        # loglevel=4

        #################################
        # lua-axfr-script       Script to be used to edit incoming AXFRs
        #
        # lua-axfr-script=

        #################################
        # lua-dnsupdate-policy-script   Lua script with DNS update policy handler
        #
        # lua-dnsupdate-policy-script=

        #################################
        # lua-health-checks-expire-delay        Stops doing health checks after the record hasn't been used for that delay (in seconds)
        #
        # lua-health-checks-expire-delay=3600

        #################################
        # lua-health-checks-interval    LUA records health checks monitoring interval in seconds
        #
        # lua-health-checks-interval=5

        #################################
        # lua-prequery-script   Lua script with prequery handler (DO NOT USE)
        #
        # lua-prequery-script=

        #################################
        # lua-records-exec-limit        LUA records scripts execution limit (instructions count). Values <= 0 mean no limit
        #
        # lua-records-exec-limit=1000

        #################################
        # primary       Act as a primary (formerly master)
        #
        primary=yes

        #################################
        # max-cache-entries     Maximum number of entries in the query cache
        #
        # max-cache-entries=1000000

        #################################
        # max-ent-entries       Maximum number of empty non-terminals in a zone
        #
        # max-ent-entries=100000

        #################################
        # max-generate-steps    Maximum number of $GENERATE steps when loading a zone from a file
        #
        # max-generate-steps=0

        #################################
        # max-nsec3-iterations  Limit the number of NSEC3 hash iterations
        #
        # max-nsec3-iterations=100

        #################################
        # max-packet-cache-entries      Maximum number of entries in the packet cache
        #
        # max-packet-cache-entries=1000000

        #################################
        # max-queue-length      Maximum queuelength before considering situation lost
        #
        # max-queue-length=5000

        #################################
        # max-signature-cache-entries   Maximum number of signatures cache entries
        #
        # max-signature-cache-entries=

        #################################
        # max-tcp-connection-duration   Maximum time in seconds that a TCP DNS connection is allowed to stay open.
        #
        # max-tcp-connection-duration=0

        #################################
        # max-tcp-connections   Maximum number of TCP connections
        #
        # max-tcp-connections=20

        #################################
        # max-tcp-connections-per-client        Maximum number of simultaneous TCP connections per client
        #
        # max-tcp-connections-per-client=0

        #################################
        # max-tcp-transactions-per-conn Maximum number of subsequent queries per TCP connection
        #
        # max-tcp-transactions-per-conn=0

        #################################
        # module-dir    Default directory for modules
        #
        module-dir=/usr/lib64/pdns

        #################################
        # negquery-cache-ttl    Seconds to store negative query results in the QueryCache
        #
        # negquery-cache-ttl=60

        #################################
        # no-shuffle    Set this to prevent random shuffling of answers - for regression testing
        #
        # no-shuffle=off

        #################################
        # non-local-bind        Enable binding to non-local addresses by using FREEBIND / BINDANY socket options
        #
        # non-local-bind=no

        #################################
        # only-notify   Only send AXFR NOTIFY to these IP addresses or netmasks
        #
        # only-notify=0.0.0.0/0,::/0

        #################################
        # outgoing-axfr-expand-alias    Expand ALIAS records during outgoing AXFR
        #
        # outgoing-axfr-expand-alias=no

        #################################
        # overload-queue-length Maximum queuelength moving to packetcache only
        #
        # overload-queue-length=0

        #################################
        # prevent-self-notification     Don't send notifications to what we think is ourself
        #
        # prevent-self-notification=yes

        #################################
        # primary       Act as a primary
        #
        # primary=no

        #################################
        # query-cache-ttl       Seconds to store query results in the QueryCache
        #
        # query-cache-ttl=20

        #################################
        # query-local-address   Source IP addresses for sending queries
        #
        # query-local-address=0.0.0.0 ::

        #################################
        # query-logging Hint backends that queries should be logged
        #
        # query-logging=no

        #################################
        # queue-limit   Maximum number of milliseconds to queue a query
        #
        # queue-limit=1500

        #################################
        # receiver-threads      Default number of receiver threads to start
        #
        # receiver-threads=1

        #################################
        # resolver      Use this resolver for ALIAS and the internal stub resolver
        #
        # resolver=no

        #################################
        # retrieval-threads     Number of AXFR-retrieval threads for secondary operation
        #
        # retrieval-threads=2

        #################################
        # reuseport     Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket
        #
        # reuseport=no

        #################################
        # rng   Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.
        #
        # rng=auto

        #################################
        # secondary     Act as a secondary
        #
        # secondary=no

        #################################
        # secondary-do-renotify If this secondary should send out notifications after receiving zone transfers from a primary
        #
        # secondary-do-renotify=no

        #################################
        # security-poll-suffix  Zone name from which to query security update notifications
        #
        # security-poll-suffix=

        #################################
        # send-signed-notify    Send TSIG secured NOTIFY if TSIG key is configured for a zone
        #
        # send-signed-notify=yes

        #################################
        # server-id     Returned when queried for 'id.server' TXT or NSID, defaults to hostname - disabled or custom
        #
        # server-id=

        #################################
        # setgid        If set, change group id to this gid for more security
        #
        setgid=pdns

        #################################
        # setuid        If set, change user id to this uid for more security
        #
        setuid=pdns

        #################################
        # signing-threads       Default number of signer threads to start
        #
        # signing-threads=3

        #################################
        # secondary     Act as a secondary (formerly slave)
        #
        #secondary=yes

        #################################
        # secondary-cycle-interval      Schedule secondary freshness checks once every .. seconds (formerly slave-cycle-interval)
        #
        # secondary-cycle-interval=60

        #################################
        # secondary-renotify    If we should send out notifications for secondaried updates (formerly slave-renotify)
        #
        # secondary-renotify=no

        #################################
        # socket-dir    Where the controlsocket will live, /var/run/pdns when unset and not chrooted. Set to the RUNTIME_DIRECTORY environment variable when that variable has a value (e.g. under systemd).
        #
        # socket-dir=

        #################################
        # autosecondary Act as an autosecondary (formerly superslave)
        #
        # autosecondary=no

        #################################
        # svc-autohints Transparently fill ipv6hint=auto ipv4hint=auto SVC params with AAAA/A records for the target name of the record (if within the same zone)
        #
        # svc-autohints=no

        #################################
        # tcp-control-address   If set, PowerDNS can be controlled over TCP on this address
        #
        # tcp-control-address=

        #################################
        # tcp-control-port      If set, PowerDNS can be controlled over TCP on this address
        #
        # tcp-control-port=53000

        #################################
        # tcp-control-range     If set, remote control of PowerDNS is possible over these networks only
        #
        # tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10

        #################################
        # tcp-control-secret    If set, PowerDNS can be controlled over TCP after passing this secret
        #
        # tcp-control-secret=

        #################################
        # tcp-fast-open Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size
        #
        # tcp-fast-open=0

        #################################
        # tcp-idle-timeout      Maximum time in seconds that a TCP DNS connection is allowed to stay open while being idle
        #
        # tcp-idle-timeout=5

        #################################
        # traceback-handler     Enable the traceback handler (Linux only)
        #
        # traceback-handler=yes

        #################################
        # trusted-notification-proxy    IP address of incoming notification proxy
        #
        # trusted-notification-proxy=

        #################################
        # udp-truncation-threshold      Maximum UDP response size before we truncate
        #
        # udp-truncation-threshold=1232

        #################################
        # upgrade-unknown-types Transparently upgrade known TYPExxx records. Recommended to keep off, except for PowerDNS upgrades until data sources are cleaned up
        #
        # upgrade-unknown-types=no

        #################################
        # version-string        PowerDNS version in packets - full, anonymous, powerdns or custom
        #
        # version-string=full
        version-string=ScoobyHost 0.1 Alpha

        #################################
        # webserver     Start a webserver for monitoring (api=yes also enables the HTTP listener)
        #
        # webserver=no

        #################################
        # webserver-address     IP Address of webserver/API to listen on
        #
        # webserver-address=127.0.0.1

        #################################
        # webserver-allow-from  Webserver/API access is only allowed from these subnets
        #
        # webserver-allow-from=127.0.0.1,::1

        #################################
        # webserver-loglevel    Amount of logging in the webserver (none, normal, detailed)
        #
        # webserver-loglevel=normal

        #################################
        # webserver-max-bodysize        Webserver/API maximum request/response body size in megabytes
        #
        # webserver-max-bodysize=2

        #################################
        # webserver-password    Password required for accessing the webserver
        #
        # webserver-password=

        #################################
        # webserver-port        Port of webserver/API to listen on
        #
        # webserver-port=8081

        #################################
        # webserver-print-arguments     If the webserver should print arguments
        #
        # webserver-print-arguments=no

        #################################
        # write-pid     Write a PID file
        #
        # write-pid=yes

        #################################
        # xfr-cycle-interval    Schedule primary/secondary SOA freshness checks once every .. seconds
        #
        # xfr-cycle-interval=60

        #################################
        # xfr-max-received-mbytes       Maximum number of megabytes received from an incoming XFR
        #
        # xfr-max-received-mbytes=100

        #################################
        # zone-cache-refresh-interval   Seconds to cache list of known zones
        #
        # zone-cache-refresh-interval=300

        #################################
        # zone-metadata-cache-ttl       Seconds to cache zone metadata from the database
        #
        # zone-metadata-cache-ttl=60
EOF

    if [[ "${OS_FAMILY}" = "rhel" ]]; then
        setsebool -P pdns_can_network_connect_db 1 || true
        setsebool -P nis_enabled 1 || true
    fi

    sed -i 's/^        //' /etc/pdns/pdns.conf
    systemctl enable --now pdns
}

###########################################
#### Install/Configure Apache or Nginx ####
###########################################
webserver_install() {
    if [[ ! -d "/var/www/html/${WEB_HOST_NAME}" ]]; then
        mkdir -p "/var/www/html/${WEB_HOST_NAME}"
    fi

    if [[ "${HTTP}" = "apache" ]]; then
        _install_apache
    elif [[ "${HTTP}" = "nginx" ]]; then
        _install_nginx
    fi
}

_install_apache() {
    if [[ "${OS_FAMILY}" = "debian" ]]; then
        ${PAKMGR} install apache2 php php-fpm php-gd php-intl php-mysql php-xml php-mbstring php-curl gettext
        systemctl restart apache2
    elif [[ "${OS_FAMILY}" = "suse" ]]; then
        ${PAKMGR} apache2 php8 php8-fpm php8-gd php8-intl php8-mysql php8-mbstring php8-curl gettext
    else
        ${PAKMGR} install httpd php php-fpm php-gd php-intl php-mysqlnd php-xml php-mbstring php-curl gettext
    fi

    local path
    if [[ "${OS_FAMILY}" = "debian" ]]; then
        path="/etc/apache2/sites-available/${WEB_HOST_NAME}.conf"
    elif [[ "${OS_FAMILY}" = "suse" ]]; then
        path="/etc/apache2/vhosts.d/${WEB_HOST_NAME}.conf"
    else
        path="/etc/httpd/conf.d/${WEB_HOST_NAME}.conf"
    fi

    {
        echo '<VirtualHost *:80>'
        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 '    <FilesMatch \.php$>'
        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 '    </FilesMatch>'
        echo '</VirtualHost>'
    } > "${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
