Requirements
- Node.js 18+ — Uses native
fetchandcrypto.randomUUID(). - npm 8+ — For dependency installation.
- An API key from at least one AI provider (or a local Ollama installation).
Quick Start
# 1. Download or clone the project
git clone https://github.com/youruser/secure-custom-ai-chat.git
cd secure-custom-ai-chat
# 2. Install dependencies
npm install
# 3. Configure environment
cp .env.example .env
# Edit .env with your settings
# 4. Start the server
npm start
# Open http://localhost:3000
Environment Variables
Environment Variables
All configuration is done via environment variables in your .env file. Copy .env.example and fill in your values.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
TCP port the server listens on. |
NODE_ENV |
development |
Set to production for production deployments. |
AI_API_URL |
— | Default provider base URL (e.g., https://api.openai.com/v1). |
AI_API_KEY |
— | Default server-side API key. Never sent to clients. |
AI_MODEL |
— | Default model ID (e.g., gpt-4o-mini). |
AI_API_TYPE |
openai |
API protocol: openai or anthropic. |
AI_MAX_TOKENS_LIMIT |
8192 |
Max tokens per request (1–100,000). Enforced server and client. |
ALLOW_USER_PROVIDERS |
0 |
Set 1 to let users provide their own provider URL and API key. |
ALLOW_PRIVATE_PROVIDER_URLS |
0 |
Set 1 to allow localhost/private IP provider URLs (for Ollama dev). |
TRUST_PROXY |
0 |
Set 1 when running behind a reverse proxy (fixes rate-limit IP detection). |
Example Configurations
OpenAI (server-side key)
AI_API_URL=https://api.openai.com/v1
AI_API_KEY=sk-proj-...
AI_MODEL=gpt-4o-mini
AI_API_TYPE=openai
ALLOW_USER_PROVIDERS=0
Anthropic (server-side key)
AI_API_URL=https://api.anthropic.com
AI_API_KEY=sk-ant-...
AI_MODEL=claude-sonnet-4-5
AI_API_TYPE=anthropic
ALLOW_USER_PROVIDERS=0
Ollama (local development)
AI_API_URL=http://localhost:11434/v1
AI_API_KEY=ollama
AI_MODEL=llama3
AI_API_TYPE=openai
ALLOW_PRIVATE_PROVIDER_URLS=1
User-configurable mode (users bring their own key)
ALLOW_USER_PROVIDERS=1
# No AI_API_KEY or AI_API_URL required
Production Deployment
Production Deployment
With nginx reverse proxy
# nginx site config
server {
listen 443 ssl;
server_name ssblucky7.dev;
ssl_certificate /etc/letsencrypt/live/ssblucky7.dev/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ssblucky7.dev/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# SSE streaming — disable buffering
proxy_buffering off;
proxy_read_timeout 120s;
}
}
Set TRUST_PROXY=1 in your .env when using nginx.
With Caddy (automatic HTTPS)
# Caddyfile
ssblucky7.dev {
reverse_proxy localhost:3000 {
flush_interval -1
}
}
With PM2 (process manager)
npm install -g pm2
pm2 start server.js --name "ai-chat" --env production
pm2 save
pm2 startup
With Docker
# Dockerfile example
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# docker-compose.yml
version: '3.8'
services:
ai-chat:
build: .
ports:
- "3000:3000"
env_file: .env
restart: unless-stopped
Ollama Integration
Ollama Local Models
To use Ollama for fully local AI with no API costs:
- Install Ollama from ollama.ai.
- Pull a model:
ollama pull llama3 - Ollama starts its API server at
http://localhost:11434automatically. - Set
ALLOW_PRIVATE_PROVIDER_URLS=1in your.env. - In the app settings, select the Ollama / local preset.
- Click Load models to see available local models.
Only set
ALLOW_PRIVATE_PROVIDER_URLS=1 in trusted local development environments. Do not enable this on a public-facing production server.Server API Reference
POST /api/chat
Stream a chat completion. Returns Server-Sent Events.
// Request body
{
"messages": [
{ "role": "user", "content": "Hello!" }
],
"model": "gpt-4o-mini",
"maxTokens": 2048,
"temperature": 0.7,
// Only if ALLOW_USER_PROVIDERS=1:
"providerUrl": "https://api.openai.com/v1",
"apiKey": "sk-...",
"apiType": "openai"
}
// Response: text/event-stream
data: {"choices":[{"delta":{"content":"Hi"}}]}
data: {"choices":[{"delta":{"content":"!"}}]}
data: [DONE]
GET /api/config
Returns server configuration visible to clients (no secrets).
// Response
{
"allowUserProviders": false,
"hasServerKey": true,
"serverApiUrl": "https://api.openai.com/v1",
"serverApiType": "openai",
"serverModel": "gpt-4o-mini",
"maxTokensLimit": 8192
}
POST /api/models
Fetch available models from a provider.
// Request body
{
"providerUrl": "https://api.openai.com/v1",
"apiKey": "sk-..." // Only if ALLOW_USER_PROVIDERS=1
}
// Response
{
"models": [
{ "id": "gpt-4o-mini", "name": "GPT-4o mini" },
...
]
}