Code Monkey home page Code Monkey logo

hetzner-api-dyndns's Introduction

Hetzner API DynDNS

A small script to dynamically update DNS records using the Hetzner DNS-API. Feel free to propose changes.

Hetzner DNS API Doc:

https://dns.hetzner.com/api-docs/

Preparations

Install tools

Generate Access Token

First, a new access token must be created in the Hetzner DNS Console. This should be copied immediately, because for security reasons it will not be possible to display the token later. But you can generate as many tokens as you like.

Usage

You store your Access Token either in the script or set it as an OS environment variable. To store it in the script replace <your-hetzner-dns-api-token> in the following line in the script.

...
auth_api_token=${HETZNER_AUTH_API_TOKEN:-'<your-hetzner-dns-api-token>'}
...

As soon as the token is deposited, the script can be called with the appropriate parameters. This allows several DynDNS records to be created in different zones. Optionally, the TTL and the record type can be specified. It is advisable to keep the TTL as low as possible, so that changed records are used as soon as possible.

./dyndns.sh [ -z <Zone ID> | -Z <zone_name> ] [-r <Record ID>] -n <Record Name> [-t <TTL>] [-T <Record Type>]

To keep your DynDNS Records up to date, you have to create a cronjob that calls the script periodically.

Examples: You have several possibilities to call the script. In these examples it is called periodically every 5 minutes and updates the DNS entry if necessary.

In the first example only the API token is passed as environment variable and the remaining information as parameters. This allows for example to set multiple DynDNS entries in different zones when the script is called multiple times with different parameters.

HETZNER_AUTH_API_TOKEN='<your-hetzner-dns-api-token>'

*/5 * * * * /usr/bin/dyndns.sh -Z example.com -n dyn

You can also pass all information as an environment variables to create a DynDNS entry.

HETZNER_AUTH_API_TOKEN='<your-hetzner-dns-api-token>'
HETZNER_ZONE_NAME='example.com'
HETZNER_RECORD_NAME='dyn'

*/5 * * * * /usr/bin/dyndns.sh

OS Environment Variables

You can use the following enviroment variables.

NAME Value Description
HETZNER_AUTH_API_TOKEN 925bf046408b55c313740eef2bc18b1e Your Hetzner API access token
HETZNER_ZONE_NAME example.com The zone name
HETZNER_ZONE_ID DaGaoE6YzDTQHKxrtzfkTx The zone ID. Use either the zone name or the zone ID. Not both.
HETZNER_RECORD_NAME dyn The record name. '@' to set the record for the zone itself.
HETZNER_RECORD_TTL 120 The TTL of the record. Default(60)
HETZNER_RECORD_TYPE AAAA The record type. Either A for IPv4 or AAAA for IPv6. Default(A)

Help

Type -h to display help page.

./dyndns.sh -h
exec: ./dyndns.sh -Z <Zone Name> -n <Record Name>

parameters:
  -z  - Zone ID
  -Z  - Zone Name
  -r  - Record ID
  -n  - Record name

optional parameters:
  -t  - TTL (Default: 60)
  -T  - Record type (Default: A)

help:
  -h  - Show Help 

example:
  .exec: ./dyndns.sh -Z example.com -n dyn -T AAAA
  .exec: ./dyndns.sh -z 98jFjsd8dh1GHasdf7a8hJG7 -r AHD82h347fGAF1 -n dyn

Additional stuff

Get all Zones

If you want to get all zones in your account and check the desired zone ID.

curl "https://dns.hetzner.com/api/v1/zones" -H \
'Auth-API-Token: ${apitoken}' | jq

Get a record ID

If you want to get a record ID manually you may use the following curl command.

curl -s --location \
    --request GET 'https://dns.hetzner.com/api/v1/records?zone_id='${zone_id} \
    --header 'Auth-API-Token: '${apitoken} | \
    jq --raw-output '.records[] | select(.type == "'${record_type}'") | select(.name == "'{record_name}'") | .id'

Add Record manually

Use the previously obtained zone ID to create a dns record. In the output you get the record ID. This is needed for the script and should therefore be noted.

curl -X "POST" "https://dns.hetzner.com/api/v1/records" \
     -H 'Content-Type: application/json' \
     -H 'Auth-API-Token: ${apitoken}' \
     -d $'{
  "value": "${yourpublicip}",
  "ttl": 60,
  "type": "A",
  "name": "dyn",
  "zone_id": "${zoneID}"
}'

hetzner-api-dyndns's People

Contributors

darkdragon-001 avatar e1mo avatar farrowstrange avatar reinernippes avatar simonkaiser9 avatar thcrt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

hetzner-api-dyndns's Issues

Remember current public IP and hit Hetzner API endpoint only if it changes

It might be a good idea not to hit the Hetzner DNS API every five or so minutes when your script is used as part of a cron job. Since you're getting the IP addresses anyway, maybe consider refactoring the script a little bit so it remembers the last public IP address, compares it with the current one, and only invokes any part of Hetzner's DNS API if there is a change.

I had to roll my own DynDNS updater for Namecheap years ago and here's how I achieved the above:

IP=$(curl -sS -A "$AGENT" "https://api.ipify.org")

if [ -z "${IP}" ]; then
	echo "No public IP address at all. Internet down? Not doing anything."
	exit 1
fi

if [ ! -f /tmp/ddnslastip ]
then
	OLDIP="unknown"
else
	OLDIP=$(</tmp/ddnslastip)
fi

printf "The last public IP address was \"%s\" and the current public IP address is \"%s\".\n" "$OLDIP" "$IP"

if [ "$OLDIP" = "$IP" ]; then
	echo "Public IP address has not changed. Nothing to do."
	exit 0
fi

echo "$IP" > /tmp/ddnslastip

# ... perform the update ...

This needs to be updated slightly for IPv6 but I'm sure you get the general idea. Also "api.ipify.org" doesn't do any user agent sniffing (Hetzner's IP address service does to decide whether to return a website or just the IP as plain text). If you switch to it, you can get rid of the pipe to grep.

Add support for IPv6 neighbors

In case of dynamic IPv6 prefixes, every host on the network obtains it's own Global Unicast Address. But there might be devices on the network, that are not able to run this script on their own. Especially IoT devices, like Webcams or other "Smart" stuff, which cannot be accessed. So, how about extending this scripts functionality to also update AAAA records of other devices (IPv6 neighbors) on the same network? I see two ways to achieve this:

The easy way is by providing the Interface Identifier (last 64 bit of the IPv6 address) to the script manually. If you could specify a list of Interface Identifier and corresponding AAAA records, the script would have all what's needed to update other devices AAAA records as well, because the network prefix (first 64 bit) are the same for all hosts in this network/vlan. This method works fine, where the Interface Identifier is generated using the MAC address (EUI-64).

However, there are some network configurations where random IPv6 addresses are assigned by the DHCPv6 server. In that case, Neighbor Discovery Protocol could be used for a lookup of the full IPv6 address, after the address has changed.

What do you think?

jq v1.5 creates dupblicate A-records

I'm running the script on a ubuntu server LTS 18.04 which only has jq version 1.5-1-a5b5cbe.

  1. when I run the script I get following output which is very strange because a) it shows that the script does find the jq command but still I get:

root@server1:/usr/local/bin# ./dyndns.sh
Info: Record_Name: server1 : Zone_ID:
Info: Record_Name: server1 : Zone_Name:
Info: Record_Name: server1 : Using IPv4, because A was set as record type.
Info: Record_Name: server1 : Current public IP address:
jq - commandline JSON processor [version 1.5-1-a5b5cbe]
Usage: jq [options] [file...]

jq is a tool for processing JSON inputs, applying the
given filter to its JSON text inputs and producing the
filter's results as JSON on standard output.
The simplest filter is ., which is the identity filter,
copying jq's input to its output unmodified (except for
formatting).
For more advanced filters see the jq(1) manpage ("man jq")
and/or https://stedolan.github.io/jq

Some of the options include:
 -c		compact instead of pretty-printed output;
 -n		use `null` as the single input value;
 -e		set the exit status code based on the output;
 -s		read (slurp) all inputs into an array; apply filter to it;
 -r		output raw strings, not JSON texts;
 -R		read raw strings, not JSON texts;
 -C		colorize JSON;
 -M		monochrome (don't colorize JSON);
 -S		sort keys of objects on output;
 --tab	use tabs for indentation;
 --arg a v	set variable $a to value <v>;
 --argjson a v	set variable $a to JSON value <v>;
 --slurpfile a f	set variable $a to an array of JSON texts read from <f>;
See the manpage for more options.

Info: Record_Name: : Record_ID:
DNS record "" does not exists - will be created.
{"record":{"id":"","type":"","name":"","value":"","zone_id":"","created":"","modified":""},"error":{"message":"422 Unprocessable Entity: taken: ; ","code":422}}

I guess the last line means that some part of the input cannot be processed by that jq version? Is there a workaround that will work with this version?

Find alternatives to determine the public ip address

It should be checked whether there are alternatives to external services with which the public IP address can be determined.
At the current time "ifconfig.co" is used to determine the public IPv4 and IPv6 addresses.

Maybe there is a solution which can be mapped via the Hetzner services.

Consider fixing shellcheck issues

There are some minor issues when running ShellCheck on the script. The biggest ones (using features not available on POSIX sh) can be fixed by changing the shebang from #!/bin/sh to e.g. #!/usr/bin/env bash

What follows is the full ShellCheck output so you can get an idea. This is after I changed the interpreter from sh to bash. I understand that majority of the problems it finds are subjective, but I still figured I'd let you know. Feel free to close the issue as WONTFIX etc. if you don't care.

# shellcheck hetznerddns.sh

In hetznerddns.sh line 46:
  echo ${1}: Record_Name: ${record_name} : ${2}
       ^--^ SC2086 (info): Double quote to prevent globbing and word splitting.
                          ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                           ^--^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
  echo "${1}": Record_Name: "${record_name}" : "${2}"


In hetznerddns.sh line 81:
          --header 'Auth-API-Token: '${auth_api_token})
                                     ^---------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          --header 'Auth-API-Token: '"${auth_api_token}")


In hetznerddns.sh line 84:
if [[ "$(echo ${zone_info} | jq --raw-output '.zones[] | select(.name=="'${zone_name}'") | .id')" = "" && "$(echo ${zone_info} | jq --raw-output '.zones[] | select(.id=="'${zone_id}'") | .name')" = "" ]]; then
              ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                         ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                                                                  ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                                                                                                                           ^--------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
if [[ "$(echo "${zone_info}" | jq --raw-output '.zones[] | select(.name=="'"${zone_name}"'") | .id')" = "" && "$(echo "${zone_info}" | jq --raw-output '.zones[] | select(.id=="'"${zone_id}"'") | .name')" = "" ]]; then


In hetznerddns.sh line 93:
  zone_id=$(echo ${zone_info} | jq --raw-output '.zones[] | select(.name=="'${zone_name}'") | .id')
                 ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                            ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
  zone_id=$(echo "${zone_info}" | jq --raw-output '.zones[] | select(.name=="'"${zone_name}"'") | .id')


In hetznerddns.sh line 98:
  zone_name=$(echo ${zone_info} | jq --raw-output '.zones[] | select(.id=="'${zone_id}'") | .name')
                   ^----------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                            ^--------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
  zone_name=$(echo "${zone_info}" | jq --raw-output '.zones[] | select(.id=="'"${zone_id}"'") | .name')


In hetznerddns.sh line 137:
                 --request GET 'https://dns.hetzner.com/api/v1/records?zone_id='${zone_id} \
                                                                                ^--------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
                 --request GET 'https://dns.hetzner.com/api/v1/records?zone_id='"${zone_id}" \


In hetznerddns.sh line 138:
                 --header 'Auth-API-Token: '${auth_api_token})
                                            ^---------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
                 --header 'Auth-API-Token: '"${auth_api_token}")


In hetznerddns.sh line 145:
    record_id=$(echo ${record_zone} | jq | sed '$d' | jq --raw-output '.records[] | select(.type == "'${record_type}'") | select(.name == "'${record_name}'") | .id')
                     ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                                                      ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                                                                                                                            ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
    record_id=$(echo "${record_zone}" | jq | sed '$d' | jq --raw-output '.records[] | select(.type == "'"${record_type}"'") | select(.name == "'"${record_name}"'") | .id')


In hetznerddns.sh line 156:
       -H 'Auth-API-Token: '${auth_api_token} \
                            ^---------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
       -H 'Auth-API-Token: '"${auth_api_token}" \


In hetznerddns.sh line 158:
          "value": "'${cur_pub_addr}'",
                     ^-------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          "value": "'"${cur_pub_addr}"'",


In hetznerddns.sh line 159:
          "ttl": '${record_ttl}',
                  ^-----------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          "ttl": '"${record_ttl}"',


In hetznerddns.sh line 160:
          "type": "'${record_type}'",
                    ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          "type": "'"${record_type}"'",


In hetznerddns.sh line 161:
          "name": "'${record_name}'",
                    ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          "name": "'"${record_name}"'",


In hetznerddns.sh line 162:
          "zone_id": "'${zone_id}'"
                       ^--------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
          "zone_id": "'"${zone_id}"'"


In hetznerddns.sh line 166:
  cur_dyn_addr=`curl -s "https://dns.hetzner.com/api/v1/records/${record_id}" -H 'Auth-API-Token: '${auth_api_token} | jq --raw-output '.record.value'`
               ^-- SC2006 (style): Use $(...) notation instead of legacy backticks `...`.
                                                                                                   ^---------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
  cur_dyn_addr=$(curl -s "https://dns.hetzner.com/api/v1/records/${record_id}" -H 'Auth-API-Token: '"${auth_api_token}" | jq --raw-output '.record.value')


In hetznerddns.sh line 171:
  if [[ $cur_pub_addr == $cur_dyn_addr ]]; then
                         ^-----------^ SC2053 (warning): Quote the right-hand side of == in [[ ]] to prevent glob matching.


In hetznerddns.sh line 178:
         -H 'Auth-API-Token: '${auth_api_token} \
                              ^---------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
         -H 'Auth-API-Token: '"${auth_api_token}" \


In hetznerddns.sh line 180:
           "value": "'${cur_pub_addr}'",
                      ^-------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
           "value": "'"${cur_pub_addr}"'",


In hetznerddns.sh line 181:
           "ttl": '${record_ttl}',
                   ^-----------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
           "ttl": '"${record_ttl}"',


In hetznerddns.sh line 182:
           "type": "'${record_type}'",
                     ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
           "type": "'"${record_type}"'",


In hetznerddns.sh line 183:
            "name": "'${record_name}'",
                      ^------------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
            "name": "'"${record_name}"'",


In hetznerddns.sh line 184:
           "zone_id": "'${zone_id}'"
                        ^--------^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
           "zone_id": "'"${zone_id}"'"


In hetznerddns.sh line 186:
    if [[ $? != 0 ]]; then
          ^-- SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.

For more information:
  https://www.shellcheck.net/wiki/SC2053 -- Quote the right-hand side of == i...
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
  https://www.shellcheck.net/wiki/SC2006 -- Use $(...) notation instead of le...

Multiple Records at once

I am setting up a local webserver for me and ofcourse some friends.
i am testing this script and its very helpful.

But my question: Is it possible to issue changes on Multiple Records like -Z example.com -n dyn -n @ or -Z example.com -n dyn,@
or something like that

systemd timer-installation example

I like systemd timers more than cronjobs so I wrote one.

Benefit against cronjob: It runs immediately after boot and from then every 5 minutes. A cronjob runs every fifth minute, i.e. you have to wait 2.5 minutes after boot on average for a initial update.

sudo curl -L https://github.com/FarrowStrange/hetzner-api-dyndns/releases/download/v1.3/dyndns.sh -o /usr/local/bin/hetzner-api-dyndns
sudo chmod +x /usr/local/bin/hetzner-api-dyndns
sudo mkdir -p /etc/hetzner-api-dyndns
cat <<EOF | sudo tee /etc/hetzner-api-dyndns.conf
HETZNER_ZONE_NAME=examle.com
HETZNER_RECORD_NAME=yourhost
HETZNER_RECORD_TYPE=AAAA
HETZNER_AUTH_API_TOKEN=<token>
EOF

cat <<EOF | sudo tee /etc/systemd/system/hetzner-api-dyndns.service
[Unit]
Description=update dyndns entry via hetzner API
After=network-online.target

[Service]
EnvironmentFile=/etc/hetzner-api-dyndns.conf
ExecStart=/usr/local/bin/hetzner-api-dyndns
EOF

cat <<EOF | sudo tee /etc/systemd/system/hetzner-api-dyndns.timer
[Unit]
Description=update dyndns entry via hetzner API every five minutes

[Timer]
Unit=hetzner-api-dyndns.service
# my network takes longer for the IPv6 address
OnBootSec=20
OnUnitActiveSec=5m

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now hetzner-api-dyndns.timer

curl not found

The script states, that curl is not installed (Debian 12 Bookworm)

root@server:~# ./dyndns.sh
Error: Record_Name: : To run the script 'curl' is needed, but it seems not to be installed.
Error: Record_Name: : Please check 'https://github.com/FarrowStrange/hetzner-api-dyndns#install-tools' for more informations and try again.
/usr/bin/curl

But in fact, it is installed:

root@server:~# apt install curl
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
curl is already the newest version (7.88.1-10+deb12u4).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

root@server:~# command -v curl
/usr/bin/curl

root@server:~# curl
curl: try 'curl --help' or 'curl --manual' for more information

Support OpenWRT's `ddns-scripts`

OpenWRT uses ddns-scripts to provide generic DDNS configuration through SSH and the LuCI web interface.

The main thing that sets the Hetzner API apart from other DDNS providers is that it requires special headers, for instance the authentication token. Most others use URL parameters, meaning you can't use Hetzner on ddns-scripts out-of-the-box.

However, the scripts can be customised, and an example is given here. At some point, it would be good to implement something like this so that OpenWRT users have a more 'native' solution compared to running a script in Cron.

I could take this on at some point -- FarrowStrange, I'm not trying to ask you to completely rewrite it to support an entirely different platform ;) I will implement it downstream in my fork and PR if it's completed.

Getting curl error "-->: is unknown" after loading IP from ifconfig.io

I get the following error when using the script.

Info: Record_Name: vpn : Zone_ID: ZONE_ID
Info: Record_Name: vpn : Zone_Name: ZONE_NAME
Info: Record_Name: vpn : Using IPv4 as record type A is not explicitly AAAA.
Info: Record_Name: vpn : Record_ID: RECORD_ID
Info: Record_Name: vpn : Current public IP Address: 123.456.789.0
DNS record "vpn" is no longer valid - updating record
curl: option -->: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Error: Record_Name: vpn : Unable to update record: "vpn"

When I checked the variables the script uses I figured out that ${cur_pub_addr} contains the whole HTML code of ifconfig.io and not just a single IP address.
This leads in line 144 to an always false statement as a single IP address never matches a whole HTML page. And when calling the PUT statement with curl from line 149 the error occurs with ${cur_pub_addr} as parameter it failes.
Is there some HTML parsing necessary or is my curl strange when getting the ${cur_pub_addr} ?

EDIT: I figured out that Cloudflare is the problem. When I call curl -4 -s ifconfig.co from my commandline I get the Cloudflare captcha page and the IP adress is hidden in the HTML page.

FIX options:

  • choosing different public IP providers (e.g. ifconfig.io)
  • parsing the HTML code (I think just too unnecessary (it is the public IP address cloudflare shows)
  • provide an error message when Cloudflare captchas happend

script cant find "Jq"

script wont run, it says jq is not installed. But there it is ;(
pi@raspberrypi:~/dns/hetzner-api-dyndns $ sh dyndns.sh Error: Record_Name: XYZ : To run the script 'jq' is needed, but it seems not to be installed. /usr/bin/jq Error: Record_Name: XYZ : Please check 'https://github.com/FarrowStrange/hetzner-api-dyndns#install-jq' for more informations and try again.

sudo apt-get install jq Paketlisten werden gelesen... Fertig Abhängigkeitsbaum wird aufgebaut. Statusinformationen werden eingelesen.... Fertig jq ist schon die neueste Version (1.5+dfsg-2+b1). 0 aktualisiert, 0 neu installiert, 0 zu entfernen und 1 nicht aktualisiert.

`pi@raspberrypi:/usr/bin $ jq
jq - commandline JSON processor [version 1.5-1-a5b5cbe]
Usage: jq [options] [file...]

    jq is a tool for processing JSON inputs, applying the
    given filter to its JSON text inputs and producing the
    filter's results as JSON on standard output.
    The simplest filter is ., which is the identity filter,
    copying jq's input to its output unmodified (except for
    formatting).
    For more advanced filters see the jq(1) manpage ("man jq")
    and/or https://stedolan.github.io/jq

    Some of the options include:
     -c             compact instead of pretty-printed output;
     -n             use `null` as the single input value;
     -e             set the exit status code based on the output;
     -s             read (slurp) all inputs into an array; apply filter to it;
     -r             output raw strings, not JSON texts;
     -R             read raw strings, not JSON texts;
     -C             colorize JSON;
     -M             monochrome (don't colorize JSON);
     -S             sort keys of objects on output;
     --tab  use tabs for indentation;
     --arg a v      set variable $a to value <v>;
     --argjson a v  set variable $a to JSON value <v>;
     --slurpfile a f        set variable $a to an array of JSON texts read from <f>;
    See the manpage for more options.

`
any ideas?

Dockerfile example alpine with cron enabled

quite handy, have it running on a Synology NAS. Should be running almost anywhere.

Preconfig:

  • Download script, save it accessible for the container.
  • Script: Change first line to '#!/bin/ash'
  • Script: Preconfigure Script-Parameters, or add script parameters to cronjob.
  • Dockerfile: Change echo for cronjobs to your needs. See example.
  • Mount Container Folder with scripts to '/srv'
# Dockerfile to create image with cron services
FROM alpine:latest

#Configure
RUN apk add --no-cache curl
RUN apk add --no-cache bind-tools
RUN apk add --no-cache jq

#Cronjobs
RUN echo '*/5     *       *       *       *       /bin/ash /srv/hetzner-dyndns_alpine.sh >> /srv/hetzner-dyndns.log' >> /root/crontab.conf


# Add the cron job
RUN crontab /root/crontab.conf

# Run the command on container startup
CMD [ "/usr/sbin/crond", "-f", "-d8" ]

Script doesn't work

Sorry if this is a totally dumb callout as I'm not really familiar with bash scripting.
Downloaded v.1.1 of the script but even with calling it minimum parameters from the readme example it shows errors right away:
./dyndns.sh -Z example.com -n dyn -T AAAA
jq: error (at :1): Cannot iterate over null (null)
jq: error (at :1): Cannot iterate over null (null)
Error: Record_Name: : Something went wrong. Could not find Zone ID.
Error: Record_Name: : Check your inputs of either -z or -Z .
Error: Record_Name: : Use -h to display help.

Script creates new A record

Hi,

nice script dude. Sadly the script creates a new A record instead of updating the created one.
Can you fix this?

Script creates new A record instead of updating current one

First of all: Very nice script, thanks a lot!

I set the script up here at home with the HETZNER_AUTH_API_TOKEN put in the script as well as HETZNER_ZONE_NAME and HETZNER_RECORD_NAME and let cron just execute the script without any additional parameters.
This worked fine at first, no errors, just updating the record as it's supposed to. The cronjob run every minute with a default TTL of 60.

Now one day later I figured that I had 2 pairs of identical records (4 total) in my DNS zone instead of only one?!
Maybe that was caused by rapidly changing IP addresses, because I fiddled around with my networking gear yesterday and had a few reconnects with different IP addresses because of that?

Anyway, if there is more than one identical record in the zone to be updated, then the script failes to do so. Maybe because it does not know which one to update?
Another question is, how those multiple entries got there in the first place. Maybe due to rapid IP address change, the IP address query can report more than one IPv4 address?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.