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",
});
2.0.0
in this repo)master
v2.0.0
Go on Docker Hub, update the tag name, save, and use the "Trigger" button: