diff --git a/.env.example b/.env.example index 4b3cbbc2a..119859930 100755 --- a/.env.example +++ b/.env.example @@ -21,6 +21,10 @@ PORT=3001 #Frontend port VITE_PORT=5173 +# Host/IP to bind servers to (default: 0.0.0.0 for all interfaces) +# Use 127.0.0.1 to restrict to localhost only +HOST=0.0.0.0 + # Uncomment the following line if you have a custom claude cli path other than the default "claude" # CLAUDE_CLI_PATH=claude diff --git a/server/index.js b/server/index.js index bac8e0bc2..f207cf40a 100755 --- a/server/index.js +++ b/server/index.js @@ -1889,6 +1889,9 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden = } const PORT = process.env.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; // Initialize database and start server async function startServer() { @@ -1908,7 +1911,7 @@ async function startServer() { console.log(`${c.warn('[WARN]')} Note: Requests will be proxied to Vite dev server at ${c.dim('http://localhost:' + (process.env.VITE_PORT || 5173))}`); } - server.listen(PORT, '0.0.0.0', async () => { + server.listen(PORT, HOST, async () => { const appInstallPath = path.join(__dirname, '..'); console.log(''); @@ -1916,7 +1919,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://0.0.0.0:' + PORT)}`); + console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + 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(''); diff --git a/vite.config.js b/vite.config.js index ee2d943be..48030b288 100755 --- a/vite.config.js +++ b/vite.config.js @@ -4,20 +4,26 @@ import react from '@vitejs/plugin-react' export default defineConfig(({ command, mode }) => { // Load env file based on `mode` in the current working directory. const env = loadEnv(mode, process.cwd(), '') - - + + const host = env.HOST || '0.0.0.0' + // When binding to all interfaces (0.0.0.0), proxy should connect to localhost + // Otherwise, proxy to the specific host the backend is bound to + const proxyHost = host === '0.0.0.0' ? 'localhost' : host + const port = env.PORT || 3001 + return { plugins: [react()], server: { + host, port: parseInt(env.VITE_PORT) || 5173, proxy: { - '/api': `http://localhost:${env.PORT || 3001}`, + '/api': `http://${proxyHost}:${port}`, '/ws': { - target: `ws://localhost:${env.PORT || 3001}`, + target: `ws://${proxyHost}:${port}`, ws: true }, '/shell': { - target: `ws://localhost:${env.PORT || 3001}`, + target: `ws://${proxyHost}:${port}`, ws: true } }