# How to Configure CORS and Middleware for Self-Hosted FreeLLMAPI Deployments

> Learn to configure CORS and middleware for self-hosted FreeLLMAPI deployments. Whitelist origins, methods, and headers effectively with Express and the cors package.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: how-to-guide
- Published: 2026-08-31

---

**FreeLLMAPI uses Express with the `cors` package configured in [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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:

```typescript
// 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-Type` and `Authorization`
- **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:

```typescript
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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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:

```typescript
// 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`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/ratelimit.ts):

```typescript
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`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/index.ts) orchestrates the application startup sequence. It loads environment variables via [`server/src/env.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/env.ts), creates the configured Express instance, and begins listening for connections:

```typescript
// 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.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/app.ts) and uses the standard `cors` npm 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`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/index.ts), which calls `createApp()` from [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/app.ts) and respects the `PORT` environment variable (defaulting to 8080).

## Frequently Asked Questions

### Where is CORS configured in FreeLLMAPI?

CORS is configured in the [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/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`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/env.ts) or pass it directly when launching the process: `PORT=3000 npm start`.