Skip to content

Open source · npm · macOS + Linux

Localhost,
but everywhere.

dynamoip gives your local services a real domain and trusted HTTPS. So app.yourdomain.com opens on your phone, anywhere on your LAN, or out on the public internet.

Same URL every time — it doesn't reset like ngrok. One flag flips it from your private LAN to the whole internet.

dynamoip is an open-source npm tool for macOS and Linux. It gives your local services real domain names with trusted HTTPS — accessible on your LAN or exposed to the public internet via Cloudflare Tunnel. No port forwarding. No firewall rules. Configure once, one command every time. Three modes: Quick (mDNS .local), Pro (Cloudflare DNS + Let's Encrypt, LAN only), Max (Cloudflare Tunnel, public internet).

$ npm install --save-dev dynamoip

WebSockets and HMR just work — Vite and Next.js Fast Refresh keep running on your phone, not just your laptop.

real domainstrusted HTTPSLAN or internetsame URL alwaysno port forwardingHMR / Fast Refresh worksrestarts itselfMIT · open sourcemacOS + Linux (Windows via Docker)

Before / after

Drag to compare.

Same dev server. Two very different lives. Drag the handle.

● Without dynamoipWith dynamoip ●

Dev server address

app.yourdomain.com

Same URL, every network.

Share it

Just send the link.

They bookmark it. Done.

Tunnel URL

app.yourdomain.com

Permanent. Never resets.

On your phone

Everything works

Trusted HTTPS on the device.

Comparison. Without dynamoip: your dev server is an IP address like 192.168.1.105:3000 that changes on every network, shared by asking for IPs, with ngrok URLs that reset every restart, and phone features blocked over HTTP. With dynamoip: a permanent domain like app.yourdomain.com that stays the same on every network, is shareable as a link, never resets, and works on your phone with trusted HTTPS.

/01

Who it's for.

Mostly one developer, one app, one real URL — but it scales up from there.

Developers

Your phone can't reach localhost.

Camera, geolocation, PWA installs, service workers — none of them work over plain HTTP, and none of them can see localhost from your phone anyway. dynamoip hands your dev server a real HTTPS URL that opens on any device. Set it up once, use the same URL every time.

“The camera API doesn’t work over HTTP. Neither does your PWA install prompt.”
Teams

Stop pasting IP addresses in Slack.

192.168.1.105:3000 isn’t a URL. dynamoip gives everyone on the network a real link — LAN-only, nothing leaves the office, no port forwarding, no VPN. Set it up once, share the same link every standup.

“What’s your local IP again?” — every standup, forever.
Home lab

Your own server shouldn't feel sketchy.

Home Assistant, Grafana, Plex, Jellyfin — give each one a real subdomain with trusted HTTPS. Bookmark them, open them from your phone, and never click through another browser warning about your own hardware.

“Your connection is not private.” — every browser, about your own server.
Remote access

Share your local app with anyone.

A webhook you’re testing, a client demo from your laptop, a staging build you want feedback on — Max mode gives you a real, permanent URL. Not a random ngrok subdomain that expires and breaks every webhook you registered.

“Can you send me a link?” — yeah, you can now.

/02

How it works.

Configure once. It just works every time after that.

01 —

Install

One command adds dynamoip as a dev dependency. It never runs in production — this is a tool for you, not your users.

npm i -D dynamoip

02 —

Configure

Drop in a config file, add your env vars, add one npm script. Five minutes, once — then you never touch it again. Add "tunnel": true when you want to go public.

03 —

Run

One command brings every domain live, on your LAN or the internet. If it crashes, it restarts itself with backoff and keeps your URLs up.

npm run dev:proxy

/03

Three modes.

From local dev to the public internet — one tool, one domain.

No tunnels on your LAN. Quick and Pro are pure local — your traffic never leaves your network. Tunnels only kick in when you go public with Max.
Max modeNew

Cloudflare
Tunnel

Your services, live on the public internet. No port forwarding, no firewall rules, no inbound ports. cloudflared installs itself, and you don't need sudo.

dynamoip.config.json
{
  "baseDomain": "acme.dev",
  "tunnel": true,
  "domains": { "app": 3000 }
}
cloudflared installs itself
app.acme.dev PUBLIC
No port forwarding
No firewall rules
Needs: a Cloudflare domain + an API token (Zone:DNS:Edit + Tunnel:Edit)
Pro mode

Cloudflare
+ Let's Encrypt

Your own domain, with Cloudflare DNS and a Let's Encrypt wildcard cert. Every device on your LAN trusts it out of the box — no CA to install on phones or tablets. LAN only. No tunnel.

dynamoip.config.json
{
  "baseDomain": "acme.dev",
  "domains": { "app": 3000 }
}
app.acme.dev LAN

Needs: a Cloudflare domain + an API token (Zone:DNS:Edit)

Quick mode

mDNS
.local

No domain, no accounts. Broadcasts .local hostnames over mDNS with a locally-trusted mkcert cert. The first time another device visits, it gets a one-tap trust page. LAN only. No tunnel.

dynamoip.config.json
{
  "domains": { "app": 3000 }
}
https://app.local

Needs: mkcert, sudo

Same URL, LAN or internet. app.yourdomain.com works in Pro (LAN) and Max (internet) — same address, nothing to reconfigure. Your URLs never reset.

/04

Quick start.

Configure once. One command every time after that.

— one-time setup · ~5 min —

01
Install

One command. It never runs in production.

npm install --save-dev dynamoip
02
Create dynamoip.config.json

Pick a mode. Expand to grab the config.

Max mode — public internetPublic internet
{
  "baseDomain": "yourdomain.com",
  "tunnel": true,
  "domains": {
    "app": 3000,
    "api": 4000
  }
}

Needs a Cloudflare API token with Zone:DNS:Edit + Account:Cloudflare Tunnel:Edit.

Pro mode — LAN, your domain
{
  "baseDomain": "yourdomain.com",
  "domains": {
    "app": 3000,
    "api": 4000
  }
}

Needs a Cloudflare API token with Zone:DNS:Edit. No tunnel — traffic stays on your LAN.

Quick mode — LAN, .local, zero accounts
{
  "domains": {
    "app": 3000
  }
}

No Cloudflare, no domain — just mkcert and mDNS. Your domains become app.local. LAN only, no tunnel.

03
Add a script to package.json

One line. This is the command you'll run from now on.

"scripts": {
  "dev:proxy": "dynamoip --config dynamoip.config.json"
}
04
Add credentials to .env

Pro and Max need these. Quick doesn't.

CF_API_TOKEN=your_cloudflare_api_token
CF_EMAIL=you@example.com   # Pro mode only

— then, every time —

Run
sudo npm run dev:proxy

Your domains are live in seconds. Same domain, every time, nothing to reconfigure.

Max runs without sudo — just npm run dev:proxy. Pro and Quick need it for ports 80/443, or pass --port 8443.

/05

Examples.

Runnable Docker projects. Clone one, run a command, done.

Docker · Max mode

Tunnel

Public internet

Two services live on the public internet through a Cloudflare Tunnel. No port forwarding. Runs on macOS, Linux, and Windows (via Docker).

inventory.yourdomain.comPUBLIC:3001
dashboard.yourdomain.comPUBLIC:6000
Docker · Pro mode

LAN

LAN only · no tunnel

Two services on your LAN with your real domain and a Let's Encrypt cert. No tunnel — traffic stays on your network.

inventory.yourdomain.comLAN:3001
dashboard.yourdomain.comLAN:6000
Docker · Quick mode

Local

.local · zero accounts

No Cloudflare account, no domain. .local hostnames plus mkcert. The simplest setup there is.

inventory.local:3001
dashboard.local:6000