# d5— The DIY Dynamic DNS *The simple, Unix-philosophy tool to retrieve your home network's IP address remotely* If you want to know the IP address of the computer you're *currently* using, there are [a](https://github.com/georgyo/ifconfig.io) huge [number](https://github.com/mehulved/ifconfig.me/blob/master/ifconfig.me) of [different](https://github.com/pmarques/ifconfig.me) tools [available](https://github.com/missdeer/ifconfig). If, however, you want to know the IP address of some *other* computer—say, you want to know the IP address of your home computer while you're traveling—your options are much more limited. That's where d5 comes in. With d5, you set a simple script on your home computer to update the IP address associated with a username—password pair. Once that's done, you can access the current value of that IP address from anywhere in the world, using that same username–password pair. This is a simple problem: you want to know a single IP address. Such a simple problem should have a simple solution. d5 is that simple solution. ## Example Usage If you want to use the public d5 server I host, you could run a cron job to send a POST command to d5. For example, use the following cron job on your home computer (replacing `USER` and `PASSWORD` with your actual values, of course): ```shell */5 * * * * curl -u USERNAME:PASSWORD https://d5.codesections.com -X POST ``` You can substitute any other timing method (systemd timers, emacs timers, runwhen scripts, etc). The only important point is that it run the `curl -u USERNAME:PASSWORD https://d5.codesections.com -X POST` command on a regular schedule. Once you've done that, you can access the most recently updated IP address with the following curl command: ```shell curl -u USERNAME:PASSWORD https://d5.codesections.com` ``` If you want to automate the process of using d5, it is simple to do so with shell scripts/aliases. For example, I use the following Bash alias: ```shell alias ssh-home='ssh $(curl $USER https://d5.codesections.com) -p $SSH_PUBLIC_PORT ``` (Omitting the `:PASSWORD` portion from the alias causes curl to prompt me for the password on each use. If you don't want the security/hassle of being prompted for your password, you could store the password as plain text or using your preferred credential storage method.) If you would like to delete a previously stored IP address, you can do so by sending a DELETE command to d5: ```shell curl -u USERNAME:PASSWORD https://d5.codesections.com -X DELETE ``` If you are happy using the public d5 server at d5.codesections.com, then this is all you need to know. If you would like to self-host d5, then read on. ## Self-hosting d5 If you prefer not to use the d5.codesections.com server, you can also host d5 yourself. (Of course, you will need to host d5 somewhere you can access remotely.) ### Installing d5 Because d5 is distributed as a statically linked binary, installing it on any x86 Linux distribution is as simple as downloading the latest release and making it executable (`chmod +x ./d5`). d5 is designed to run in server environments, and thus does not currently provide binaries for macOS, Windows, or ARM (e.g., Raspberry Pi) computers. If you would like a precompiled binary for one of those platforms, please open an issue. In the meantime, you can build d5 from source using Cargo, the Rust package manager. ### Configuring and Running d5 Run d5 by invoking it from the command line (`./d5`). You can configure it using environmental variables; d5 currently supports the following variables: * `PORT`: the port on which to run d5 (if unspecified, defaults to `3030`) * `HOST`: the host address on which to run d5 (if unspecified, defaults to `127.0.0.1`). `HOST` may be specified as an IPv4 address or a string (e.g., `localhost`). * `KEY`: If set, enables **single-user mode**, described below, and sets the `username:password` key for single-user mode. By default, d5 is in **multi-user mode**. In this mode, d5 allows anyone to store IP addresses and retrieve them with the associated username–password pair. If you provide a `KEY` environmental variable, d5 will run in **single-user mode**, and will *only* allow a single IP address to be stored with the username–password pair provided via the `KEY` environmental variable. When setting the `KEY` variable, you must provide the username and password in the same format curl uses: separated by a colon (`username:password`). ### Using d5 with a Reverse Proxy (e.g., Nginx) Although you *could* directly expose d5 to the public Internet, a more common deployment strategy would be to place d5 behind a reverse proxy, such as [Nginx](https://www.nginx.com/) or [Traefik](https://traefik.io/). If you do so, you will need to configure your reverse proxy to forward on the incoming IP address using either the `remote_addr` or `x-forwarded-for` header. (d5 reads these headers to learn the relevant IP address.) For example, the following is a minimal Nginx configuration block for a server located at d5.codesections.com ```nginx server { server_name d5.codesections.com; location / { proxy_pass http://localhost:3030; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ``` Depending on your desired security, you will almost certainly want to set up https (e.g., with LetsEncrypt) and may additionally want to set rate limits. ## Using the IP Address Returned by d5 As mentioned above, d5's *primary* use case is returning a computer's current IP address to provide a target for `ssh` or similar commands. However, in the long tradition of Unix tools, d5 provides simple, machine- and human-readable output and can be easily combined with other tools to solve more complex problems. For example, if you want a *full* dynamic DNS solution (rather than a DIY version), you can pass the new IP address to [DNS Lexicon](https://github.com/AnalogJ/lexicon) and let it handle updating the DNS record associated with a particular URL. ## Goals d5 aspires to be: * **simple/minimalist** — d5 is solving a simple problem: you don't know the IP address of a computer and would like to. This should not be hard. d5's source code is currently a single file with 73 lines of code; I can't think of any reason it should ever exceed 100 lines of code. * **lightweight** — consistent with the above, d5 should not use many CPU cycles or much RAM to solve such a simple problem. * **private and reasonably secure** — d5 should never log IP or user information and, to the extent that it does not detract from the first two goals, should be as secure as practicable. ## Non-Goals d5 is *not* attempting to: * provide information *other than* IP address (useragent, etc.). Use [ifconfig.me](https://ifconfig.me/) instead. * provide a full (non-DIY) dynamic DNS solution. Use [DDclient](https://sourceforge.net/p/ddclient/wiki/Home/) or [duckdns](https://www.duckdns.org/)/a similar service instead. (Or use d5 + DNS Lexicon, as described above.) ## FAQ #### Why should I use d5 instead of a full dynamic DNS solution like DDclient? Maybe you shouldn't! DDclient/similar software does two things: 1) it monitors your current IP address and 2) it updates DNS settings to point a human-readable URL to the new address. If you need both of these features—that is, if you want a human-readable URL set dynamically—then it *might* make sense to use DDclient. (Though I think there's still a Unix-philosophy/ separation of concerns case to be made for splitting the two tasks into separate programs and using d5 + DNS Lexicon.) But, many times, you *don't* need a true dynamic DNS with a human-readable URL—you just need a way to connect to a computer regardless of its changing IP address. If you don't need that extra functionality, then taking on the code complexity of something like DDclient is excessive. For example, DDclient is over 4,000 lines of Perl; d5 is under 100 lines of Rust code. 4,000 lines of code provides a much larger surface area for bugs. #### Why should I use d5 instead of DuckDNS or a similar service? Privacy and control. I have nothing against DuckDNS or any service like it—DuckDNS's [privacy policy](https://www.duckdns.org/pp.jsp) seems pretty decent, as far as such things go. But they have a privacy policy because they *do* collect personal data—they have to, to provide the service they do. d5 does not store your data in any way and, if you don't trust the version running at d5.codesections.com, you can easily self-host your own copy. #### Why should I use d5 instead of self-hosting [ifconfig.io](https://github.com/georgyo/ifconfig.io) or something similar? Simplicity. Tools like ifconfg do both too much and too little. They do too much in that they provide a large amount of information in addition to IP address; you don't need this information to connect remotely, and collecting it just makes the code more complicated. They do too little in that they tell you about the IP address of the *current* computer and don't let you retrieve the IP address of a different computer. This means that, when using ifconfig, you need to *first* retrieve the IP address for your computer and *then* find a way to send that IP address elsewhere. This involves multiple round-trips and more complexity than is justified by the simple task. #### Can I use d5 without curl? Of course—d5 exposes a very simple HTTP API, and curl is just one way to consume that API. If you would prefer to use a different tool to make an HTTP request, you can convert the example curl commands to your tool of choice at [curl.trillworks.com](https://curl.trillworks.com). #### How secure is d5? d5 provides decent security, but not excellent. d5 does not store IP address or username–password pairs on disk and thus a compromise of d5 servers cannot leak any of that data. However, because d5 uses [basic authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#Basic_authentication_scheme), username–password pairs are transmitted in plain text (aside from the encryption provided by HTTPS). Thus, anyone who *thoroughly* compromised a d5 server would be in a position to intercept IP addresses and username–password pairs. Additionally, d5 does not itself implement rate limiting (though it's easy to so at the reverse proxy level). This means that, depending on proxy configuration, weak username–password pairs could be vulnerable to brute forcing. #### Shouldn't d5 store IP addresses in a database like Postgres or Redis rather than keeping them in memory? No. One of d5's primary goals is to be as simple as possible and relying on a separate database would be the exact opposite of "simple". #### Ok, but shouldn't d5 at least store IP addresses in a text file? Keeping them in memory just seems … fragile. That was my first thought too (and the [initial implementation](https://github.com/codesections/d5/commit/ded0019d67e9a1e2dd5d5c18a06233cae784c56a) for d5), but two considerations changed my mind. First, storing the passwords would both require hashing them (increasing complexity) and would create the possibility of an attacker gaining access to the hashed passwords (decreasing security). Second, and more importantly, I realized that persisting the IP addresses is unnecessary. The normal reason to persist data to the hard drive is to prevent data loss in the case of a program crash or shutdown. But the entire idea behind d5 is that the IP address is constantly subject to change and is being updated every few minutes. So, if d5 crashes, no meaningful data is lost—within 5 minutes, all IP addresses will be added back to the system. #### Is it really fair to call d5 "DIY Dynamic DNS"? It doesn't create any DNS entries. That's a fair point, and what I am attempting to get at by calling it "DIY". If you want to call it "self-hosted remote IP address retrieval", I won't argue with you. But that doesn't roll off the tongue quite as well. #### Why the name d5? I notice that "DIY Dynamic DNS" only has three Ds. Well, mostly because I want to avoid name collision with [d3.js](https://d3js.org/), the JavaScript data-visualization library. But if the two missing Ds bother you, you can think of this project as "Daniel's DIY Dynamic DNS for Dimwits" (with the "for Dimwits" part referring to the obsessive focus on simplicity).