You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Express vhost实现多Node.js应用同3000端口运行

多Express应用共享3000端口的虚拟主机配置问题

我在Debian服务器上部署了三个基于Node.js(Express+EJS+视图)的应用文件夹,每个应用单独运行在3000端口时均可正常工作,但无法同时启动运行。目前已配置Nginx反向代理,将443端口的SSL请求转发至Express的3000端口。现请求帮助配置虚拟主机,使这三个应用共享3000端口,且各自使用独立的静态文件与视图文件夹。

报错信息

Error: Failed to lookup view "index" in views directory
"/var/express/vhost/ejs"
at Function.render (/var/express/uc.domain.com/dev/node_modules/express/lib/application.js:597:17)
at ServerResponse.render (/var/express/uc.domain.com/dev/node_modules/express/lib/response.js:1039:7)
at file:///var/express/uc.domain.com/dev/express.js:25:7
at Layer.handle [as handle_request] (/var/express/uc.domain.com/dev/node_modules/express/lib/router/layer.js:95:5)
at next (/var/express/uc.domain.com/dev/node_modules/express/lib/router/route.js:144:13)
at Route.dispatch (/var/express/uc.domain.com/dev/node_modules/express/lib/router/route.js:114:3)
at Layer.handle [as handle_request] (/var/express/uc.domain.com/dev/node_modules/express/lib/router/layer.js:95:5)
at /var/express/uc.domain.com/dev/node_modules/express/lib/router/index.js:284:15
at Function.process_params (/var/express/uc.domain.com/dev/node_modules/express/lib/router/index.js:346:12)
at next (/var/express/uc.domain.com/dev/node_modules/express/lib/router/index.js:280:10)

当前代码

vhost.js

import express from 'express'
import vhost from 'vhost'
import https from 'https'
import fs from 'fs'
import path from 'path'

import app from '../uc.domain.com/dev/express.js'

const options = {
  key: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.key'),
  cert: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.crt'),
  requestCert: false,
  rejectUnauthorized: false,
}

const port = process.env.PORT || 3000
const app = express()

tools.get('/', (req, res) => {
  res.send('This is the tools.uc.domain.com')
})


app.use(vhost('dev.uc.domain.com', app))
app.use(vhost('tools.uc.domain.com', tools))

const server = https.createServer(options, app).listen(port, () => {
  console.log(`- https://dev.uc.domain.com:${port},`)
  console.log(`- https://tools.uc.domain.com:${port}`) 
  console.log('For end of work press Ctrl+C')
})

../uc.domain.com/dev/express.js

import express from 'express'
import https from 'https'
import fs from 'fs'
import path from 'path'
import router from './system/routes.js'

const options = {
  key: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.key'),
  cert: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.crt'),
  requestCert: false,
  rejectUnauthorized: false,
}

const port = process.env.PORT || 3000
const app = express()
app.set('view engine', 'ejs')
app.set('views', path.resolve(process.cwd(), 'ejs'))

app.use(express.static(path.resolve(process.cwd(), 'static')))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(router)

app.get('/', (req, res) => {
  res.render('index', {
    title: 'Sweet home Alabama',
  })
})

app.get('/:sub', (req, res) => {
  res.render(req.params.sub, {
    title: 'Sweet home Alabama',
  })
})

// const server = https.createServer(options, app).listen(port, () => {
//  console.log(`- https://dev.uc.domain.com:${port})
// })

export default app

问题根源与修复方案

核心问题分析

  1. 变量重名冲突:vhost.js中先导入dev应用的app实例,随后又重新声明const app = express(),直接覆盖了原实例,导致虚拟主机配置失效。
  2. 工作目录错误:express.js用process.cwd()获取当前目录,当通过vhost主应用启动时,process.cwd()指向vhost.js所在的/var/express/vhost,而非dev应用的/var/express/uc.domain.com/dev,因此找不到ejs和static文件夹。
  3. 未初始化应用实例:vhost.js中直接使用tools但未创建对应的Express实例。

修复步骤

1. 修正vhost.js的变量与实例配置

import express from 'express'
import vhost from 'vhost'
import https from 'https'
import fs from 'fs'
import path from 'path'

// 避免变量重名,重命名导入的dev应用
import devApp from '../uc.domain.com/dev/express.js'

// 创建tools应用实例
const toolsApp = express()
toolsApp.get('/', (req, res) => {
  res.send('This is the tools.uc.domain.com')
})

const options = {
  key: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.key'),
  cert: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.crt'),
  requestCert: false,
  rejectUnauthorized: false,
}

const port = process.env.PORT || 3000
const mainApp = express()

// 配置虚拟主机规则
mainApp.use(vhost('dev.uc.domain.com', devApp))
mainApp.use(vhost('tools.uc.domain.com', toolsApp))

// 启动主服务器
const server = https.createServer(options, mainApp).listen(port, () => {
  console.log(`- https://dev.uc.domain.com:${port}`)
  console.log(`- https://tools.uc.domain.com:${port}`) 
  console.log('For end of work press Ctrl+C')
})

2. 修正express.js的路径配置

用import.meta.url获取当前文件的绝对路径,替代process.cwd(),确保指向正确的应用目录:

import express from 'express'
import https from 'https'
import fs from 'fs'
import path from 'path'
import router from './system/routes.js'

const options = {
  key: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.key'),
  cert: fs.readFileSync('/var/express/_ssl/helios.uc.domain.com.crt'),
  requestCert: false,
  rejectUnauthorized: false,
}

const port = process.env.PORT || 3000
const app = express()
app.set('view engine', 'ejs')

// 获取当前应用的根目录
const appRoot = path.dirname(new URL(import.meta.url).pathname)
// 配置视图文件夹路径
app.set('views', path.join(appRoot, 'ejs'))
// 配置静态文件路径
app.use(express.static(path.join(appRoot, 'static')))

app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(router)

app.get('/', (req, res) => {
  res.render('index', {
    title: 'Sweet home Alabama',
  })
})

app.get('/:sub', (req, res) => {
  res.render(req.params.sub, {
    title: 'Sweet home Alabama',
  })
})

export default app

3. 第三个应用的扩展配置

参照dev应用的模式创建第三个应用的Express实例,在vhost.js中导入并添加虚拟主机规则:

// 在vhost.js中导入第三个应用
import thirdApp from '../path/to/third/app.js'

// 添加对应的虚拟主机规则
mainApp.use(vhost('third.uc.domain.com', thirdApp))

4. Nginx反向代理确认

确保Nginx将不同域名的请求转发到Express的3000端口,示例配置:

server {
    listen 443 ssl;
    server_name dev.uc.domain.com;

    ssl_certificate /path/to/ssl/cert;
    ssl_certificate_key /path/to/ssl/key;

    location / {
        proxy_pass https://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 443 ssl;
    server_name tools.uc.domain.com;

    ssl_certificate /path/to/ssl/cert;
    ssl_certificate_key /path/to/ssl/key;

    location / {
        proxy_pass https://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

内容的提问来源于stack exchange,提问作者user22790531

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:55:00