DynDNS server with built-in Let's Encrypt certificate management
2.0K
An alley-oop is:
Say you're running some data logger, IoT device or home automation gateway on your LAN. You want it to be reachable over HTTPS or WSS (WebSocket Secure) because:
The major release 2.0.0 of alley-oop now supports ACMEv2/RFC 8555 with dns-01 challenge. dns-01 challenge has to be used to get certificates for private IPs. ACMEv1 is being deprecated and should not be used anymore.

alley-oop API with a domain name and IP pair, e.g. my-app.lan.example.com and 192.168.1.123. The API is HTTPS-only, and requires authentication.https://my-app.lan.example.com, its DNS resolver first goes to the DNS provider of your apex domain (example.com), e.g. Gandi, Hover, Route 53, etc.lan.example.com is managed by your alley-oop instance.alley-oop resolves the query for my-app.lan.example.com to the LAN address 192.168.1.123.https://my-app.lan.example.com.This section describes getting a working demo set up. It uses example.com as the domain, but you should obviously substitute that for your own domain when going through the setup process.
This example will be creating a DigitalOcean droplet. You can of course skip this step if you already have a server you can use, or do something similar on another VPS host (e.g. Amazon EC2).
Create a new droplet
Select Docker from One-click apps, for example:

Even the cheapest droplet is plenty enough:

Make sure your SSH will be added to the machine
Choose a hostname, e.g. alley-oop
Create the droplet, and wait for it to be provisioned
Now, we need to make the host accessible via a domain name. Using your DNS provider of choice (e.g. Gandi, Hover, Route 53, etc):
Create a DNS record that points to the server you just created in the previous step:
Name: alley-oop.example.com
Type: A
Value: <IP address of the server>
TTL: 300
Then, we need another record for our DNS server itself:
Name: lan.example.com.
Type: NS
Value: alley-oop.example.com
TTL: 300
Note that it might be tempting to have the A record name also be lan.example.com, but due to DNS zone cuts, it's not possible.
We need to run a few commands on the host to make sure it can act as a DNS server. Feel free to adapt these to your particulars if you're running on a different distro, for example.
So SSH over, switch to root, and:
Open up standard HTTP(S) & DNS ports on the firewall:
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 53/tcp
ufw allow 53/udp
Disable the local DNS server, so it doesn't conflict with our new DNS server (i.e. alley-oop):
systemctl stop systemd-resolved.service
systemctl disable systemd-resolved.service
Use Google's DNS for local name resolution (or any other DNS host you prefer):
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
alley-oop serverFinally, we need to configure and run alley-oop itself.
Using your favorite text editor (e.g. vim), create a file called alley-oop.cfg and update it to:
[auth]
username = "alley-oop"
password = "password"
[dns]
domain = "lan.example.com"
nsadmin = "admin.alley-oop.example.com"
nameservers = ["alley-oop.example.com"]
recordttl = 300
[db]
directory = "/var/lib/alley-oop"
Please change the password to be a secret known only to you. Seriously.
Now we're ready to pull and start the server itself:
$ docker run --name alley-oop -d \
-p 80:80 -p 443:443 -p 53:53/tcp -p 53:53/udp \
-v "$(pwd)/alley-oop.cfg:/etc/alley-oop/config.cfg" \
futurice/alley-oop:2.0.0
...
$ docker logs -f alley-oop
Starting alley-oop v2.0.0
Starting server at http://localhost:443
Starting DNS server at localhost:53
Starting server at http://localhost:80
^C
To check that the server is responding over the network, at the correct address, and with a valid certificate of its own, try:
$ curl https://alley-oop.example.com/
alley-oop v2.0.0
This repository ships with a demo client, which you can use to verify your server works as expected. Assuming you have a local IP address of 10.6.3.8:
$ cd demo
$ npm install
...
$ export DOMAIN_NAME=lan.example.com
$ export SERVER_NAME=alley-oop.example.com
$ export SERVER_PASSWORD=password
$ npm start
Current configuration is:
{ DOMAIN_NAME: 'lan.example.com',
SERVER_NAME: 'alley-oop.example.com',
SERVER_USERNAME: 'alley-oop',
SERVER_PASSWORD: 'password',
HTTP_PORT: 1080,
HTTPS_PORT: 10443 }
Fetching https://alley-oop.example.com/v1/update?hostname=10-6-3-8.lan.example.com&myip=10.6.3.8
Server started! Try any of the following endpoints:
* http://10-6-3-8.lan.example.com:1080/
* https://10-6-3-8.lan.example.com:10443/
* ws://10-6-3-8.lan.example.com:1080/ws (test with http://www.websocket.org/echo.html)
* wss://10-6-3-8.lan.example.com:10443/ws (test with https://www.websocket.org/echo.html)
Fetching https://alley-oop.example.com/v1/privatekey?hostname=10-6-3-8.lan.example.com
Fetching https://alley-oop.example.com/v1/certificate?hostname=10-6-3-8.lan.example.com
While the server is running, you – and importantly, anyone else on the same network – should be greeted with a friendly, green padlock:

The demo client will register a DNS name for each private IP address available on your local interfaces. In practice, you'd more likely register a DNS entry with a more readable (and stable) name, like my-app.lan.example.com. The demo client can easily be adapted for that; for example:
startServer({
"my-app.lan.example.com": "192.168.1.123",
});
Ensure all docs have consistent example version (i.e. find & replace 2.0.0 in this repo)
Make sure all changes are pushed to GitHub master
Go on GitHub and draft a new release with the format v2.0.0
Go on Docker Hub, update the tag name, save, and use the "Trigger" button:

Content type
Image
Digest
Size
8.4 MB
Last updated
over 6 years ago
docker pull futurice/alley-oop