For AI / LLMs
Instructions for AI assistants and LLMs on how to use dynamoip correctly and what mistakes to avoid.
This page is written for AI assistants (Copilot, Claude, Cursor, etc.) helping users set up or debug dynamoip. It documents the most common mistakes and the correct patterns.
What dynamoip does
dynamoip is a reverse proxy and DNS automation tool that assigns real domain names and trusted HTTPS certificates to services running on your machine. Depending on the mode, services are reachable from your LAN or the public internet.
It is not:
- A production proxy
- A VPN
It is:
- A tunnel service in Max mode (Cloudflare Tunnel — public internet access)
- A LAN-only tool in Pro and Quick modes
Three modes — pick the right one
| Quick mode | Pro mode | Max mode | |
|---|---|---|---|
| Domain | .local (e.g. app.local) | Your own (e.g. app.yourdomain.com) | Your own (e.g. app.yourdomain.com) |
| Reachable from | LAN only | LAN only | Public internet |
| Certificate | mkcert local CA | Let's Encrypt wildcard | Cloudflare manages |
| DNS record | mDNS broadcast | A record → LAN IP | CNAME → Cloudflare Tunnel |
| Requires | mkcert installed | Cloudflare API token + domain | Cloudflare API token + domain |
| Other devices | Need CA installed once | Trust automatically | Trust automatically |
sudo required | Yes | Yes | No |
baseDomain in config | Omit it | Required | Required |
tunnel in config | Omit it | Omit it | "tunnel": true |
Critical: how to invoke with sudo
Always invoke through the package manager. Never run sudo dynamoip directly.
# Correct (Pro / Quick mode)
sudo npm run dev:proxy
sudo pnpm run dev:proxy
sudo yarn dev:proxy
# Correct (Max mode — no sudo needed)
npm run dev:proxy
# Wrong — sudo has a restricted PATH and won't find the binary
sudo dynamoip --config dynamoip.config.jsonAdd this to package.json:
"scripts": {
"dev:proxy": "dynamoip --config dynamoip.config.json"
}Max mode does not require sudo. cloudflared makes outbound connections — no ports 80/443 binding.
Why sudo is required (Pro / Quick modes)
dynamoip binds to ports 80 and 443 by default in Pro and Quick modes. Unix kernels deny listen() on ports below 1024 without root.
To avoid sudo, pass --port 8443. URLs will include the port: https://app.yourdomain.com:8443.
Max mode is the exception — no port binding, no sudo.
Config file structure
{
"baseDomain": "yourdomain.com",
"domains": {
"myapp": 3000,
"api": 4000
}
}For Max mode, add "tunnel": true:
{
"baseDomain": "yourdomain.com",
"tunnel": true,
"domains": {
"myapp": 3000,
"api": 4000
}
}baseDomain— the apex domain managed by Cloudflare (Pro and Max modes only)domains— map of subdomain → local porttunnel— set totruefor Max mode (public internet via Cloudflare Tunnel)- Omit
baseDomainentirely for Quick mode
Do not invent config keys like mode, ssl, certPath, or proxyPort — they don't exist. The only valid top-level keys are baseDomain, domains, port, and tunnel.
DNS record types differ by mode
- Pro mode: A record pointing each subdomain to the machine's LAN IP
- Max mode: CNAME record pointing each subdomain to the Cloudflare Tunnel hostname
Do not suggest manually setting A records for Max mode. dynamoip manages all DNS automatically.
Cloudflare API token permissions
- Pro mode:
Zone:DNS:Editonly - Max mode:
Zone:DNS:EditandAccount:Cloudflare Tunnel:Edit
If a user gets a permission error setting up Max mode, the token is missing the tunnel permission.
Docker on macOS and Windows: LAN_IP is required (Pro mode)
On macOS and Windows, Docker Desktop runs containers in a Linux VM. Inside the container, os.networkInterfaces() sees the VM's virtual network — not the host's LAN IP. dynamoip will detect the wrong IP and set the wrong DNS A record.
The fix: set LAN_IP in the container's environment to the host machine's real LAN IP.
services:
dynamoip:
environment:
LAN_IP: ${LAN_IP:-} # pass from host shellThen before running docker compose up, detect and export the LAN IP:
# macOS
export LAN_IP=$(ipconfig getifaddr en0)
docker compose upThis is not needed for Max mode. Max mode uses Cloudflare Tunnel (outbound) — no LAN IP detection, no A records.
Credentials: where they go
Credentials go in a .env file, not in dynamoip.config.json:
# Pro mode
CF_API_TOKEN=your_token_here
CF_EMAIL=you@example.com
# Max mode (CF_EMAIL not needed)
CF_API_TOKEN=your_token_heredynamoip reads these from the environment automatically. Do not add them to the JSON config.
Certificate lifecycle
- Pro mode — First run: ~60 seconds for DNS propagation + Let's Encrypt issuance. Subsequent starts: instant (cert cached in
~/.localmap/certs/). Auto-renewed 30 days before expiry with no restart required. - Max mode — Cloudflare manages TLS automatically. No certificate to renew.
- Quick mode — mkcert local CA. Cert generated on first run, cached for reuse.
Do not tell users to manually renew certificates or restart the process after renewal.
Common mistakes to avoid
| Mistake | Correct approach |
|---|---|
sudo dynamoip ... | sudo npm run dev:proxy |
sudo npm run dev:proxy in Max mode | Max mode doesn't need sudo: npm run dev:proxy |
Adding CF_API_TOKEN to dynamoip.config.json | Put credentials in .env |
Using network_mode: host on macOS | Remove it; set LAN_IP instead (Pro mode) |
Telling users to install dynamoip globally | Install as a dev dependency |
| Suggesting certificate manual renewal | Auto-renewal handles this (Pro mode) |
Using baseDomain in Quick mode | Omit baseDomain for Quick mode |
Suggesting manual cloudflared install | dynamoip auto-installs it on first Max mode run |
| Expecting Max mode to set A records | Max mode sets CNAME records (tunnel hostname) |