Skip to content

Commit 1e604d5

Browse files
eirslettnihalgonsalvesantfu
authored
fix(server): Listen only to 127.0.0.1 by default (#2977)
Co-authored-by: Nihal Gonsalves <[email protected]> Co-authored-by: Anthony Fu <[email protected]>
1 parent 0c97412 commit 1e604d5

File tree

5 files changed

+80
-44
lines changed

5 files changed

+80
-44
lines changed

docs/config/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,12 @@ export default async ({ command, mode }) => {
328328
### server.host
329329

330330
- **Type:** `string`
331+
- **Default:** `'127.0.0.1'`
331332

332-
Specify server hostname.
333+
Specify which IP addresses the server should listen on.
334+
Set this to `0.0.0.0` to listen on all addresses, including LAN and public addresses.
335+
336+
This can be set via the CLI using `--host 0.0.0.0` or `--host`.
333337

334338
### server.port
335339

packages/vite/src/node/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ cli
6363
cli
6464
.command('[root]') // default command
6565
.alias('serve')
66-
.option('--host <host>', `[string] specify hostname`)
66+
.option('--host [host]', `[string] specify hostname`)
6767
.option('--port <port>', `[number] specify port`)
6868
.option('--https', `[boolean] use TLS + HTTP/2`)
6969
.option('--open [path]', `[boolean | string] open browser on startup`)

packages/vite/src/node/preview.ts

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,48 @@ export async function preview(
4141
)
4242

4343
const options = config.server || {}
44-
const hostname = options.host || 'localhost'
44+
let hostname: string | undefined
45+
if (options.host === undefined || options.host === 'localhost') {
46+
// Use a secure default
47+
hostname = '127.0.0.1'
48+
} else if (options.host === true) {
49+
// The user probably passed --host in the CLI, without arguments
50+
hostname = undefined // undefined typically means 0.0.0.0 or :: (listen on all IPs)
51+
} else {
52+
hostname = options.host as string
53+
}
4554
const protocol = options.https ? 'https' : 'http'
4655
const logger = config.logger
4756
const base = config.base
4857

49-
httpServer.listen(port, () => {
58+
httpServer.listen(port, hostname, () => {
5059
logger.info(
5160
chalk.cyan(`\n vite v${require('vite/package.json').version}`) +
5261
chalk.green(` build preview server running at:\n`)
5362
)
54-
const interfaces = os.networkInterfaces()
55-
Object.keys(interfaces).forEach((key) =>
56-
(interfaces[key] || [])
57-
.filter((details) => details.family === 'IPv4')
58-
.map((detail) => {
59-
return {
60-
type: detail.address.includes('127.0.0.1')
61-
? 'Local: '
62-
: 'Network: ',
63-
host: detail.address.replace('127.0.0.1', hostname)
64-
}
65-
})
66-
.forEach(({ type, host }) => {
67-
const url = `${protocol}://${host}:${chalk.bold(port)}${base}`
68-
logger.info(` > ${type} ${chalk.cyan(url)}`)
69-
})
70-
)
63+
if (hostname === '127.0.0.1') {
64+
const url = `${protocol}://localhost:${chalk.bold(port)}${base}`
65+
logger.info(` > Local: ${chalk.cyan(url)}`)
66+
logger.info(` > Network: ${chalk.dim('use `--host` to expose')}`)
67+
} else {
68+
const interfaces = os.networkInterfaces()
69+
Object.keys(interfaces).forEach((key) =>
70+
(interfaces[key] || [])
71+
.filter((details) => details.family === 'IPv4')
72+
.map((detail) => {
73+
return {
74+
type: detail.address.includes('127.0.0.1')
75+
? 'Local: '
76+
: 'Network: ',
77+
host: detail.address
78+
}
79+
})
80+
.forEach(({ type, host }) => {
81+
const url = `${protocol}://${host}:${chalk.bold(port)}${base}`
82+
logger.info(` > ${type} ${chalk.cyan(url)}`)
83+
})
84+
)
85+
}
7186

7287
if (options.open) {
7388
const path = typeof options.open === 'string' ? options.open : base

packages/vite/src/node/server/index.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { ssrRewriteStacktrace } from '../ssr/ssrStacktrace'
5353
import { createMissingImporterRegisterFn } from '../optimizer/registerMissing'
5454

5555
export interface ServerOptions {
56-
host?: string
56+
host?: string | boolean
5757
port?: number
5858
/**
5959
* Enable TLS + HTTP/2.
@@ -532,8 +532,17 @@ async function startServer(
532532

533533
const options = server.config.server || {}
534534
let port = inlinePort || options.port || 3000
535-
let hostname = options.host || 'localhost'
536-
if (hostname === '0.0.0.0') hostname = 'localhost'
535+
let hostname: string | undefined
536+
if (options.host === undefined || options.host === 'localhost') {
537+
// Use a secure default
538+
hostname = '127.0.0.1'
539+
} else if (options.host === true) {
540+
// probably passed --host in the CLI, without arguments
541+
hostname = undefined // undefined typically means 0.0.0.0 or :: (listen on all IPs)
542+
} else {
543+
hostname = options.host as string
544+
}
545+
537546
const protocol = options.https ? 'https' : 'http'
538547
const info = server.config.logger.info
539548
const base = server.config.base
@@ -546,7 +555,7 @@ async function startServer(
546555
reject(new Error(`Port ${port} is already in use`))
547556
} else {
548557
info(`Port ${port} is in use, trying another one...`)
549-
httpServer.listen(++port)
558+
httpServer.listen(++port, hostname)
550559
}
551560
} else {
552561
httpServer.removeListener('error', onError)
@@ -556,7 +565,7 @@ async function startServer(
556565

557566
httpServer.on('error', onError)
558567

559-
httpServer.listen(port, options.host, () => {
568+
httpServer.listen(port, hostname, () => {
560569
httpServer.removeListener('error', onError)
561570

562571
info(
@@ -566,23 +575,30 @@ async function startServer(
566575
clear: !server.config.logger.hasWarned
567576
}
568577
)
569-
const interfaces = os.networkInterfaces()
570-
Object.keys(interfaces).forEach((key) =>
571-
(interfaces[key] || [])
572-
.filter((details) => details.family === 'IPv4')
573-
.map((detail) => {
574-
return {
575-
type: detail.address.includes('127.0.0.1')
576-
? 'Local: '
577-
: 'Network: ',
578-
host: detail.address.replace('127.0.0.1', hostname)
579-
}
580-
})
581-
.forEach(({ type, host }) => {
582-
const url = `${protocol}://${host}:${chalk.bold(port)}${base}`
583-
info(` > ${type} ${chalk.cyan(url)}`)
584-
})
585-
)
578+
579+
if (hostname === '127.0.0.1') {
580+
const url = `${protocol}://localhost:${chalk.bold(port)}${base}`
581+
info(` > Local: ${chalk.cyan(url)}`)
582+
info(` > Network: ${chalk.dim('use `--host` to expose')}`)
583+
} else {
584+
const interfaces = os.networkInterfaces()
585+
Object.keys(interfaces).forEach((key) =>
586+
(interfaces[key] || [])
587+
.filter((details) => details.family === 'IPv4')
588+
.map((detail) => {
589+
return {
590+
type: detail.address.includes('127.0.0.1')
591+
? 'Local: '
592+
: 'Network: ',
593+
host: detail.address
594+
}
595+
})
596+
.forEach(({ type, host }) => {
597+
const url = `${protocol}://${host}:${chalk.bold(port)}${base}`
598+
info(` > ${type} ${chalk.cyan(url)}`)
599+
})
600+
)
601+
}
586602

587603
// @ts-ignore
588604
if (global.__vite_start_time) {

scripts/jestPerTestSetup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ beforeAll(async () => {
7373
// misses change events, so enforce polling for consistency
7474
usePolling: true,
7575
interval: 100
76-
}
76+
},
77+
host: true
7778
},
7879
build: {
7980
// skip transpilation and dynamic import polyfills during tests to

0 commit comments

Comments
 (0)