Skip to content

Instantly share code, notes, and snippets.

@tranphuquy19
Created September 13, 2025 09:01
Show Gist options
  • Save tranphuquy19/c74d5a88eb6f11344c357629d41c65c5 to your computer and use it in GitHub Desktop.
Save tranphuquy19/c74d5a88eb6f11344c357629d41c65c5 to your computer and use it in GitHub Desktop.
DDNS updater installation script
#!/bin/bash
# DDNS-Updater Installation Script
# Author: Auto-generated installer
# Description: Downloads, installs and configures ddns-updater service
set -e
# Configuration variables
DDNS_VERSION="${DDNS_VERSION:-latest}"
INSTALL_DIR="/usr/local/bin"
CONFIG_DIR="/etc/ddns-updater"
DATA_DIR="$CONFIG_DIR/data"
SERVICE_FILE="/etc/systemd/system/ddns-updater.service"
USER="ddns-updater"
GROUP="ddns-updater"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_blue() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Function to ask user for replacement
ask_replace() {
local item="$1"
echo -e "${YELLOW}$item already exists.${NC}"
while true; do
read -p "Do you want to replace it? (y/n): " yn
case $yn in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer yes or no.";;
esac
done
}
# Function to detect architecture
detect_arch() {
local arch
case $(uname -m) in
x86_64)
arch="amd64"
;;
aarch64)
arch="arm64"
;;
armv7l)
arch="armv7"
;;
armv6l)
arch="armv6"
;;
*)
log_error "Unsupported architecture: $(uname -m)"
exit 1
;;
esac
echo $arch
}
# Function to get latest version
get_latest_version() {
if [ "$DDNS_VERSION" = "latest" ]; then
log_info "Fetching latest version..."
local latest_version=$(curl -s https://api.github.com/repos/qdm12/ddns-updater/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$latest_version" ]; then
log_error "Failed to fetch latest version"
exit 1
fi
echo $latest_version
else
echo $DDNS_VERSION
fi
}
# Function to download ddns-updater binary
download_ddns_updater() {
local version="$1"
local arch="$2"
local download_url="https://github.com/qdm12/ddns-updater/releases/download/${version}/ddns-updater_${version}_linux_${arch}.tar.gz"
local temp_dir=$(mktemp -d)
log_info "Downloading ddns-updater ${version} for ${arch}..."
log_blue "Download URL: $download_url"
if ! curl -L -o "$temp_dir/ddns-updater.tar.gz" "$download_url"; then
log_error "Failed to download ddns-updater"
rm -rf "$temp_dir"
exit 1
fi
log_info "Extracting binary..."
if ! tar -xzf "$temp_dir/ddns-updater.tar.gz" -C "$temp_dir"; then
log_error "Failed to extract ddns-updater"
rm -rf "$temp_dir"
exit 1
fi
# Install binary
log_info "Installing binary to $INSTALL_DIR/ddns-updater..."
sudo cp "$temp_dir/ddns-updater" "$INSTALL_DIR/ddns-updater"
sudo chmod +x "$INSTALL_DIR/ddns-updater"
# Cleanup
rm -rf "$temp_dir"
log_info "Binary installed successfully"
}
# Function to create system user
create_system_user() {
if id "$USER" &>/dev/null; then
log_info "User $USER already exists"
else
log_info "Creating system user $USER..."
sudo useradd -r -s /bin/false -d /nonexistent "$USER"
log_info "User $USER created"
fi
}
# Function to create directories
create_directories() {
log_info "Creating directories..."
sudo mkdir -p "$DATA_DIR"
sudo chown -R "$USER:$GROUP" "$CONFIG_DIR"
log_info "Directories created and ownership set"
}
# Function to create systemd service
create_systemd_service() {
local service_content='[Unit]
Description=DDNS Updater
Documentation=https://github.com/qdm12/ddns-updater
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ddns-updater
Group=ddns-updater
ExecStart=/usr/local/bin/ddns-updater
Restart=always
RestartSec=30
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ddns-updater
# Environment variables
Environment=CONFIG_FILEPATH=/etc/ddns-updater/data/config.json
Environment=LISTENING_ADDRESS=:8000
Environment=PERIOD=5m
Environment=LOG_LEVEL=info
Environment=DATA_DIR=/etc/ddns-updater/data
Environment=HEALTH_SERVER_ADDRESS=:9999
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/etc/ddns-updater
[Install]
WantedBy=multi-user.target'
log_info "Creating systemd service file..."
echo "$service_content" | sudo tee "$SERVICE_FILE" > /dev/null
log_info "Service file created at $SERVICE_FILE"
}
# Function to create empty config file
create_config_file() {
local config_file="$DATA_DIR/config.json"
local config_content='{
"settings": [
{
"provider": "",
"domain": "",
"username": "",
"password": "",
"ip_version": "ipv4"
}
]
}'
log_info "Creating empty configuration file..."
echo "$config_content" | sudo tee "$config_file" > /dev/null
sudo chown "$USER:$GROUP" "$config_file"
log_info "Config file created at $config_file"
log_warn "Please edit $config_file with your DDNS provider settings before starting the service"
}
# Main installation function
main() {
log_blue "=== DDNS-Updater Installation Script ==="
log_blue "Version to install: $DDNS_VERSION"
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]] && ! sudo -v; then
log_error "This script requires root privileges or sudo access"
exit 1
fi
# Check if binary already exists
if [ -f "$INSTALL_DIR/ddns-updater" ]; then
if ! ask_replace "DDNS-Updater binary"; then
log_info "Skipping binary installation"
else
# Stop service if running
if systemctl is-active --quiet ddns-updater 2>/dev/null; then
log_info "Stopping ddns-updater service..."
sudo systemctl stop ddns-updater
fi
# Download and install
arch=$(detect_arch)
version=$(get_latest_version)
download_ddns_updater "$version" "$arch"
fi
else
# Download and install
arch=$(detect_arch)
version=$(get_latest_version)
download_ddns_updater "$version" "$arch"
fi
# Create system user
create_system_user
# Create directories
create_directories
# Check if service file already exists
if [ -f "$SERVICE_FILE" ]; then
if ! ask_replace "Systemd service file"; then
log_info "Keeping existing service file"
else
create_systemd_service
fi
else
create_systemd_service
fi
# Check if config file already exists
if [ -f "$DATA_DIR/config.json" ]; then
if ! ask_replace "Configuration file"; then
log_info "Keeping existing configuration"
else
create_config_file
fi
else
create_config_file
fi
# Reload systemd and enable service
log_info "Reloading systemd daemon..."
sudo systemctl daemon-reload
log_info "Enabling ddns-updater service..."
sudo systemctl enable ddns-updater
# Ask if user wants to start the service
echo
log_blue "Installation completed successfully!"
echo
log_info "Next steps:"
log_info "1. Edit configuration: sudo nano $DATA_DIR/config.json"
log_info "2. Start service: sudo systemctl start ddns-updater"
log_info "3. Check status: sudo systemctl status ddns-updater"
log_info "4. View logs: sudo journalctl -u ddns-updater -f"
log_info "5. Access Web UI: http://localhost:8000"
echo
while true; do
read -p "Do you want to start the service now? (y/n): " yn
case $yn in
[Yy]* )
log_info "Starting ddns-updater service..."
if sudo systemctl start ddns-updater; then
log_info "Service started successfully!"
log_info "Web UI available at: http://localhost:8000"
log_info "Health check: http://localhost:9999/health"
else
log_error "Failed to start service. Check configuration and logs."
fi
break
;;
[Nn]* )
log_info "Service not started. You can start it later with:"
log_blue "sudo systemctl start ddns-updater"
break
;;
* )
echo "Please answer yes or no."
;;
esac
done
echo
log_blue "=== Installation Summary ==="
log_info "Binary: $INSTALL_DIR/ddns-updater"
log_info "Config: $DATA_DIR/config.json"
log_info "Service: $SERVICE_FILE"
log_info "User: $USER"
log_info "Web UI: http://localhost:8000"
log_info "Health: http://localhost:9999/health"
echo
}
# Run main function
main "$@"
@tranphuquy19
Copy link
Author

How to install:

curl -fsSL https://gist.githubusercontent.com/tranphuquy19/c74d5a88eb6f11344c357629d41c65c5/raw/install-ddns-updater.sh | sudo bash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment