Archived
Preserve the GitHub history and the newer deployed source from ct_134_karldns. Exclude runtime data, credentials, AppleDouble files and local backup copies. Make Gitea the canonical source for documentation, package metadata and project links.
312 lines
10 KiB
Bash
Executable File
312 lines
10 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
KARLDNS_BASE_URL="${KARLDNS_BASE_URL:-https://karldns.de}"
|
|
KARLDNS_INTERVAL_MINUTES="${KARLDNS_INTERVAL_MINUTES:-5}"
|
|
KARLDNS_INSTALL_MODE="${KARLDNS_INSTALL_MODE:-auto}"
|
|
KARLDNS_UPDATE_URL="${KARLDNS_UPDATE_URL:-}"
|
|
KARLDNS_HOSTNAME="${KARLDNS_HOSTNAME:-}"
|
|
KARLDNS_MANAGEMENT_URL="${KARLDNS_MANAGEMENT_URL:-}"
|
|
KARLDNS_ACTIVATION_URL="${KARLDNS_ACTIVATION_URL:-}"
|
|
KARLDNS_RAW_BASE_URL="${KARLDNS_RAW_BASE_URL:-}"
|
|
KARLDNS_IPV4="${KARLDNS_IPV4:-auto}"
|
|
KARLDNS_IPV6="${KARLDNS_IPV6:-auto}"
|
|
KARLDNS_SKIP_CRON="${KARLDNS_SKIP_CRON:-0}"
|
|
KARLDNS_SKIP_FIRST_UPDATE="${KARLDNS_SKIP_FIRST_UPDATE:-0}"
|
|
KARLDNS_REUSED_CONFIG=0
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
KarlDNS Linux installer
|
|
|
|
Usage:
|
|
install-linux.sh [options]
|
|
|
|
Options:
|
|
--base-url URL KarlDNS server URL. Default: https://karldns.de
|
|
--raw-base-url URL Updater script download URL
|
|
--every MINUTES Update interval, 1-60. Default: 5
|
|
--mode MODE auto, system, or user. Default: auto
|
|
--update-url URL Existing private update URL
|
|
--hostname NAME Hostname to show after install
|
|
--dashboard-url URL Private dashboard URL to show after install
|
|
--activation-url URL Private registration URL for pending hostnames
|
|
--ipv4 VALUE auto, off, or a static IPv4. Default: auto
|
|
--ipv6 VALUE auto, off, or a static IPv6. Default: auto
|
|
--no-cron Install files only, do not configure cron
|
|
--no-run Do not run the first update after install
|
|
-h, --help Show this help
|
|
|
|
Examples:
|
|
curl -fsSL https://karldns.de/install.sh | sudo sh
|
|
curl -fsSL https://karldns.de/install.sh | sh -s -- --mode user
|
|
EOF
|
|
}
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--base-url) KARLDNS_BASE_URL="${2:?missing value for --base-url}"; shift 2 ;;
|
|
--raw-base-url) KARLDNS_RAW_BASE_URL="${2:?missing value for --raw-base-url}"; shift 2 ;;
|
|
--every) KARLDNS_INTERVAL_MINUTES="${2:?missing value for --every}"; shift 2 ;;
|
|
--mode) KARLDNS_INSTALL_MODE="${2:?missing value for --mode}"; shift 2 ;;
|
|
--update-url) KARLDNS_UPDATE_URL="${2:?missing value for --update-url}"; shift 2 ;;
|
|
--hostname) KARLDNS_HOSTNAME="${2:?missing value for --hostname}"; shift 2 ;;
|
|
--dashboard-url|--management-url) KARLDNS_MANAGEMENT_URL="${2:?missing value for --dashboard-url}"; shift 2 ;;
|
|
--activation-url) KARLDNS_ACTIVATION_URL="${2:?missing value for --activation-url}"; shift 2 ;;
|
|
--ipv4) KARLDNS_IPV4="${2:?missing value for --ipv4}"; shift 2 ;;
|
|
--ipv6) KARLDNS_IPV6="${2:?missing value for --ipv6}"; shift 2 ;;
|
|
--no-cron) KARLDNS_SKIP_CRON=1; shift ;;
|
|
--no-run) KARLDNS_SKIP_FIRST_UPDATE=1; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "KarlDNS installer: unknown option: $1" >&2; usage >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
KARLDNS_RAW_BASE_URL="${KARLDNS_RAW_BASE_URL:-${KARLDNS_BASE_URL%/}}"
|
|
|
|
need() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "KarlDNS installer: missing required command: $1" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
json_field() {
|
|
key="$1"
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
python3 -c 'import json,sys; print(json.load(sys.stdin).get(sys.argv[1], ""))' "$key"
|
|
else
|
|
sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" | head -n 1
|
|
fi
|
|
}
|
|
|
|
quote_sh() {
|
|
printf "%s" "$1" | sed "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
|
|
}
|
|
|
|
download_updater() {
|
|
target_path="$1"
|
|
tmp_path="$(mktemp)"
|
|
mkdir -p "$(dirname "$target_path")"
|
|
if ! "$curl_bin" -fsS "$KARLDNS_RAW_BASE_URL/karldns-update.sh" -o "$tmp_path"; then
|
|
rm -f "$tmp_path"
|
|
exit 1
|
|
fi
|
|
chmod 755 "$tmp_path"
|
|
mv "$tmp_path" "$target_path"
|
|
}
|
|
|
|
load_existing_config() {
|
|
if [ -n "$KARLDNS_UPDATE_URL" ]; then
|
|
return
|
|
fi
|
|
config_file="$1"
|
|
if [ -r "$config_file" ]; then
|
|
# shellcheck disable=SC1090
|
|
. "$config_file"
|
|
KARLDNS_REUSED_CONFIG=1
|
|
fi
|
|
}
|
|
|
|
cron_schedule() {
|
|
if [ "$KARLDNS_INTERVAL_MINUTES" = "60" ]; then
|
|
printf '0 * * * *'
|
|
else
|
|
printf '*/%s * * * *' "$KARLDNS_INTERVAL_MINUTES"
|
|
fi
|
|
}
|
|
|
|
update_crontab() {
|
|
cron_file="$1"
|
|
schedule="$2"
|
|
command="$3"
|
|
marker_start="# karldns-update start"
|
|
marker_end="# karldns-update end"
|
|
awk -v start="$marker_start" -v end="$marker_end" '
|
|
$0 == start {skip = 1; next}
|
|
$0 == end {skip = 0; next}
|
|
skip != 1 {print}
|
|
' "$cron_file" 2>/dev/null
|
|
printf '%s\n' "$marker_start"
|
|
printf '%s %s\n' "$schedule" "$command"
|
|
printf '%s\n' "$marker_end"
|
|
}
|
|
|
|
install_system_cron() {
|
|
schedule="$1"
|
|
command="$2"
|
|
if [ -d /etc/cron.d ]; then
|
|
cron_file="/etc/cron.d/karldns-updater"
|
|
cat > "$cron_file" <<EOF
|
|
SHELL=/bin/sh
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
$schedule root $command
|
|
EOF
|
|
chmod 644 "$cron_file"
|
|
return
|
|
fi
|
|
|
|
if [ -d /etc/crontabs ]; then
|
|
cron_file="/etc/crontabs/root"
|
|
tmp_file="$(mktemp)"
|
|
update_crontab "$cron_file" "$schedule" "$command" > "$tmp_file"
|
|
cat "$tmp_file" > "$cron_file"
|
|
rm -f "$tmp_file"
|
|
chmod 600 "$cron_file" 2>/dev/null || true
|
|
return
|
|
fi
|
|
|
|
if command -v crontab >/dev/null 2>&1; then
|
|
cron_file="$(mktemp)"
|
|
crontab -l > "$cron_file" 2>/dev/null || true
|
|
update_crontab "$cron_file" "$schedule" "$command" > "$cron_file.new"
|
|
mv "$cron_file.new" "$cron_file"
|
|
crontab "$cron_file"
|
|
rm -f "$cron_file"
|
|
return
|
|
fi
|
|
|
|
echo "KarlDNS installer: cron is not available. Install cron or re-run with --no-cron." >&2
|
|
exit 1
|
|
}
|
|
|
|
write_config() {
|
|
config_file="$1"
|
|
cache_file="$2"
|
|
lock_file="$3"
|
|
umask 077
|
|
{
|
|
printf 'KARLDNS_BASE_URL=%s\n' "$(quote_sh "$KARLDNS_BASE_URL")"
|
|
printf 'KARLDNS_UPDATE_URL=%s\n' "$(quote_sh "$KARLDNS_UPDATE_URL")"
|
|
printf 'KARLDNS_HOSTNAME=%s\n' "$(quote_sh "$KARLDNS_HOSTNAME")"
|
|
printf 'KARLDNS_MANAGEMENT_URL=%s\n' "$(quote_sh "$KARLDNS_MANAGEMENT_URL")"
|
|
printf 'KARLDNS_ACTIVATION_URL=%s\n' "$(quote_sh "$KARLDNS_ACTIVATION_URL")"
|
|
printf 'KARLDNS_CACHE_FILE=%s\n' "$(quote_sh "$cache_file")"
|
|
printf 'KARLDNS_LOCK_FILE=%s\n' "$(quote_sh "$lock_file")"
|
|
printf 'KARLDNS_IPV4=%s\n' "$(quote_sh "$KARLDNS_IPV4")"
|
|
printf 'KARLDNS_IPV6=%s\n' "$(quote_sh "$KARLDNS_IPV6")"
|
|
} > "$config_file"
|
|
chmod 600 "$config_file"
|
|
}
|
|
|
|
install_user() {
|
|
config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/karldns"
|
|
cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/karldns"
|
|
bin_dir="${HOME}/.local/bin"
|
|
config_file="${config_dir}/updater.env"
|
|
updater_path="${bin_dir}/karldns-update"
|
|
cron_file="$(mktemp)"
|
|
mkdir -p "$config_dir" "$cache_dir" "$bin_dir"
|
|
|
|
download_updater "$updater_path"
|
|
chmod 700 "$updater_path"
|
|
|
|
write_config "$config_file" "$cache_dir/last-ip" "$cache_dir/updater.lock"
|
|
|
|
if [ "$KARLDNS_SKIP_CRON" = "0" ]; then
|
|
need crontab
|
|
crontab -l > "$cron_file" 2>/dev/null || true
|
|
update_crontab "$cron_file" "$(cron_schedule)" \
|
|
"KARLDNS_CONFIG=$(quote_sh "$config_file") $(quote_sh "$updater_path") >/dev/null 2>&1" > "$cron_file.new"
|
|
mv "$cron_file.new" "$cron_file"
|
|
crontab "$cron_file"
|
|
rm -f "$cron_file"
|
|
fi
|
|
}
|
|
|
|
install_system() {
|
|
config_dir="/etc/karldns"
|
|
cache_dir="/var/cache/karldns"
|
|
config_file="${config_dir}/updater.env"
|
|
updater_path="/usr/local/bin/karldns-update"
|
|
mkdir -p "$config_dir" "$cache_dir"
|
|
|
|
download_updater "$updater_path"
|
|
|
|
write_config "$config_file" "$cache_dir/last-ip" "/run/karldns-updater.lock"
|
|
|
|
if [ "$KARLDNS_SKIP_CRON" = "0" ]; then
|
|
install_system_cron "$(cron_schedule)" "KARLDNS_CONFIG=$(quote_sh "$config_file") $(quote_sh "$updater_path") >/dev/null 2>&1"
|
|
fi
|
|
}
|
|
|
|
need curl
|
|
curl_bin="$(command -v curl)"
|
|
|
|
case "$KARLDNS_INTERVAL_MINUTES" in
|
|
''|*[!0-9]*) echo "KARLDNS_INTERVAL_MINUTES must be a positive integer" >&2; exit 1 ;;
|
|
esac
|
|
if [ "$KARLDNS_INTERVAL_MINUTES" -lt 1 ] || [ "$KARLDNS_INTERVAL_MINUTES" -gt 60 ]; then
|
|
echo "KARLDNS_INTERVAL_MINUTES must be between 1 and 60" >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "$KARLDNS_INSTALL_MODE" in
|
|
auto)
|
|
if [ "$(id -u)" -eq 0 ]; then
|
|
KARLDNS_INSTALL_MODE="system"
|
|
else
|
|
KARLDNS_INSTALL_MODE="user"
|
|
fi
|
|
;;
|
|
user|system) ;;
|
|
*) echo "KARLDNS_INSTALL_MODE must be auto, user, or system" >&2; exit 1 ;;
|
|
esac
|
|
|
|
if [ "$KARLDNS_INSTALL_MODE" = "system" ] && [ "$(id -u)" -ne 0 ]; then
|
|
echo "System install needs root. Re-run with sudo or use --mode user." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$KARLDNS_INSTALL_MODE" = "system" ]; then
|
|
load_existing_config /etc/karldns/updater.env
|
|
else
|
|
load_existing_config "${XDG_CONFIG_HOME:-$HOME/.config}/karldns/updater.env"
|
|
fi
|
|
|
|
if [ -z "$KARLDNS_UPDATE_URL" ]; then
|
|
echo "KarlDNS: creating a new hostname at $KARLDNS_BASE_URL ..."
|
|
response="$("$curl_bin" -fsS --max-time 30 -X POST -H "Content-Type: application/x-www-form-urlencoded" "$KARLDNS_BASE_URL/api/v1/hostnames")"
|
|
KARLDNS_UPDATE_URL="$(printf '%s' "$response" | json_field update_url)"
|
|
KARLDNS_HOSTNAME="$(printf '%s' "$response" | json_field hostname)"
|
|
KARLDNS_MANAGEMENT_URL="$(printf '%s' "$response" | json_field dashboard_url)"
|
|
KARLDNS_ACTIVATION_URL="$(printf '%s' "$response" | json_field registration_url)"
|
|
fi
|
|
|
|
if [ -z "$KARLDNS_UPDATE_URL" ]; then
|
|
echo "KarlDNS installer: could not create an update URL" >&2
|
|
exit 1
|
|
fi
|
|
case "$KARLDNS_UPDATE_URL" in
|
|
*"<ipaddr>"*|*"<ip6addr>"*) KARLDNS_UPDATE_URL="${KARLDNS_UPDATE_URL%%\?*}" ;;
|
|
esac
|
|
|
|
if [ -n "$KARLDNS_ACTIVATION_URL" ] && [ "$KARLDNS_REUSED_CONFIG" = "0" ]; then
|
|
echo "KarlDNS: registering hostname ..."
|
|
"$curl_bin" -fsS --max-time 30 -X POST -H "Content-Type: application/x-www-form-urlencoded" "$KARLDNS_ACTIVATION_URL" >/dev/null
|
|
fi
|
|
|
|
if [ "$KARLDNS_INSTALL_MODE" = "system" ]; then
|
|
install_system
|
|
else
|
|
install_user
|
|
fi
|
|
|
|
echo "KarlDNS installed."
|
|
echo "Hostname: ${KARLDNS_HOSTNAME:-already configured}"
|
|
echo "Dashboard: ${KARLDNS_MANAGEMENT_URL:-use your existing private dashboard}"
|
|
echo "Mode: $KARLDNS_INSTALL_MODE"
|
|
if [ "$KARLDNS_SKIP_CRON" = "0" ]; then
|
|
echo "Interval: every $KARLDNS_INTERVAL_MINUTES minutes"
|
|
else
|
|
echo "Cron: skipped"
|
|
fi
|
|
if [ "$KARLDNS_SKIP_FIRST_UPDATE" = "0" ]; then
|
|
echo "Running first update now..."
|
|
if [ "$KARLDNS_INSTALL_MODE" = "system" ]; then
|
|
KARLDNS_CONFIG=/etc/karldns/updater.env /usr/local/bin/karldns-update
|
|
else
|
|
KARLDNS_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/karldns/updater.env" "$HOME/.local/bin/karldns-update"
|
|
fi
|
|
fi
|