Skip to content

Instantly share code, notes, and snippets.

@ergolyam
Last active October 24, 2025 16:47
Show Gist options
  • Select an option

  • Save ergolyam/6ea69a7b6c64e7e725b299243a771e1c to your computer and use it in GitHub Desktop.

Select an option

Save ergolyam/6ea69a7b6c64e7e725b299243a771e1c to your computer and use it in GitHub Desktop.
This custom updater integrates OpenWrt’s `ddns-scripts` with Spaceship.dev DNS.
#!/bin/sh
API_KEY="$api_key"
API_SECRET="$api_secret"
FQDN="$domain"
ADDR="$__IP"
TTL=3600
WAIT="${param_wait:-8}"
DNS="${dns_server:-1.1.1.1}"
RECORDS="${param_records:-@}"
REC_LIST="$(printf '%s' "$RECORDS" | tr ',' ' ')"
BASE="https://spaceship.dev/api/v1/dns/records/$FQDN"
CURL_BASE_OPTS="-sS --fail --connect-timeout 5 -m 20 --retry 3 --retry-delay 2 --retry-all-errors"
HDRS="-H X-Api-Key:$API_KEY -H X-Api-Secret:$API_SECRET"
i="$WAIT"
while [ "$i" -gt 0 ]; do
ip route get 1.1.1.1 >/dev/null 2>&1 || { sleep 1; i=$((i-1)); continue; }
nslookup spaceship.dev "$DNS" >/dev/null 2>&1 || { sleep 1; i=$((i-1)); continue; }
break
done
CURRENT_JSON="$(curl $CURL_BASE_OPTS -G "$BASE" \
-d take=500 -d skip=0 -d orderBy=name $HDRS)" || exit 1
DEL_ITEMS=""
PUT_ITEMS=""
for name in $REC_LIST; do
[ -n "$name" ] || continue
OLD_IPS="$(printf '%s' "$CURRENT_JSON" \
| jsonfilter -e "@.items[@.type=\"A\" && @.name=\"$name\"].address" 2>/dev/null)"
has_match=0
for ip in $OLD_IPS; do
[ -n "$ip" ] || continue
if [ "$ip" != "$ADDR" ]; then
if [ -z "$DEL_ITEMS" ]; then
DEL_ITEMS=$(printf '{"type":"A","name":"%s","address":"%s"}' "$name" "$ip")
else
DEL_ITEMS=$(printf '%s,{"type":"A","name":"%s","address":"%s"}' "$DEL_ITEMS" "$name" "$ip")
fi
else
has_match=1
fi
done
if [ "$has_match" -eq 0 ]; then
if [ -z "$PUT_ITEMS" ]; then
PUT_ITEMS=$(printf '{"type":"A","name":"%s","address":"%s","ttl":%s}' "$name" "$ADDR" "$TTL")
else
PUT_ITEMS=$(printf '%s,{"type":"A","name":"%s","address":"%s","ttl":%s}' "$PUT_ITEMS" "$name" "$ADDR" "$TTL")
fi
fi
done
[ -n "$DEL_ITEMS" ] && DEL_ITEMS="[$DEL_ITEMS]"
if [ -n "$DEL_ITEMS" ]; then
curl $CURL_BASE_OPTS -X DELETE "$BASE" $HDRS \
-H "Content-Type: application/json" \
--data "$DEL_ITEMS" \
-o /dev/null || exit 1
fi
if [ -n "$PUT_ITEMS" ]; then
PUT_BODY=$(printf '{"force":false,"items":[%s]}' "$PUT_ITEMS")
curl $CURL_BASE_OPTS -X PUT "$BASE" $HDRS \
-H "Content-Type: application/json" \
--data "$PUT_BODY" \
-o /dev/null || exit 1
fi
exit $?
@ergolyam

ergolyam commented Aug 4, 2025

Copy link
Copy Markdown
Author

Deploying update_spaceship.sh on OpenWrt (DDNS)

This custom updater integrates OpenWrt’s ddns-scripts with Spaceship.dev DNS.
On each run, it ensures the specified A records point to the router’s current public IPv4 and removes stale A records for those names.

  1. Requirements
  • OpenWrt 19.07+ (tested with recent releases).

  • Packages:

    • ddns-scripts (and ddns-scripts-regular on some versions)
    • curl
    • jsonfilter
  • Install:

    opkg update
    opkg install ddns-scripts curl jsonfilter
  1. Install the updater script
  • Save the script as /usr/lib/ddns/update_spaceship.sh and make it executable:

    curl -fsSL https://gist.github.com/ergolyam/6ea69a7b6c64e7e725b299243a771e1c/raw/update_spaceship.sh \
      -o /usr/lib/ddns/update_spaceship.sh
    chmod +x /usr/lib/ddns/update_spaceship.sh
  • What the script does:

    • Reads credentials (api_key, api_secret), domain (domain), the current WAN IP (__IP), and the list of records (param_records) from the DDNS environment.
    • Calls the Spaceship.dev API to list current records for your domain, deletes any mismatching A records for the requested names, and adds/updates the correct A records with a default TTL=3600.
  1. Configure DDNS
  • Edit /etc/config/ddns and add a service (replace placeholders with your values):
    config service 'spaceship'
            option enabled '1'
            option domain 'example.com'
            option api_key 'YOUR_API_KEY'
            option api_secret 'YOUR_API_SECRET'
            option ip_source 'network'
            option ip_network 'wan'
            option force_interval '72'
            option force_unit 'hours'
            option check_interval '10'
            option check_unit 'minutes'
            option update_script '/usr/lib/ddns/update_spaceship.sh'
            option lookup_host 'example.com'
            option param_records '@,www'
            option dns_server '1.1.1.1'
    • param_records is a comma-separated list of hostnames under domain. Use @ for the root record.
    • If your WAN gets a private address (CGNAT), updates will be skipped because upd_privateip is 0. Consider switching ISPs or using a tunnel if you need a public IPv4.
    • lookup_host is what ddns-scripts resolves to decide if an update is needed (usually the root or one of your records).
  1. Enable and start the DDNS service

    /etc/init.d/ddns enable
    /etc/init.d/ddns restart
    • Give it a minute; the service runs on the check_interval you set (10 minutes above).
  2. Verify

  • Check logs:

    logread -e ddns
  • Confirm DNS records match your current public IPv4:

    # Should show your WAN public IP
    nslookup example.com 1.1.1.1
    nslookup www.example.com 1.1.1.1

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