Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/shiny-rats-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

Change local dev server default ip to `*` instead of `0.0.0.0`. This will cause the dev server to listen on both ipv4 and ipv6 interfaces
5 changes: 5 additions & 0 deletions .changeset/small-gifts-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"miniflare": patch
---

Only output ipv4 addresses when starting
4 changes: 2 additions & 2 deletions packages/miniflare/src/http/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export function getAccessibleHosts(ipv4Only = false): string[] {
// @ts-expect-error the `family` property is numeric as of Node.js 18.0.0
if (family === "IPv4" || family === 4) {
hosts.push(address);
} else if (!ipv4Only && (family === "IPv6" || family === 6)) {
hosts.push(`[${address}]`);
} else if (!ipv4Only) {
hosts.push(address);
}
});
});
Expand Down
15 changes: 8 additions & 7 deletions packages/miniflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1181,13 +1181,14 @@ export class Miniflare {
);

if (initial) {
let hosts: string[];
if (host === "::" || host === "*") {
hosts = getAccessibleHosts(false);
} else if (host === "0.0.0.0") {
hosts = getAccessibleHosts(true);
} else {
hosts = [];
const hosts: string[] = [];
if (host === "::" || host === "*" || host === "0.0.0.0") {
hosts.push(...getAccessibleHosts(true));

if (host !== "0.0.0.0") {
hosts.push("localhost");
hosts.push("[::1]");
}
}

for (const h of hosts) {
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/__tests__/configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe("normalizeAndValidateConfig()", () => {
constellation: [],
hyperdrive: [],
dev: {
ip: "0.0.0.0",
ip: "*",
local_protocol: "http",
port: undefined, // the default of 8787 is set at runtime
upstream_protocol: "https",
Expand Down
6 changes: 3 additions & 3 deletions packages/wrangler/src/__tests__/dev.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -833,13 +833,13 @@ describe("wrangler dev", () => {
});

describe("ip", () => {
it("should default ip to 0.0.0.0", async () => {
it("should default ip to *", async () => {
writeWranglerToml({
main: "index.js",
});
fs.writeFileSync("index.js", `export default {};`);
await runWrangler("dev");
expect((Dev as jest.Mock).mock.calls[0][0].initialIp).toEqual("0.0.0.0");
expect((Dev as jest.Mock).mock.calls[0][0].initialIp).toEqual("*");
expect(std.out).toMatchInlineSnapshot(`""`);
expect(std.warn).toMatchInlineSnapshot(`""`);
expect(std.err).toMatchInlineSnapshot(`""`);
Expand Down Expand Up @@ -1055,7 +1055,7 @@ describe("wrangler dev", () => {
});
fs.writeFileSync("index.js", `export default {};`);
await runWrangler("dev");
expect((Dev as jest.Mock).mock.calls[0][0].initialIp).toEqual("0.0.0.0");
expect((Dev as jest.Mock).mock.calls[0][0].initialIp).toEqual("*");
expect(std.out).toMatchInlineSnapshot(`
"Your worker has access to the following bindings:
- Durable Objects:
Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export interface DevConfig {
/**
* IP address for the local dev server to listen on,
*
* @default `0.0.0.0`
* @default `*`
*/
ip: string;

Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ function normalizeAndValidateDev(
rawDev: RawDevConfig
): DevConfig {
const {
ip = "0.0.0.0",
ip = "*",
port,
inspector_port,
local_protocol = "http",
Expand Down
37 changes: 21 additions & 16 deletions packages/wrangler/src/dev/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { createServer as createHttpServer } from "node:http";
import { connect } from "node:http2";
import { createServer as createHttpsServer } from "node:https";
import https from "node:https";
import { networkInterfaces } from "node:os";
import { createHttpTerminator } from "http-terminator";
import { getAccessibleHosts } from "miniflare";
import { useEffect, useRef, useState } from "react";
import serveStatic from "serve-static";
import { getHttpsOptions } from "../https-options";
Expand Down Expand Up @@ -166,7 +166,15 @@ export async function startPreviewServer({
const usedPort =
address && typeof address === "object" ? address.port : port;
logger.log(`⬣ Listening at ${localProtocol}://${ip}:${usedPort}`);
const accessibleHosts = ip !== "0.0.0.0" ? [ip] : getAccessibleHosts();
const accessibleHosts = [];
if (ip === "::" || ip === "*" || ip === "0.0.0.0") {
accessibleHosts.push(...getAccessibleHosts(true));

if (ip !== "0.0.0.0") {
accessibleHosts.push("localhost");
accessibleHosts.push("[::1]");
}
}
for (const accessibleHost of accessibleHosts) {
logger.log(`- ${localProtocol}://${accessibleHost}:${usedPort}`);
}
Expand Down Expand Up @@ -299,13 +307,21 @@ export function usePreviewServer({
const usedPort =
address && typeof address === "object" ? address.port : port;
logger.log(`⬣ Listening at ${localProtocol}://${ip}:${usedPort}`);
const accessibleHosts =
ip !== "0.0.0.0" ? [ip] : getAccessibleHosts();
const accessibleHosts = [];
if (ip === "::" || ip === "*" || ip === "0.0.0.0") {
accessibleHosts.push(...getAccessibleHosts(true));

if (ip !== "0.0.0.0") {
accessibleHosts.push("localhost");
accessibleHosts.push("[::1]");
}
}
for (const accessibleHost of accessibleHosts) {
logger.log(`- ${localProtocol}://${accessibleHost}:${usedPort}`);
}
});
proxy.server.listen(port, ip);

proxy.server.listen(port, ip === "*" ? "::" : ip);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does :: always work? Can a user configure their computer to prevent IPV6?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure, looks like you can disable ipv6 on a computer so I'll test manually and see what happens

Copy link
Contributor Author

@jspspike jspspike Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After testing with

sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1

on linux it seems to still be able to listen on ipv4 addresses

})
.catch((err) => {
if ((err as { code: string }).code !== "ABORT_ERR") {
Expand Down Expand Up @@ -681,14 +697,3 @@ export async function waitForPortToBeAvailable(
}
});
}

function getAccessibleHosts(): string[] {
const hosts: string[] = [];
Object.values(networkInterfaces()).forEach((net) => {
net?.forEach(({ family, address }) => {
// @ts-expect-error the `family` property is numeric as of Node.js 18.0.0
if (family === "IPv4" || family === 4) hosts.push(address);
});
});
return hosts;
}
1 change: 1 addition & 0 deletions packages/wrangler/src/dev/remote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export function useWorker(
)
);
}

start().catch((err) => {
// instead of logging the raw API error to the user,
// give them friendly instructions
Expand Down
17 changes: 2 additions & 15 deletions packages/wrangler/src/https-options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from "node:fs";
import os from "node:os";
import * as path from "node:path";
import { promisify } from "node:util";
import { getAccessibleHosts } from "miniflare";
import { getGlobalWranglerConfigPath } from "./global-wrangler-config-path";
import { logger } from "./logger";
import type { Attributes, Options } from "selfsigned";
Expand Down Expand Up @@ -103,7 +103,7 @@ async function generateCertificate() {
name: "subjectAltName",
altNames: [
{ type: 2, value: "localhost" },
...getAccessibleHosts().map((ip) => ({ type: 7, ip })),
...getAccessibleHosts(false).map((ip) => ({ type: 7, ip })),
],
},
],
Expand All @@ -112,16 +112,3 @@ async function generateCertificate() {
const { private: key, cert } = await generate(certAttrs, certOptions);
return { key, cert };
}

/**
* Ask the OS for the addresses of locally accessible hosts.
*/
function getAccessibleHosts(ipv4 = false): string[] {
const hosts: string[] = [];
Object.values(os.networkInterfaces()).forEach((net) =>
net?.forEach(({ family, address }) => {
if (!ipv4 || family === "IPv4") hosts.push(address);
})
);
return hosts;
}
110 changes: 50 additions & 60 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.