Changelog
All notable changes to dynamoip.
The format follows Keep a Changelog. dynamoip uses semantic versioning.
[1.0.7] — 2026-05-19
Changed
- Full TypeScript migration: all source (
src/,bin/) rewritten to TypeScript — no behavioural changes, a pure type-safety upgrade for contributors. - New build toolchain: direct Node execution replaced by tsdown (Rolldown-backed). Published output is
dist/dynamoip.cjswith a sourcemap. - Minimum Node.js bumped to 18+: Node 14 and 16 are end-of-life.
- Async DNS in the ACME module:
dns.Resolverreplaced withdns.promises.Resolver.
Added
- 73-test Vitest suite covering config parsing, proxy routing, Cloudflare API helpers, ACME cert logic, tunnel config generation, mDNS cleanup, and LAN IP detection.
npm run typecheck— runstsc --noEmitfor type-only validation without a build.src/types.ts— shared interfaces (DomainEntry,Config,CloudflareConfig,SslOptions) used across all modules.- Smaller npm package — only
dist/is shipped;src/,bin/, and tests are excluded.
Fixed
- Wrong
binextension:package.jsonpointed atdynamoip.js; corrected todist/dynamoip.cjsafter the tsdown build.
[1.0.6] — 2026-04-04
Fixed
- Proxy crash on WebSocket errors:
http-proxypasses a rawnet.Socket(nothttp.ServerResponse) as the third argument when a WebSocket proxy error occurs. The error handler was callingres.writeHead()on the socket, crashing the entire process. The handler now detects this and callssocket.destroy()instead. - WebSocket HMR not working through proxy:
http-proxy1.18.1 has a race condition with fast upstream servers (e.g. Next.js Turbopack) that send WebSocket frames in the same TCP packet as the101 Switching Protocolsresponse — the HTTP parser sees binary frame bytes before theupgradeevent fires. Replacedproxy.ws()with raw TCP piping vianet.connect(), bypassing the HTTP parser entirely. - Next.js HMR unauthorized rejection: Next.js 15+ validates the
Originheader on HMR WebSocket connections as a CSRF guard. The proxy was forwarding the browser'sOrigin: https://your-domain.comto the upstream, which Next.js rejected. BothHostandOriginare now rewritten to the upstream address before forwarding. - Repeated WebSocket error log spam: The same proxy error from the same host was logged on every browser retry. Now rate-limited to once per 5 seconds per host and message.
- Cloudflare DNS error when switching from Max to Pro mode:
upsertARecordsonly queried for existing A records. If a CNAME record was left over from a previous Max mode run, Cloudflare rejected the new A record creation. Now queries all record types for the hostname and deletes any conflicting record first.
Added
- Graceful restart: Unhandled exceptions and rejected promises no longer kill the process permanently. dynamoip closes open servers and restarts with exponential backoff (2s → 4s → 8s → 16s → 30s, max 5 consecutive restarts). The counter resets after 5 minutes of stable operation. Startup errors (port in use, bad config) still exit immediately.
[1.0.5] — 2026-04-03
Added
- Max mode:
"tunnel": trueconfig key enables Cloudflare Tunnel for public internet access — no port forwarding, no firewall rules, no inbound ports required cloudflaredauto-installation on first Max mode run (Homebrew on macOS, binary download on Linux)- CNAME DNS records for tunnel mode — each subdomain points to the Cloudflare Tunnel (replaces A records used in Pro mode)
[PUBLIC]and[LAN]labels in CLI output to distinguish internet-exposed vs LAN-only domains at a glance- Mode labels in startup output:
Max — Cloudflare Tunnel,Pro — Cloudflare + Let's Encrypt,Quick — mkcert,HTTP - No
sudorequired in Max mode —cloudflaredmakes outbound connections only, no port 80/443 binding TARGET_HOSTenvironment variable for Docker setups to override proxy forwarding host (default:localhost)dynamoip-examples/tunnel/— Docker Compose example for Max mode (cross-platform, no host networking needed)dynamoip-examples/local/— Docker Compose example for Quick modedocs/tunnel.md— Max mode setup guide with token permissions and architecture walkthrough
[1.0.4] — 2026-04-02
Added
- Docker support:
LAN_IPenvironment variable override allows running inside containers where auto-detected IPs are incorrect docs/docker.mdwith full Docker and Docker Compose setup guidellms.txtfor LLM-readable project documentation.env.examplewith documented environment variables
[1.0.3] — 2026-04-01
Changed
- README: replaced bare
sudo dynamoipinvocations with package manager equivalents (sudo npm exec,sudo npx,sudo pnpm exec,sudo yarn) sincenode_modules/.binis not in sudo's restrictedPATH - Added production setup section to README
[1.0.2] — 2026-04-01
Changed
- README: added pnpm and yarn install/run instructions alongside npm
- Local dev docs updated with pnpm and yarn equivalents
[1.0.1] — 2026-04-01
Changed
- Renamed all internal references from
localDNS/localdnstodynamoip - Rewrote README with clearer use-case framing
[1.0.0] — 2026-04-01
Added
- Pro mode: Cloudflare DNS + Let's Encrypt wildcard certificate via DNS-01 challenge
- Quick mode: mDNS
.localhostnames viadns-sd(macOS) andavahi(Linux) - HTTPS reverse proxy with Host-header routing and WebSocket support (Vite HMR, Next.js Fast Refresh)
- HTTP → HTTPS redirect on port 80
- Automatic certificate renewal with exponential backoff and hot-reload via
setSecureContext() - LAN IP auto-detection
--config,--port,--no-ssl,--helpCLI flags- Concurrent ACME challenge support (handles both
*.domainanddomainSANs simultaneously) - Cert cache in
~/.localmap/certs/for instant subsequent startups - Graceful shutdown with mDNS cleanup on Ctrl+C
Security
- Shell commands use
spawnSyncwith argument arrays — no string interpolation, no shell injection risk - Private keys written with
0o600permissions, cert directories with0o700 - Cloudflare API error responses truncated before logging to prevent credential leakage
- Cloudflare API requests have a 10-second timeout
.envquote-stripping uses matched-pair logic to prevent silent token corruption
Dependencies
| Package | Purpose |
|---|---|
acme-client ^5.4.0 | ACME protocol client for Let's Encrypt |
http-proxy ^1.18.1 | Reverse proxy with WebSocket support |
tldts ^7.0.27 | Public Suffix List parser for correct multi-label TLD handling |