← Back to DevBytes

New-API Deployment: 4 Pitfalls That Will Cost You Hours

Why I Ditched My Custom API Proxy for New-API

I spent two weeks building a custom API proxy service in Python. It handled authentication, rate limiting, usage tracking, and multi-model routing. It worked, but it was fragile — every edge case required more code, and I was spending more time maintaining the proxy than building my actual product. Then I found New-API, deployed it in 10 minutes, and deleted my custom code. Here's what I learned about deploying New-API correctly, including four pitfalls that will trip you up if you don't know about them.

What is New-API?

New-API is an open-source API management and distribution system designed for LLM APIs. Think of it as a self-hosted version of OpenRouter — it sits between your customers and your LLM provider (OpenAI, DeepSeek, Anthropic, etc.), handling:

It's the standard solution for anyone running an API reselling or multi-tenant LLM service. One Docker container, one SQLite database, and you have a production-ready API gateway.

Quick Deployment

docker run -d --name new-api \
  -p 3000:3000 \
  -v /path/to/data:/data \
  --restart always \
  calciumion/new-api:latest

Access the admin panel at http://your-server:3000. Default credentials are root / 123456 (change immediately).

That's the easy part. Now for the four pitfalls that cost me real time.

Pitfall 1: The First User Is Not an Admin

When you first access New-API, it asks you to register. The first registered user should become the admin automatically, but in practice, this doesn't always happen — especially if you access the registration page through a reverse proxy or with certain configurations.

Symptom: You register, log in, and see a normal user dashboard instead of the admin panel. No "Channels," "Tokens," or "Users" management options.

Fix: Directly modify the SQLite database:

# Access the SQLite database inside the container
docker exec -it new-api sqlite3 /data/new-api.db

# Check your user's role
SELECT id, username, role FROM users;

# Set role to 100 (super admin)
UPDATE users SET role = 100 WHERE id = 1;

# Verify
SELECT id, username, role FROM users;
# Should show role = 100 for your admin user

.quit

Then restart the container:

docker restart new-api

After restarting, log in again and you should see the full admin panel.

Pitfall 2: Channels and Tokens Must Be Created via Database (Sometimes)

The web UI for creating channels (LLM provider connections) and tokens (customer API keys) usually works. But if you're setting up programmatically or the UI is being stubborn, you can insert directly into SQLite:

docker exec -it new-api sqlite3 /data/new-api.db

-- Create a channel (DeepSeek example)
INSERT INTO channels (type, key, name, base_url, models, status, created_time)
VALUES (
  1,                                    -- type: 1 = OpenAI-compatible
  'sk-your-deepseek-api-key',          -- your provider API key
  'DeepSeek',                           -- channel name
  'https://api.deepseek.com',          -- provider base URL
  'deepseek-v4-flash',                  -- allowed models (comma-separated)
  1,                                    -- status: 1 = enabled
  strftime('%s','now')
);

-- Create an ability (maps model to channel)
INSERT INTO abilities (channel_id, model, enabled)
VALUES (1, 'deepseek-v4-flash', 1);

-- Create a user token (customer API key)
INSERT INTO tokens (user_id, key, name, status, used_quota, remain_quota, created_time)
VALUES (
  1,                                    -- user_id
  'customer-api-key-here',              -- the API key customers will use (NO sk- prefix!)
  'Customer 1',                         -- token name
  1,                                    -- status: 1 = enabled
  0,                                    -- used_quota
  100000000,                           -- remain_quota (in tokens)
  strftime('%s','now')
);

.quit

Then restart:

docker restart new-api

Pitfall 3: Token Keys Don't Use the sk- Prefix

This one is counterintuitive. When you create a token for a customer, New-API stores it without the sk- prefix. But when the customer uses the API, they include the sk- prefix in their Authorization header.

# In database: key = 'abc123def456'
# Customer uses: Authorization: Bearer sk-abc123def456

If you store the key with sk- in the database, authentication will fail because New-API will look for a key that starts with sk-sk-. This is a common source of "invalid API key" errors.

Additionally, make sure the token's group field is set to default:

UPDATE tokens SET "group" = 'default' WHERE id = 1;

Pitfall 4: Only Enable the Models You Can Afford

New-API lets you specify which models each channel supports. If you enable a model that uses an expensive provider tier, you can lose money fast. Here's what happened to me:

  1. I set up DeepSeek as my provider
  2. DeepSeek has two tiers: Flash (cheap) and Pro (expensive)
  3. I initially enabled both models in the channel
  4. A customer used Pro for a long conversation, consuming 50M tokens at Pro prices
  5. My cost for that one customer was higher than their monthly subscription fee

Fix: Only enable the cheapest model that meets your quality requirements:

-- Disable the expensive model
UPDATE abilities SET enabled = 0 WHERE model = 'deepseek-v4-pro';

-- Or remove it entirely from the channel
UPDATE channels SET models = 'deepseek-v4-flash' WHERE id = 1;

Then restart. Now customers can only use Flash, and your margins are safe.

Complete Working Configuration

Here's my production setup for reference:

# docker-compose.yml
version: '3'
services:
  new-api:
    image: calciumion/new-api:latest
    container_name: new-api
    ports:
      - "3000:3000"
    volumes:
      - ./data:/data
    restart: always
    environment:
      - TZ=Asia/Shanghai

Customer Usage

# Customer makes API calls like this:
curl https://your-server:3000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-customer1-key-abc" \
  -d '{
    "model": "deepseek-v4-flash",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Monitoring and Maintenance

Check Usage

docker exec -it new-api sqlite3 /data/new-api.db

-- Usage by token
SELECT t.name, t.used_quota, t.remain_quota,
       ROUND(t.used_quota * 100.0 / (t.used_quota + t.remain_quota), 1) as pct_used
FROM tokens t
ORDER BY t.used_quota DESC;

Backup

# The entire state is in one SQLite file
cp /path/to/data/new-api.db /path/to/backup/new-api-$(date +%Y%m%d).db

# That's it. One file = complete backup.

Conclusion

New-API is the fastest way to get a production-ready LLM API gateway. The four pitfalls — admin role, database channel creation, token key format, and model cost control — are the difference between a smooth deployment and hours of debugging. Set it up right the first time, and you can focus on your product instead of maintaining proxy infrastructure.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles