Improve dev host handling and clarify backend port configuration (#532)

* fix: remove --host from npm run server command

Running `vite --host` exposes the dev server on all interfaces. However,
we should expose it on all interfaces only when `HOST` is set to `0.0.0.0`.
Otherwise, we should assume the user wants to bind to a host of their choice
and not expose the server on the network.

* fix: use src hostname for redirecting to Vite in development

Previously, the server redirected to Vite using `localhost` as the hostname.
Even if the user was using HOST="0.0.0.0", if they connected to server from
another device on the same network using `http://<host_ip>:3001`, the
server would redirect them to `http://localhost:5173`, which would not
work since `localhost` would resolve to the client's machine instead of the server.

* fix: use shared network hosts configuration for better proxy setup

- Normalize all localhost variants to 'localhost' for consistent proxy
configuration in Vite and server setup.
- use one source of truth for network hosts functions by moving them to
a shared
- log production and development urls

* refactor: rename PORT to SERVER_PORT for clarity

* chore: add comments explaining host normalization

* fix: add legacy PORT env fallback for server port configuration

* fix: add fallback for SERVER_PORT using PORT environment variable

---------

Co-authored-by: Haileyesus <something@gmail.com>
Co-authored-by: Simos Mikelatos <simosmik@gmail.com>
This commit is contained in:
Haile
2026-03-16 14:40:01 +03:00
committed by GitHub
parent 14aef73cc6
commit d6133ba2ad
7 changed files with 65 additions and 30 deletions

View File

@@ -31,7 +31,7 @@ const c = {
dim: (text) => `${colors.dim}${text}${colors.reset}`,
};
console.log('PORT from env:', process.env.PORT);
console.log('SERVER_PORT from env:', process.env.SERVER_PORT);
import express from 'express';
import { WebSocketServer, WebSocket } from 'ws';
@@ -70,6 +70,7 @@ import { initializeDatabase, sessionNamesDb, applyCustomSessionNames } from './d
import { configureWebPush } from './services/vapid-keys.js';
import { validateApiKey, authenticateToken, authenticateWebSocket } from './middleware/auth.js';
import { IS_PLATFORM } from './constants/config.js';
import { getConnectableHost } from '../shared/networkHosts.js';
const VALID_PROVIDERS = ['claude', 'codex', 'cursor', 'gemini'];
@@ -2403,7 +2404,8 @@ app.get('*', (req, res) => {
res.sendFile(indexPath);
} else {
// In development, redirect to Vite dev server only if dist doesn't exist
res.redirect(`http://localhost:${process.env.VITE_PORT || 5173}`);
const redirectHost = getConnectableHost(req.hostname);
res.redirect(`${req.protocol}://${redirectHost}:${VITE_PORT}`);
}
});
@@ -2491,10 +2493,10 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
});
}
const PORT = process.env.PORT || 3001;
const SERVER_PORT = process.env.SERVER_PORT || 3001;
const HOST = process.env.HOST || '0.0.0.0';
// Show localhost in URL when binding to all interfaces (0.0.0.0 isn't a connectable address)
const DISPLAY_HOST = HOST === '0.0.0.0' ? 'localhost' : HOST;
const DISPLAY_HOST = getConnectableHost(HOST);
const VITE_PORT = process.env.VITE_PORT || 5173;
// Initialize database and start server
async function startServer() {
@@ -2511,13 +2513,15 @@ async function startServer() {
// Log Claude implementation mode
console.log(`${c.info('[INFO]')} Using Claude Agents SDK for Claude integration`);
console.log(`${c.info('[INFO]')} Running in ${c.bright(isProduction ? 'PRODUCTION' : 'DEVELOPMENT')} mode`);
console.log('');
if (!isProduction) {
console.log(`${c.warn('[WARN]')} Note: Requests will be proxied to Vite dev server at ${c.dim('http://localhost:' + (process.env.VITE_PORT || 5173))}`);
if (isProduction) {
console.log(`${c.info('[INFO]')} To run in production mode, go to http://${DISPLAY_HOST}:${SERVER_PORT}`);
}
server.listen(PORT, HOST, async () => {
console.log(`${c.info('[INFO]')} To run in development mode with hot-module replacement, go to http://${DISPLAY_HOST}:${VITE_PORT}`);
server.listen(SERVER_PORT, HOST, async () => {
const appInstallPath = path.join(__dirname, '..');
console.log('');
@@ -2525,7 +2529,7 @@ async function startServer() {
console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
console.log(c.dim('═'.repeat(63)));
console.log('');
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + PORT)}`);
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + SERVER_PORT)}`);
console.log(`${c.info('[INFO]')} Installed at: ${c.dim(appInstallPath)}`);
console.log(`${c.tip('[TIP]')} Run "cloudcli status" for full configuration details`);
console.log('');