Commit ef6048e9e5

ef6048e9e5520b926193b54d191b22ee32e7ebad

parent: f6c6355ea9

Unsigned

cmc <hello@cleberg.net> · 2024-03-15 14:59 UTC

add ddns-updater post

Layout: unified · split

content/blog/2024-03-15-self-hosting-ddns-updater.md added +284
@@ -0,0 +1,284 @@
1+++
2date = 2024-03-15T14:49:59+00:00
3title = "Self-Hosting DDNS Updater"
4description = "A guide to self-hosting the DDNS Updater container."
5+++
6
7![DDNS Updater Web View](https://img.cleberg.net/blog/20240315-ddns-updater/ddns.png)
8
9[DDNS Updater](https://github.com/qdm12/ddns-updater) is a program to keep DNS A and/or AAAA records updated for multiple DNS providers.
10
11If 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.
12
13Luckily, DDNS Upater fits both of these preferences.
14
15## Installation
16
17To get started, always make sure to review the project's [README](https://github.com/qdm12/ddns-updater/blob/master/README.md). I'll be documenting my steps below, but they may have changed by the time you read this.
18
19The first step is to set up the directories and files required for the project.
20
21```sh
22mkdir ~/ddns-updater
23mkdir ~/ddns-updater/data
24touch ~/ddns-updater/data/config.json
25```
26
27### Configuration
28
29The 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.
30
31```sh
32nano ~/ddns-updater/data/config.json
33```
34
35When setting up the configuration for Cloudflare, you'll need the following:
36
37- Required Parameters
38 - `"zone_identifier"` is the Zone ID of your site from the domain overview page
39 - `"host"` is your host and can be `"@"`, a subdomain or the wildcard `"*"`. See [this issue comment for context](https://github.com/qdm12/ddns-updater/issues/243#issuecomment-928313949).
40 - `"ttl"` integer value for record TTL in seconds (specify 1 for automatic)
41 - One of the following ([how to find API keys](https://developers.cloudflare.com/fundamentals/api/get-started/)):
42 - Email `"email"` and Global API Key `"key"`
43 - User service key `"user_service_key"`
44 - API Token `"token"`, configured with DNS edit permissions for your DNS name's zone
45- Optional Parameters
46 - `"proxied"` can be set to `true` to use the proxy services of Cloudflare
47 - `"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`.
48 - `"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.
49
50```conf
51{
52 "settings": [
53 {
54 "provider": "cloudflare",
55 "zone_identifier": "some id",
56 "domain": "domain.com",
57 "host": "@",
58 "ttl": 1,
59 "proxied": true,
60 "token": "yourtoken",
61 "ip_version": "ipv4",
62 "ipv6_suffix": ""
63 }
64 ]
65}
66```
67
68Once you have configured the provider of your choice, correct the file and directory permissions and ownership.
69
70```sh
71cd ~/ddns_updater
72# Owned by user ID of Docker container (1000)
73chown -R 1000 data
74# all access (for creating json database file data/updates.json)
75chmod 700 data
76# read access only
77chmod 400 data/config.json
78```
79
80### Docker Compose
81
82After creating the project structure, let's create the `docker-compose.yml` file.
83
84```sh
85nano ~/ddns_-pdater/docker-compose.yml
86```
87
88```config
89version: "3.7"
90services:
91 ddns-updater:
92 image: qmcgaw/ddns-updater
93 container_name: ddns-updater
94 network_mode: bridge
95 ports:
96 - 8097:8000/tcp # Change the 8097 value to whichever port you want to use
97 volumes:
98 - ./data:/updater/data
99 environment:
100 - CONFIG=
101 - PERIOD=5m
102 - UPDATE_COOLDOWN_PERIOD=5m
103 - PUBLICIP_FETCHERS=all
104 - PUBLICIP_HTTP_PROVIDERS=all
105 - PUBLICIPV4_HTTP_PROVIDERS=all
106 - PUBLICIPV6_HTTP_PROVIDERS=all
107 - PUBLICIP_DNS_PROVIDERS=all
108 - PUBLICIP_DNS_TIMEOUT=3s
109 - HTTP_TIMEOUT=10s
110
111 # Web UI
112 - LISTENING_ADDRESS=:8000
113 - ROOT_URL=/
114
115 # Backup
116 - BACKUP_PERIOD=0 # 0 to disable
117 - BACKUP_DIRECTORY=/updater/data
118
119 # Other
120 - LOG_LEVEL=info
121 - LOG_CALLER=hidden
122 - SHOUTRRR_ADDRESSES=
123 restart: always
124```
125
126After configuring your preferences in the `docker-compose.yml`, launch the container.
127
128```sh
129cd ~/ddns-updater
130sudo docker-compose up -d
131```
132
133If you've launched this on your local machine, you can launch `localhost:8097` in your browser to see the results.
134
135### Nginx Reverse Proxy
136
137If 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.
138
139Start by creating the Nginx configuration file.
140
141```sh
142sudo nano /etc/nginx/sites-available/ddns
143```
144
145Here's a basic example that should work properly.
146
147```conf
148server {
149 # If using 443, remember to include your ssl_certificate
150 # and ssl_certificate_key
151 listen [::]:80;
152 listen 80;
153 server_name ddns.example.com;
154
155 location / {
156 set $upstream_ao http://127.0.0.1:9380;
157 proxy_pass $upstream_ao;
158
159 # May need some additional proxy_* parameters,
160 # see the full example below if necessary
161 }
162}
163```
164
165Here's a full example that uses my Authelia authentication service to require authentication before someone can access the web page.
166
167```conf
168server {
169 if ($host ~ ^[^.]+\.example\.com$) {
170 return 301 https://$host$request_uri;
171 }
172
173 listen [::]:80;
174 listen 80;
175 server_name ddns.example.com;
176 return 404;
177}
178
179server {
180 listen [::]:443 ssl http2;
181 listen 443 ssl http2;
182 server_name ddns.example.com;
183 access_log /var/log/nginx/ddns.access.log;
184 error_log /var/log/nginx/ddns.error.log;
185
186 add_header X-Content-Type-Options "nosniff";
187 add_header X-XSS-Protection "1; mode=block";
188 add_header X-Frame-Options "DENY";
189 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
190 add_header Referrer-Policy "no-referrer";
191
192 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
193 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
194 include /etc/letsencrypt/options-ssl-nginx.conf;
195 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
196
197 location /authelia {
198 internal;
199 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
200 proxy_pass_request_body off;
201 proxy_pass $upstream_authelia;
202 proxy_set_header Content-Length "";
203
204 # Timeout if the real server is dead
205 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
206 client_body_buffer_size 128k;
207 proxy_set_header Host $host;
208 proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
209 proxy_set_header X-Real-IP $remote_addr;
210 proxy_set_header X-Forwarded-For $remote_addr;
211 proxy_set_header X-Forwarded-Proto $scheme;
212 proxy_set_header X-Forwarded-Host $http_host;
213 proxy_set_header X-Forwarded-Uri $request_uri;
214 proxy_set_header X-Forwarded-Ssl on;
215 proxy_redirect http:// $scheme://;
216 proxy_http_version 1.1;
217 proxy_set_header Connection "";
218 proxy_cache_bypass $cookie_session;
219 proxy_no_cache $cookie_session;
220 proxy_buffers 4 32k;
221
222 send_timeout 5m;
223 proxy_read_timeout 240;
224 proxy_send_timeout 240;
225 proxy_connect_timeout 240;
226 }
227
228 location / {
229 set $upstream_ddns http://127.0.0.1:8097; #change ddns to match your container name: $upstream_some-container-name or $upstream_somecontainername
230 proxy_pass $upstream_ddns; #change ddns to match your container name: $upstream_some-container-name or $upstream_somecontainername
231
232 auth_request /authelia;
233 auth_request_set $target_url https://$http_host$request_uri;
234 auth_request_set $user $upstream_http_remote_user;
235 auth_request_set $email $upstream_http_remote_email;
236 auth_request_set $groups $upstream_http_remote_groups;
237 proxy_set_header Remote-User $user;
238 proxy_set_header Remote-Email $email;
239 proxy_set_header Remote-Groups $groups;
240
241 error_page 401 =302 https://auth.example.com/?rd=$target_url; #change this to match your authentication domain/subdomain
242
243 client_body_buffer_size 128k;
244
245 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
246
247 send_timeout 5m;
248 proxy_read_timeout 360;
249 proxy_send_timeout 360;
250 proxy_connect_timeout 360;
251
252 proxy_set_header Host $host;
253 proxy_set_header Upgrade $http_upgrade;
254 proxy_set_header Connection upgrade;
255 proxy_set_header Accept-Encoding gzip;
256 proxy_set_header X-Real-IP $remote_addr;
257 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
258 proxy_set_header X-Forwarded-Proto $scheme;
259 proxy_set_header X-Forwarded-Host $http_host;
260 proxy_set_header X-Forwarded-Uri $request_uri;
261 proxy_set_header X-Forwarded-Ssl on;
262 proxy_redirect http:// $scheme://;
263 proxy_http_version 1.1;
264 proxy_set_header Connection "";
265 proxy_cache_bypass $cookie_session;
266 proxy_no_cache $cookie_session;
267 proxy_buffers 64 256k;
268
269 # set_real_ip_from 192.168.1.0/16; #make sure this matches your network setup
270 # real_ip_header CF-Connecting-IP;
271 # real_ip_recursive on;
272 }
273}
274```
275
276When complete, simply link the file and restart the web server.
277
278```sh
279sudo ln -s /etc/nginx/sites-available/ddns /etc/nginx/sites-enabled/ddns
280sudo systemctl restart nginx.service
281```
282
283Your ddns-updater service will now be available via `ddns.example.com`!
284