Go to file
m5r ccaef7827c
update website ip, it's not using a shared IPv4
2024-01-03 01:36:16 +01:00
certs housekeeping 2023-12-12 22:25:39 +01:00
http add proper content type to force the browser to download the files instead of rendering their content 2023-12-12 23:33:14 +01:00
xip update website ip, it's not using a shared IPv4 2024-01-03 01:36:16 +01:00
.dockerignore first iteration to automate certificate generation 2023-02-26 11:02:30 +01:00
.gitignore untrack .lego directory 2023-12-13 23:11:26 +01:00
Dockerfile housekeeping 2023-12-12 22:25:39 +01:00
LICENSE Initial commit 2022-10-27 23:19:23 +02:00
README.md write up readme 2023-12-14 01:07:15 +01:00
fly.toml always have 1 machine running 2023-12-12 22:26:45 +01:00
go.mod housekeeping 2023-12-12 22:25:39 +01:00
go.sum housekeeping 2023-12-12 22:25:39 +01:00
main.go cleanup 2023-12-13 22:27:51 +01:00



local-ip.sh is a magic domain name that provides wildcard DNS for any IP address.
It is heavily inspired by local-ip.co, sslip.io, and xip.io


go run ./main.go # binds to :53 by default but you can override it by using the `-port` parameter

dig @localhost 10-0-1-29.my.local-ip.sh +short
dig @localhost app.10-0-1-29.my.local-ip.sh +short
dig @localhost foo.bar. +short
dig @localhost +short

How it works

local-ip.sh packs up:

  • an authoritative DNS server that answers queries for the zone local-ip.sh
  • a Let's Encrypt client that takes care of obtaining and renewing the wildcard certificate for *.local-ip.sh using the DNS-01 challenge
  • an HTTP server that serves the certificate files

It answers queries with the IPv4 address it may find in the subdomain by pattern matching the FQDN.
It registers an account to Let's Encrypt's ACME server to obtain the wildcard certificate on the first run and then renew it about a month before it expires. The account file and the associated key used to request a certificate under the .lego directory but the certificate's files are stored in /certs at the root of the filesystem. I've done it this way to mount a persistent storage volume there and keep the files between deployments without tracking them in git but feel free to change this behavior in certs/certs.go and in http/server.go if you're planning to self-host it.

The certificate files are served by an HTTP server on the arbitrary port :9229 that is intentionally not exposed to the internet. The website is connected to the same private network as the service and serves as a proxy to access the files securely.


I'm currently hosting local-ip.sh at Fly.io but you can host the service yourself if you're into that kind of thing. Note that you will need to edit your domain's glue records so make sure your registrar allows it.

You will essentially need to:

  • replace any occurrence of local-ip.sh in .go files with your domain
  • replace the hardcoded IP addresses in the hardcodedRecords map declared in xip.go:37, the important records to keep are:
    • A ns.local-ip.sh. holds both IP addresses pointing to ns1. and ns2.
    • A ns1.local-ip.sh. holds the first IP address pointing to the server hosting local-ip.sh
    • A ns2.local-ip.sh. holds the second IP address pointing to the server, exists for redundancy
    • TXT _acme-challenge.local-ip.sh. will temporarily hold the value to solve the DNS-01 challenge
  • set your domain's glue records to point to the IP addresses you set for ns1. and ns2.
  • retrieve the certificate files once the program is up and running