aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2024-03-15-self-hosting-ddns-updater.org
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/2024-03-15-self-hosting-ddns-updater.org')
-rw-r--r--content/blog/2024-03-15-self-hosting-ddns-updater.org314
1 files changed, 314 insertions, 0 deletions
diff --git a/content/blog/2024-03-15-self-hosting-ddns-updater.org b/content/blog/2024-03-15-self-hosting-ddns-updater.org
new file mode 100644
index 0000000..0e70c58
--- /dev/null
+++ b/content/blog/2024-03-15-self-hosting-ddns-updater.org
@@ -0,0 +1,314 @@
+#+title: Self-Hosting DDNS Updater
+#+date: <2024-03-15 Fri 14:49:59>
+#+description: A guide to self-hosting the DDNS Updater container.
+
+#+caption: DDNS Updater Web View
+[[https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png]]
+
+[[https://github.com/qdm12/ddns-updater][DDNS Updater]] is a program to
+keep DNS A and/or AAAA records updated for multiple DNS providers.
+
+If you've read any of my other posts, you'll notice that I have been
+searching for and using a few different DDNS updating solutions for
+years. You'll also notice that I love any projects that offer a Docker
+Compose solution.
+
+Luckily, DDNS Upater fits both of these preferences.
+
+** Installation
+
+To get started, always make sure to review the project's
+[[https://github.com/qdm12/ddns-updater/blob/master/README.md][README]].
+I'll be documenting my steps below, but they may have changed by the
+time you read this.
+
+The first step is to set up the directories and files required for the
+project.
+
+#+begin_src sh
+mkdir ~/ddns-updater
+mkdir ~/ddns-updater/data
+touch ~/ddns-updater/data/config.json
+#+end_src
+
+*** Configuration
+
+The main configuration you need to update is the =data/config.json=
+file. There is a large list of supported providers in the README, but
+I'm going to use Cloudflare in this example.
+
+#+begin_src sh
+nano ~/ddns-updater/data/config.json
+#+end_src
+
+When setting up the configuration for Cloudflare, you'll need the
+following:
+
+- Required Parameters
+ - ="zone_identifier"= is the Zone ID of your site from the domain
+ overview page
+ - ="host"= is your host and can be ="@"=, a subdomain or the wildcard
+ ="*"=. See
+ [[https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949][this
+ issue comment for context]].
+ - ="ttl"= integer value for record TTL in seconds (specify 1 for
+ automatic)
+ - One of the following
+ ([[https://developers.cloudflare.com/fundamentals/api/get-started/][how
+ to find API keys]]):
+ - Email ="email"= and Global API Key ="key"=
+ - User service key ="user_service_key"=
+ - API Token ="token"=, configured with DNS edit permissions for your
+ DNS name's zone
+- Optional Parameters
+ - ="proxied"= can be set to =true= to use the proxy services of
+ Cloudflare
+ - ="ip_version"= can be =ipv4= (A records), or =ipv6= (AAAA records)
+ or =ipv4 or ipv6= (update one of the two, depending on the public
+ ip found). It defaults to =ipv4 or ipv6=.
+ - ="ipv6_suffix"= is the IPv6 interface identifier suffix to use. It
+ can be for example =0:0:0:0:72ad:8fbb:a54e:bedd/64=. If left empty,
+ it defaults to no suffix and the raw public IPv6 address obtained is
+ used in the record updating.
+
+#+begin_src conf
+{
+ "settings": [
+ {
+ "provider": "cloudflare",
+ "zone_identifier": "some id",
+ "domain": "domain.com",
+ "host": "@",
+ "ttl": 1,
+ "proxied": true,
+ "token": "yourtoken",
+ "ip_version": "ipv4",
+ "ipv6_suffix": ""
+ }
+ ]
+}
+#+end_src
+
+Once you have configured the provider of your choice, correct the file
+and directory permissions and ownership.
+
+#+begin_src sh
+cd ~/ddns_updater
+# Owned by user ID of Docker container (1000)
+chown -R 1000 data
+# all access (for creating json database file data/updates.json)
+chmod 700 data
+# read access only
+chmod 400 data/config.json
+#+end_src
+
+*** Docker Compose
+
+After creating the project structure, let's create the
+=docker-compose.yml= file.
+
+#+begin_src sh
+nano ~/ddns_-pdater/docker-compose.yml
+#+end_src
+
+#+begin_src config
+version: "3.7"
+services:
+ ddns-updater:
+ image: qmcgaw/ddns-updater
+ container_name: ddns-updater
+ network_mode: bridge
+ ports:
+ - 8097:8000/tcp # Change the 8097 value to whichever port you want to use
+ volumes:
+ - ./data:/updater/data
+ environment:
+ - CONFIG=
+ - PERIOD=5m
+ - UPDATE_COOLDOWN_PERIOD=5m
+ - PUBLICIP_FETCHERS=all
+ - PUBLICIP_HTTP_PROVIDERS=all
+ - PUBLICIPV4_HTTP_PROVIDERS=all
+ - PUBLICIPV6_HTTP_PROVIDERS=all
+ - PUBLICIP_DNS_PROVIDERS=all
+ - PUBLICIP_DNS_TIMEOUT=3s
+ - HTTP_TIMEOUT=10s
+
+ # Web UI
+ - LISTENING_ADDRESS=:8000
+ - ROOT_URL=/
+
+ # Backup
+ - BACKUP_PERIOD=0 # 0 to disable
+ - BACKUP_DIRECTORY=/updater/data
+
+ # Other
+ - LOG_LEVEL=info
+ - LOG_CALLER=hidden
+ - SHOUTRRR_ADDRESSES=
+ restart: always
+#+end_src
+
+After configuring your preferences in the =docker-compose.yml=, launch
+the container.
+
+#+begin_src sh
+cd ~/ddns-updater
+sudo docker-compose up -d
+#+end_src
+
+If you've launched this on your local machine, you can launch
+=localhost:8097= in your browser to see the results.
+
+*** Nginx Reverse Proxy
+
+If you launched this service on a server, other machine, or just want to
+access it remotely via a domain name, you can use Nginx as a reverse
+proxy to expose the service publicly.
+
+Start by creating the Nginx configuration file.
+
+#+begin_src sh
+sudo nano /etc/nginx/sites-available/ddns
+#+end_src
+
+Here's a basic example that should work properly.
+
+#+begin_src conf
+server {
+ # If using 443, remember to include your ssl_certificate
+ # and ssl_certificate_key
+ listen [::]:80;
+ listen 80;
+ server_name ddns.example.com;
+
+ location / {
+ set $upstream_ao http://127.0.0.1:9380;
+ proxy_pass $upstream_ao;
+
+ # May need some additional proxy_* parameters,
+ # see the full example below if necessary
+ }
+}
+#+end_src
+
+Here's a full example that uses my Authelia authentication service to
+require authentication before someone can access the web page.
+
+#+begin_src conf
+server {
+ if ($host ~ ^[^.]+\.example\.com$) {
+ return 301 https://$host$request_uri;
+ }
+
+ listen [::]:80;
+ listen 80;
+ server_name ddns.example.com;
+ return 404;
+}
+
+server {
+ listen [::]:443 ssl http2;
+ listen 443 ssl http2;
+ server_name ddns.example.com;
+ access_log /var/log/nginx/ddns.access.log;
+ error_log /var/log/nginx/ddns.error.log;
+
+ add_header X-Content-Type-Options "nosniff";
+ add_header X-XSS-Protection "1; mode=block";
+ add_header X-Frame-Options "DENY";
+ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
+ add_header Referrer-Policy "no-referrer";
+
+ ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+
+ location /authelia {
+ internal;
+ set $upstream_authelia http://127.0.0.1:9091/api/verify; #change the IP and Port to match the IP and Port of your Authelia container
+ proxy_pass_request_body off;
+ proxy_pass $upstream_authelia;
+ proxy_set_header Content-Length "";
+
+ # Timeout if the real server is dead
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
+ client_body_buffer_size 128k;
+ proxy_set_header Host $host;
+ proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-Host $http_host;
+ proxy_set_header X-Forwarded-Uri $request_uri;
+ proxy_set_header X-Forwarded-Ssl on;
+ proxy_redirect http:// $scheme://;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "";
+ proxy_cache_bypass $cookie_session;
+ proxy_no_cache $cookie_session;
+ proxy_buffers 4 32k;
+
+ send_timeout 5m;
+ proxy_read_timeout 240;
+ proxy_send_timeout 240;
+ proxy_connect_timeout 240;
+ }
+
+ location / {
+ set $upstream_ddns http://127.0.0.1:8097; #change ddns to match your container name: $upstream_some-container-name or $upstream_somecontainername
+ proxy_pass $upstream_ddns; #change ddns to match your container name: $upstream_some-container-name or $upstream_somecontainername
+
+ auth_request /authelia;
+ auth_request_set $target_url https://$http_host$request_uri;
+ auth_request_set $user $upstream_http_remote_user;
+ auth_request_set $email $upstream_http_remote_email;
+ auth_request_set $groups $upstream_http_remote_groups;
+ proxy_set_header Remote-User $user;
+ proxy_set_header Remote-Email $email;
+ proxy_set_header Remote-Groups $groups;
+
+ error_page 401 =302 https://auth.example.com/?rd=$target_url; #change this to match your authentication domain/subdomain
+
+ client_body_buffer_size 128k;
+
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
+
+ send_timeout 5m;
+ proxy_read_timeout 360;
+ proxy_send_timeout 360;
+ proxy_connect_timeout 360;
+
+ proxy_set_header Host $host;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection upgrade;
+ proxy_set_header Accept-Encoding gzip;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Forwarded-Host $http_host;
+ proxy_set_header X-Forwarded-Uri $request_uri;
+ proxy_set_header X-Forwarded-Ssl on;
+ proxy_redirect http:// $scheme://;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "";
+ proxy_cache_bypass $cookie_session;
+ proxy_no_cache $cookie_session;
+ proxy_buffers 64 256k;
+
+ # set_real_ip_from 192.168.1.0/16; #make sure this matches your network setup
+ # real_ip_header CF-Connecting-IP;
+ # real_ip_recursive on;
+ }
+}
+#+end_src
+
+When complete, simply link the file and restart the web server.
+
+#+begin_src sh
+sudo ln -s /etc/nginx/sites-available/ddns /etc/nginx/sites-enabled/ddns
+sudo systemctl restart nginx.service
+#+end_src
+
+Your ddns-updater service will now be available via =ddns.example.com=!