@@ -14,6 +14,7 @@ export interface Config {
1414 host : string ;
1515 port : number ;
1616 api_key ?: string ;
17+ cors_origins ?: string [ ] ;
1718 daytona_api_url ?: string ;
1819 daytona_api_key ?: string ;
1920 daytona_proxy_url ?: string ;
@@ -69,10 +70,45 @@ export const createConfig = (): Config => {
6970 : localDataDirectory ;
7071 const defaultDatabasePath = resolve ( defaultDataDirectory , "controller.db" ) ;
7172
73+ const isLoopbackHost = ( value : string ) : boolean => {
74+ const normalized = value . trim ( ) . toLowerCase ( ) ;
75+ return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1" ;
76+ } ;
77+
78+ const parseBooleanFlag = ( value : string | undefined ) : boolean => {
79+ if ( ! value ) return false ;
80+ return [ "1" , "true" , "yes" , "on" ] . includes ( value . trim ( ) . toLowerCase ( ) ) ;
81+ } ;
82+
83+ const normalizeOrigin = ( value : string ) : string | null => {
84+ try {
85+ const origin = new URL ( value . trim ( ) ) . origin ;
86+ return origin === "null" ? null : origin ;
87+ } catch {
88+ return null ;
89+ }
90+ } ;
91+
92+ const parseCorsOrigins = ( value : string | undefined ) : string [ ] => {
93+ const defaults = [
94+ "http://localhost:3000" ,
95+ "http://127.0.0.1:3000" ,
96+ "http://localhost:3001" ,
97+ "http://127.0.0.1:3001" ,
98+ "http://host.docker.internal:3000" ,
99+ "http://host.docker.internal:3001" ,
100+ ] ;
101+ const candidates =
102+ value && value . trim ( ) . length > 0 ? value . split ( "," ) . map ( ( entry ) => entry . trim ( ) ) : defaults ;
103+ return [ ...new Set ( candidates . map ( ( entry ) => normalizeOrigin ( entry ) ) . filter ( ( entry ) : entry is string => Boolean ( entry ) ) ) ] ;
104+ } ;
105+
72106 const schema = z . object ( {
73- VLLM_STUDIO_HOST : z . string ( ) . default ( "0 .0.0.0 " ) ,
107+ VLLM_STUDIO_HOST : z . string ( ) . default ( "127 .0.0.1 " ) ,
74108 VLLM_STUDIO_PORT : z . coerce . number ( ) . int ( ) . positive ( ) . default ( 8080 ) ,
75109 VLLM_STUDIO_API_KEY : z . string ( ) . optional ( ) ,
110+ VLLM_STUDIO_ALLOW_UNAUTHENTICATED : z . string ( ) . optional ( ) ,
111+ VLLM_STUDIO_CORS_ORIGINS : z . string ( ) . optional ( ) ,
76112 VLLM_STUDIO_DAYTONA_API_KEY : z . string ( ) . optional ( ) ,
77113 VLLM_STUDIO_DAYTONA_API_URL : z . string ( ) . optional ( ) ,
78114 VLLM_STUDIO_DAYTONA_PROXY_URL : z . string ( ) . optional ( ) ,
@@ -96,6 +132,7 @@ export const createConfig = (): Config => {
96132 } ) ;
97133
98134 const parsed = schema . parse ( process . env ) ;
135+ const host = parsed . VLLM_STUDIO_HOST . trim ( ) || "127.0.0.1" ;
99136
100137 const strictOpenAIModels = parsed . VLLM_STUDIO_STRICT_OPENAI_MODELS ;
101138 const strictOpenAIModelsEnabled = strictOpenAIModels
@@ -116,7 +153,7 @@ export const createConfig = (): Config => {
116153 activationPolicyRaw === "switch_on_request" ? "switch_on_request" : "load_if_idle" ;
117154
118155 const config : Config = {
119- host : parsed . VLLM_STUDIO_HOST ,
156+ host,
120157 port : parsed . VLLM_STUDIO_PORT ,
121158 inference_port : parsed . VLLM_STUDIO_INFERENCE_PORT ,
122159
@@ -127,6 +164,7 @@ export const createConfig = (): Config => {
127164 daytona_agent_mode : daytonaAgentMode ,
128165 agent_fs_local_fallback : localAgentFsFallback ,
129166 openai_model_activation_policy : openaiModelActivationPolicy ,
167+ cors_origins : parseCorsOrigins ( parsed . VLLM_STUDIO_CORS_ORIGINS ) ,
130168 providers : [ ] ,
131169 } ;
132170
@@ -139,6 +177,14 @@ export const createConfig = (): Config => {
139177 if ( parsed . VLLM_STUDIO_API_KEY ) {
140178 config . api_key = parsed . VLLM_STUDIO_API_KEY ;
141179 }
180+
181+ const allowUnauthenticated = parseBooleanFlag ( parsed . VLLM_STUDIO_ALLOW_UNAUTHENTICATED ) ;
182+ if ( ! config . api_key && ! allowUnauthenticated && ! isLoopbackHost ( host ) ) {
183+ throw new Error (
184+ "VLLM_STUDIO_API_KEY is required when binding the controller to a non-loopback host. Set VLLM_STUDIO_ALLOW_UNAUTHENTICATED=true only for trusted local environments."
185+ ) ;
186+ }
187+
142188 if ( parsed . VLLM_STUDIO_DAYTONA_API_KEY ) {
143189 config . daytona_api_key = parsed . VLLM_STUDIO_DAYTONA_API_KEY ;
144190 }
0 commit comments