feat(config): support PORT env override

This commit is contained in:
William Valentin
2026-02-15 18:12:05 -08:00
parent 81385745e6
commit 1a7b7f6ce8
3 changed files with 89 additions and 2 deletions
+13 -1
View File
@@ -43,6 +43,18 @@
"test_status": "pnpm test:run + pnpm typecheck passing" "test_status": "pnpm test:run + pnpm typecheck passing"
}, },
"deployment-port-env-override": {
"status": "completed",
"date": "2026-02-16",
"updated": "2026-02-16",
"summary": "Added PORT environment variable override support so PaaS deployments can bind the gateway to the platform-assigned port without requiring config changes.",
"files_modified": [
"src/config/loader.ts",
"src/config/loader.test.ts"
],
"test_status": "pnpm test:run + pnpm typecheck passing"
},
"openclaw-gap-roadmap": { "openclaw-gap-roadmap": {
"file": "2026-02-15-openclaw-gap-roadmap.md", "file": "2026-02-15-openclaw-gap-roadmap.md",
"status": "planned", "status": "planned",
@@ -2132,7 +2144,7 @@
}, },
"overall_progress": { "overall_progress": {
"total_test_count": 1692, "total_test_count": 1694,
"all_tests_passing": true, "all_tests_passing": true,
"p0_completion": "3/3 (100%)", "p0_completion": "3/3 (100%)",
"p1_completion": "4/4 (100%)", "p1_completion": "4/4 (100%)",
+62
View File
@@ -102,6 +102,68 @@ telegram:
rmSync(testDir, { recursive: true }); rmSync(testDir, { recursive: true });
}); });
it('overrides server.port from PORT env var when set', () => {
mkdirSync(testDir, { recursive: true });
const configPath = join(testDir, 'config.yaml');
const prevPort = process.env.PORT;
process.env.PORT = '3777';
writeFileSync(configPath, `
telegram:
bot_token: "test-token"
allowed_chat_ids: [123]
server:
port: 18800
models:
default:
provider: anthropic
model: claude-sonnet
`);
const config = loadConfig(configPath);
expect(config.server.port).toBe(3777);
if (prevPort !== undefined) {
process.env.PORT = prevPort;
} else {
delete process.env.PORT;
}
rmSync(testDir, { recursive: true });
});
it('ignores invalid PORT env var values', () => {
mkdirSync(testDir, { recursive: true });
const configPath = join(testDir, 'config.yaml');
const prevPort = process.env.PORT;
process.env.PORT = 'not-a-number';
writeFileSync(configPath, `
telegram:
bot_token: "test-token"
allowed_chat_ids: [123]
server:
port: 18800
models:
default:
provider: anthropic
model: claude-sonnet
`);
const config = loadConfig(configPath);
expect(config.server.port).toBe(18800);
if (prevPort !== undefined) {
process.env.PORT = prevPort;
} else {
delete process.env.PORT;
}
rmSync(testDir, { recursive: true });
});
}); });
describe('loadConfig with overlay', () => { describe('loadConfig with overlay', () => {
+14 -1
View File
@@ -81,5 +81,18 @@ export function loadConfig(configPath: string, overlayPath?: string): Config {
} }
const expandedConfig = expandEnvVarsInObject(rawConfig); const expandedConfig = expandEnvVarsInObject(rawConfig);
return configSchema.parse(expandedConfig); const config = configSchema.parse(expandedConfig);
// PaaS convention: if PORT is set, bind the gateway to it.
// This is intentionally an override (even if config.server.port is set)
// to make deployments on Fly/Railway/Render/Heroku-style platforms work.
const envPort = process.env.PORT;
if (envPort && /^\d+$/.test(envPort)) {
const port = Number(envPort);
if (Number.isFinite(port) && port > 0 && port <= 65535) {
config.server.port = port;
}
}
return config;
} }