How to Configure CORS and Middleware for Self-Hosted FreeLLMAPI Deployments
FreeLLMAPI uses Express with the cors package configured in server/src/app.ts to whitelist origins, methods, and headers before mounting routes and rate limiters.
When self-hosting the tashfeenahmed/freellmapi repository, proper CORS and middleware configuration ensures secure cross-origin requests and robust request processing. This guide explains how to configure CORS and middleware for self-hosted FreeLLMAPI deployments based on the actual TypeScript implementation, covering the middleware pipeline from CORS setup through rate limiting.
Core CORS Configuration in FreeLLMAPI
The CORS middleware is registered early in the Express application lifecycle within server/src/app.ts (around line 173). This placement ensures that cross-origin policies are enforced before any request processing or authentication occurs.
Importing and Registering the CORS Middleware
The server imports the standard cors package and applies it via app.use() at the beginning of the middleware chain:
// server/src/app.ts
import express from 'express';
import cors from 'cors';
export function createApp() {
const app = express();
app.use(
cors({
origin: ['https://my-frontend.example.com', 'http://localhost:3000'],
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
})
);
return app;
}
The configuration object accepts several key properties:
- origin: A string, array of strings, or callback function that validates the requesting domain
- methods: HTTP verbs the API accepts (typically
GET,POST,OPTIONS) - allowedHeaders: Headers clients may send, including
Content-TypeandAuthorization - credentials: Boolean indicating whether cookies or authorization headers should be forwarded
Dynamic Origin Validation
For production self-hosted deployments, use a dynamic validation function instead of hardcoded arrays. This approach reads allowed domains from environment variables or a configuration file:
app.use(
cors({
origin: (origin, callback) => {
const whitelist = ['https://my-frontend.example.com', 'http://localhost:3000'];
if (!origin || whitelist.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
})
);
Essential Middleware Stack
FreeLLMAPI layers several security and parsing middleware between the CORS handler and the API routes. The order of registration in server/src/app.ts is critical, as Express processes middleware sequentially.
Body Parsing and Request Serialization
Immediately after CORS configuration, the server attaches Express built-in body parsers to handle JSON and URL-encoded payloads:
// server/src/app.ts (excerpt)
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
These parsers convert raw request bodies into JavaScript objects available on req.body. The extended: true option allows rich objects and arrays to be encoded within the URL-encoded format.
Rate Limiting Implementation
Before mounting the API router, the server applies rate limiting through the custom service defined in server/src/services/ratelimit.ts:
import { ratelimit } from './services/ratelimit';
// Applied after body parsing, before routes
app.use(ratelimit());
This protects the LLM inference endpoints from abuse by tracking request frequency per client. The rate limiter executes after CORS to ensure preflight OPTIONS requests are handled correctly, but before route handlers to prevent unnecessary computation on throttled requests.
Bootstrapping the Server
The entry point at server/src/index.ts orchestrates the application startup sequence. It loads environment variables via server/src/env.ts, creates the configured Express instance, and begins listening for connections:
// server/src/index.ts
import { createApp } from './app';
import { loadEnv } from './env';
loadEnv(); // Reads .env file configuration
const app = createApp();
const port = Number(process.env.PORT) || 8080;
app.listen(port, () => {
console.log(`🚀 FreeLLMAPI listening on ${port}`);
});
The loadEnv() function initializes configuration from your environment files, allowing you to externalize the CORS whitelist, port numbers, and API keys without modifying source code.
Summary
- CORS configuration resides in
server/src/app.tsand uses the standardcorsnpm package to whitelist origins, methods, and headers near line 173. - Middleware ordering follows this sequence: CORS validation → body parsing (
express.json(),express.urlencoded()) → rate limiting (ratelimit()) → route handling (router). - Dynamic origin validation should replace static arrays in production deployments to support environment-specific domain whitelisting.
- Server initialization occurs in
server/src/index.ts, which callscreateApp()fromserver/src/app.tsand respects thePORTenvironment variable (defaulting to 8080).
Frequently Asked Questions
Where is CORS configured in FreeLLMAPI?
CORS is configured in the server/src/app.ts file within the createApp() function. The middleware is registered via app.use(cors({ ... })) around line 173, before body parsers and route handlers are attached. This ensures cross-origin policies are evaluated on every incoming request before reaching the API logic in server/src/services/router.ts.
How do I allow specific domains in FreeLLMAPI CORS?
Modify the origin property in the CORS configuration object inside server/src/app.ts. You can provide a static array of allowed domains or implement a callback function that checks the requesting origin against a whitelist. For production deployments, externalize this list to environment variables loaded through server/src/env.ts rather than hardcoding values in the source.
What middleware runs after CORS in the request pipeline?
After CORS validation, requests pass through express.json() and express.urlencoded() for body parsing, followed by the custom ratelimit() middleware defined in server/src/services/ratelimit.ts. Only then do requests reach the API routes mounted via app.use('/v1', router). This ordering ensures security and validation layers process requests before endpoint logic executes.
How do I change the default port for self-hosted deployments?
Set the PORT environment variable before starting the server. The server/src/index.ts entry point reads process.env.PORT and defaults to 8080 if undefined. You can define this variable in a .env file loaded by server/src/env.ts or pass it directly when launching the process: PORT=3000 npm start.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →