dynamoip

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.cjs with a sourcemap.
  • Minimum Node.js bumped to 18+: Node 14 and 16 are end-of-life.
  • Async DNS in the ACME module: dns.Resolver replaced with dns.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 — runs tsc --noEmit for 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 bin extension: package.json pointed at dynamoip.js; corrected to dist/dynamoip.cjs after the tsdown build.

[1.0.6] — 2026-04-04

Fixed

  • Proxy crash on WebSocket errors: http-proxy passes a raw net.Socket (not http.ServerResponse) as the third argument when a WebSocket proxy error occurs. The error handler was calling res.writeHead() on the socket, crashing the entire process. The handler now detects this and calls socket.destroy() instead.
  • WebSocket HMR not working through proxy: http-proxy 1.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 the 101 Switching Protocols response — the HTTP parser sees binary frame bytes before the upgrade event fires. Replaced proxy.ws() with raw TCP piping via net.connect(), bypassing the HTTP parser entirely.
  • Next.js HMR unauthorized rejection: Next.js 15+ validates the Origin header on HMR WebSocket connections as a CSRF guard. The proxy was forwarding the browser's Origin: https://your-domain.com to the upstream, which Next.js rejected. Both Host and Origin are 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: upsertARecords only 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": true config key enables Cloudflare Tunnel for public internet access — no port forwarding, no firewall rules, no inbound ports required
  • cloudflared auto-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 sudo required in Max mode — cloudflared makes outbound connections only, no port 80/443 binding
  • TARGET_HOST environment 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 mode
  • docs/tunnel.md — Max mode setup guide with token permissions and architecture walkthrough

[1.0.4] — 2026-04-02

Added

  • Docker support: LAN_IP environment variable override allows running inside containers where auto-detected IPs are incorrect
  • docs/docker.md with full Docker and Docker Compose setup guide
  • llms.txt for LLM-readable project documentation
  • .env.example with documented environment variables

[1.0.3] — 2026-04-01

Changed

  • README: replaced bare sudo dynamoip invocations with package manager equivalents (sudo npm exec, sudo npx, sudo pnpm exec, sudo yarn) since node_modules/.bin is not in sudo's restricted PATH
  • 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/localdns to dynamoip
  • 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 .local hostnames via dns-sd (macOS) and avahi (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, --help CLI flags
  • Concurrent ACME challenge support (handles both *.domain and domain SANs simultaneously)
  • Cert cache in ~/.localmap/certs/ for instant subsequent startups
  • Graceful shutdown with mDNS cleanup on Ctrl+C

Security

  • Shell commands use spawnSync with argument arrays — no string interpolation, no shell injection risk
  • Private keys written with 0o600 permissions, cert directories with 0o700
  • Cloudflare API error responses truncated before logging to prevent credential leakage
  • Cloudflare API requests have a 10-second timeout
  • .env quote-stripping uses matched-pair logic to prevent silent token corruption

Dependencies

PackagePurpose
acme-client ^5.4.0ACME protocol client for Let's Encrypt
http-proxy ^1.18.1Reverse proxy with WebSocket support
tldts ^7.0.27Public Suffix List parser for correct multi-label TLD handling

On this page