Skip to content

Instantly share code, notes, and snippets.

@chefkoch-de42
Forked from besmirzanaj/technitium-sync.sh
Last active July 1, 2025 13:56
Show Gist options
  • Select an option

  • Save chefkoch-de42/bd1088649a579126f98243ecb38887b4 to your computer and use it in GitHub Desktop.

Select an option

Save chefkoch-de42/bd1088649a579126f98243ecb38887b4 to your computer and use it in GitHub Desktop.
synch two technitium servers
# Technitium Sync Configuration
# Fill in the following variables for your environment
master_dns_server='source.ip.address'
slave_dns_server='dest.ip.address'
master_dns_serverdomain='fqdn.of.source.server'
slave_dns_serverdomain='fqdn.of.dest.server'
master_dns_token='MASTER_TECHNITIUM_TOKEN_HERE'
slave_dns_token='SLAVE_TECHNITIUM_TOKEN_HERE'
dhcp_scope_name="local-home"
#!/bin/bash
# Author: Besmir Zanaj, 2024
# This is a very raw script to backup configs (no logs and no stats) from a technitium server
# to another
#
# Recommended install location: /usr/local/sbin/technitium-sync.sh
# (per Linux Filesystem Hierarchy Standard, system admin scripts should go in /usr/local/sbin)
#
# first create two tokens: one on the master server and another one on the slave one
# fill out the vars below in /usr/local/etc/technitium-sync.conf
# create a cronjob with this script on the slave host
# eg:
# 30 */6 * * * /usr/local/sbin/technitium-sync.sh
#
# --- systemd.service and systemd.timer example ---
# /etc/systemd/system/technitium-sync.service
# [Unit]
# Description=Technitium Sync
#
# [Service]
# Type=oneshot
# ExecStart=/usr/local/sbin/technitium-sync.sh
#
# /etc/systemd/system/technitium-sync.timer
# [Unit]
# Description=Run Technitium Sync every 6 hours
#
# [Timer]
# OnCalendar=*:0/6
# Persistent=true
#
# [Install]
# WantedBy=timers.target
#
# Enable and start with:
# sudo systemctl enable --now technitium-sync.timer
# -------------------------------------------------
#
# --- /usr/local/etc/technitium-sync.conf example ---
# master_dns_server='source.ip.address'
# slave_dns_server='dest.ip.address'
# master_dns_serverdomain='fqdn.of.source.server'
# slave_dns_serverdomain='fqdn.of.dest.server'
# master_dns_token='MASTER_TECHNITIUM_TOKEN_HERE'
# slave_dns_token='SLAVE_TECHNITIUM_TOKEN_HERE'
# dhcp_scope_name="local-home"
# disable_dhcp="yes"
# ---------------------------------------------------
usage() {
echo "Usage: $0 [--config <file>] [--no-restore] [--create-cronjob] [--create-systemd] [--generate-conf] [--help]"
echo
echo " --config <file> Use alternate config file (default: /usr/local/etc/technitium-sync.conf)"
echo " --no-restore Only fetch backup from master, do not restore to slave"
echo " --create-cronjob Create a cronjob for this script"
echo " --create-systemd Generate systemd service and timer files"
echo " --generate-conf Interactively generate a config file"
echo " -h, --help Show this help message"
}
# Default values
CONFIG_FILE="/usr/local/etc/technitium-sync.conf"
DO_RESTORE=1
# Helper: Generate config interactively
generate_conf() {
local conf_file="${1:-/usr/local/etc/technitium-sync.conf}"
echo "Generating config file at $conf_file"
read -rp "Master DNS server IP: " master_dns_server
read -rp "Slave DNS server IP: " slave_dns_server
read -rp "Master DNS server domain: " master_dns_serverdomain
read -rp "Slave DNS server domain: " slave_dns_serverdomain
read -rp "Master DNS API token: " master_dns_token
read -rp "Slave DNS API token: " slave_dns_token
read -rp "DHCP scope name (leave empty if not used): " dhcp_scope_name
read -rp "Disable DHCP on slave after restore? (yes/no): " disable_dhcp
sudo tee "$conf_file" >/dev/null <<EOF
master_dns_server='$master_dns_server'
slave_dns_server='$slave_dns_server'
master_dns_serverdomain='$master_dns_serverdomain'
slave_dns_serverdomain='$slave_dns_serverdomain'
master_dns_token='$master_dns_token'
slave_dns_token='$slave_dns_token'
dhcp_scope_name="$dhcp_scope_name"
disable_dhcp="${disable_dhcp:-no}"
EOF
echo "Config file created at $conf_file"
}
# Helper: Create cronjob
create_cronjob() {
local script_path
script_path="$(realpath "$0")"
local cron_line="30 */6 * * * $script_path"
echo "Adding cronjob:"
echo "$cron_line"
(crontab -l 2>/dev/null; echo "$cron_line") | crontab -
echo "Cronjob installed."
}
# Helper: Generate systemd files
create_systemd() {
local script_path
script_path="$(realpath "$0")"
local service_file="/etc/systemd/system/technitium-sync.service"
local timer_file="/etc/systemd/system/technitium-sync.timer"
sudo tee "$service_file" >/dev/null <<EOF
[Unit]
Description=Technitium Sync
[Service]
Type=oneshot
ExecStart=$script_path
EOF
sudo tee "$timer_file" >/dev/null <<EOF
[Unit]
Description=Run Technitium Sync every 6 hours
[Timer]
OnCalendar=*:0/6
Persistent=true
[Install]
WantedBy=timers.target
EOF
echo "Systemd service and timer files created."
echo "Enable and start with:"
echo " sudo systemctl enable --now technitium-sync.timer"
}
# Parse parameters
while [[ $# -gt 0 ]]; do
case "$1" in
--config)
CONFIG_FILE="$2"
shift 2
;;
--no-restore)
DO_RESTORE=0
shift
;;
--create-cronjob)
create_cronjob
exit 0
;;
--create-systemd)
create_systemd
exit 0
;;
--generate-conf)
generate_conf "$CONFIG_FILE"
exit 0
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown parameter: $1"
usage
exit 1
;;
esac
done
# Load configuration
. "$CONFIG_FILE"
set -euxo pipefail
# Use mktemp to create a secure temporary directory
tmp_dir=$(mktemp -d /tmp/technitium-backup.XXXXXX)
backup_file="$tmp_dir/backup.zip"
# Ensure required tools are installed
command -v curl >/dev/null 2>&1 || { echo "curl is not installed. Aborting." >&2; exit 1; }
# Check the master server's health before running the script
echo "Checking master Technitium server status"
status_code=$(curl --write-out %{http_code} --silent --output /dev/null http://$master_dns_server:5380)
if [[ "$status_code" -ne 200 ]] ; then
echo "Master DNS server is not available. Skipping backup"
exit 1
else
echo "Getting the backup archive from the master server"
curl -s "http://$master_dns_server:5380/api/settings/backup?token=$master_dns_token&blockLists=true&logs=false&scopes=true&stats=false&zones=true&allowedZones=true&blockedZones=true&dnsSettings=true&logSettings=true&authConfig=true&apps=true" -o $backup_file
fi
# Ensure cleanup of the temporary directory on exit
cleanup() {
[[ -d "$tmp_dir" ]] && rm -rf "$tmp_dir"
}
trap cleanup EXIT
# restore_backup
if [[ -f "$backup_file" && "$DO_RESTORE" -eq 1 ]]; then
echo "Restoring the backup on $HOSTNAME"
curl -s --form file="@$backup_file" "http://$slave_dns_server:5380/api/settings/restore?token=$slave_dns_token&blockLists=true&logs=true&scopes=true&stats=true&apps=true&zones=true&allowedZones=true&blockedZones=true&dnsSettings=true&logSettings=true&deleteExistingFiles=true&authConfig=true" --output /dev/null
# wait for server to come back
echo "Waiting for 10 seconds for the slave server to start up"
sleep 10
# set dnsServerDomain on slave server
echo "Updating DNS server Domain in slave server"
curl -X POST "http://$slave_dns_server:5380/api/settings/set?token=$slave_dns_token&dnsServerDomain=$slave_dns_serverdomain"
# disable DHCP on the slave server if configured
if [[ "${disable_dhcp,,}" == "yes" && -n "$dhcp_scope_name" ]]; then
echo "Disabling DHCP in slave server"
curl -X POST "http://$slave_dns_server:5380/api/dhcp/scopes/disable?token=$slave_dns_token&name=$dhcp_scope_name"
else
echo "DHCP disable step skipped (disable_dhcp=${disable_dhcp}, dhcp_scope_name='${dhcp_scope_name}')"
fi
# cleanup message (actual cleanup is handled by trap)
echo "Cleaning up temporary files"
elif [[ "$DO_RESTORE" -eq 0 ]]; then
echo "Backup fetched, but not restored (--no-restore set)."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment