Deployment guide

New API

Overview

New API is an open-source, AGPL-3.0 licensed AI gateway. You connect upstream model services as channels (OpenAI, Anthropic, Google Gemini, Azure OpenAI, AWS Bedrock, Vertex AI, DeepSeek or any OpenAI-compatible endpoint). New API exposes them to your applications through one consistent API, with per-application API keys, quotas, model routing and a usage log of every call.

This guide shows you how to deploy and operate the SecureAnyCloud image of New API on Ubuntu 24.04 from the Azure Marketplace. The image ships the official upstream v1.0.0-rc.44 release binary, unmodified and pinned by checksum.

New API hosts no model. It relays requests to the providers you connect, using your provider accounts, so it needs no GPU and runs comfortably on a small CPU-only VM. It is a single Go executable with its web console built in and an embedded SQLite database, so the appliance runs no database server, no cache server and no container runtime.

Out of the box, the upstream release lets whoever reaches it first create the administrator through its setup wizard, and it leaves open self-registration switched on. On this image, both are closed on the VM itself before anything is reachable. First boot creates the administrator with a password generated for your VM, turns registration off, and proves that the password works. It also proves that a wrong password is refused and that the wizard is closed, all before nginx is allowed to start.

New API is an independent open-source project by QuantumNous and its contributors. SecureAnyCloud produces this image. It is not affiliated with, endorsed by, or sponsored by the New API project or its contributors, and it ships the free, open-source, AGPL-3.0 licensed software unmodified.

What you get:

  • New API v1.0.0-rc.44, the official upstream linux/amd64 release binary, pinned by sha256 and shipped unmodified, with its LICENSE, NOTICE and third-party notices in /usr/share/doc/new-api
  • The New API web console, built into the same binary
  • nginx serving the console and the API over HTTPS on port 443 with a certificate generated for your VM. Port 80 only redirects to HTTPS
  • An nftables fence that keeps the New API port 3000 reachable on loopback only, so nginx is the only way in
  • An embedded SQLite database owned by an unprivileged new-api service account. No database server is installed, so there is no database port to protect
  • A unique administrator password, session secret, encryption secret and TLS certificate generated per VM on first boot, never baked into the image
  • 24/7 SecureAnyCloud support

Why this release. At the time of this build, the upstream project publishes its 1.0 release candidates as full releases and describes them as the last ones before 1.0. The older stable-named 0.13 line is affected by security advisories that were fixed only in the 1.0 candidates, including a critical one. This image therefore ships the current 1.0 candidate.

Prerequisites

Before you deploy this image, you need:

  • An Azure subscription with permission to create VMs
  • An account and API key for at least one model provider you want to connect (OpenAI, Anthropic, Google, Azure OpenAI, AWS Bedrock, DeepSeek or any OpenAI-compatible service). You add these yourself after launch
  • A Standard_B2s VM or larger. The work New API does per request is authentication, routing and a streaming copy, so 2 vCPU and 4 GiB suit most teams
  • Inbound TCP 443 (and optionally 80, which only redirects) open to the networks your applications and administrators connect from
  • An SSH key pair for administrative access

You are responsible for complying with the terms of every upstream provider you connect, and with any legal or regulatory obligations that apply to the service you run with this gateway in your jurisdiction.

1

Deploy from the Azure Portal

  1. In the Azure Portal, search the Marketplace for New API on Ubuntu 24.04 LTS by SecureAnyCloud and select Create.
  2. Choose your subscription, resource group and region.
  3. Set the VM size to Standard_B2s or larger.
  4. Set the authentication type to SSH public key and supply your key.
  5. Under Inbound port rules, allow SSH (22) and HTTPS (443). Add HTTP (80) if you want plain http:// links to redirect.
  6. On the Disks tab, choose StandardSSD_LRS for a good balance of cost and performance.
  7. Select Review + create, then Create.

First boot takes well under a minute. During it, the appliance generates your VM's credentials and certificate and closes the setup wizard and registration. nginx does not start until it has proved that all of this worked.

2

Deploy from the Azure CLI

Accept the Marketplace terms, create the VM, and open port 443:

az vm image terms accept --urn sac1647283583153:new-api-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-resource-group \
  --name new-api-gateway \
  --image sac1647283583153:new-api-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --storage-sku StandardSSD_LRS \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
az vm open-port \
  --resource-group my-resource-group \
  --name new-api-gateway \
  --port 443 --priority 1001

In production, restrict that rule to your own address ranges. A gateway holds your provider keys and spends on your provider accounts, so the fewer networks that can reach it, the better.

3

Connect to your VM

Connect over SSH:

ssh azureuser@<vm-ip>
4

Confirm the services are running

Check that all four services are active:

sudo systemctl is-active new-api-loopback-fence.service new-api-firstboot.service new-api.service nginx.service

Expected output:

active active active active

nginx listens on ports 80 and 443. New API listens on port 3000:

sudo ss -lntp | grep -E ':(80|443|3000)\b'

Expected output (process ids differ):

LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=3219,fd=5),...) LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=3219,fd=7),...) LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=3219,fd=6),...) LISTEN 0 511 [::]:443 [::]:* users:(("nginx",pid=3219,fd=8),...) LISTEN 0 4096 *:3000 *:* users:(("new-api",pid=3880,fd=11))

New API has no option to listen on loopback only. The appliance therefore adds a small nftables table that drops every packet to port 3000 unless it is addressed to loopback:

sudo nft list table inet sac_new_api

Expected output (the counters will differ):

table inet sac_new_api { chain input { type filter hook input priority filter - 10; policy accept; tcp dport 3000 ip daddr != 127.0.0.0/8 counter packets 0 bytes 0 drop tcp dport 3000 ip6 daddr != ::1 counter packets 0 bytes 0 drop } }

You can prove this from the VM itself. Port 3000 answers on loopback but not on the VM's own address, while nginx serves HTTPS:

curl -s -o /dev/null -w 'loopback 127.0.0.1:3000 -> HTTP %{http_code}\n' http://127.0.0.1:3000/api/status
curl -s -o /dev/null -m 4 -w "own address $(hostname -I | awk '{print $1}'):3000 -> HTTP %{http_code}\n" "http://$(hostname -I | awk '{print $1}'):3000/api/status" || true
curl -s -o /dev/null -w 'http://127.0.0.1/ -> HTTP %{http_code} %{redirect_url}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'https://127.0.0.1/ -> HTTP %{http_code}\n' https://127.0.0.1/

Expected output (your private address differs):

loopback 127.0.0.1:3000 -> HTTP 200 own address 10.0.0.11:3000 -> HTTP 000 http://127.0.0.1/ -> HTTP 301 https://127.0.0.1/ https://127.0.0.1/ -> HTTP 200

HTTP 000 means the request was dropped. Nothing outside the VM can reach New API except through nginx.

5

Read your VM's credentials

Every credential on this appliance was generated for this VM on its first boot. Print the credentials file:

sudo cat /root/new-api-credentials.txt

Expected output (your values differ):

# New API - generated for this VM on first boot by new-api-firstboot.service.
# Nothing here is shared with any other VM. Store the password somewhere safe;
# changing it in the console does not update this file. NEWAPI_URL=https://<your VM's public IP>/ NEWAPI_ADMIN_USERNAME=admin NEWAPI_ADMIN_PASSWORD=<24 characters generated on your VM> NEWAPI_TLS_SHA256_FINGERPRINT=<unique to your VM> # Sign in to the console at NEWAPI_URL. The certificate is self-signed for this VM, so # your browser warns once; compare the fingerprint above before accepting it. # OpenAI compatible base URL for your applications: https://<your VM's public IP>/v1
# (create one API key per application under API Keys). Open self-registration is OFF.

The session secret and the encryption secret that New API uses for its own tokens are in /etc/new-api/new-api.env. Only root and the new-api service account can read it. You never need to type these secrets.

6

Sign in to the console

Open NEWAPI_URL from the credentials file in your browser. The certificate is generated for your VM and is self-signed, so the browser warns once. Compare the fingerprint it shows with NEWAPI_TLS_SHA256_FINGERPRINT before you accept the certificate. Sign in as admin with NEWAPI_ADMIN_PASSWORD.

After you sign in, you land on the overview, which walks you through creating a key and sending a first request. The admin sections (Channels, Models, Users and System Settings) are in the sidebar.

To set a password of your own, go to Security & Access > Change Password and record the new password somewhere safe. The credentials file keeps the original.

7

Understand the access model

The public status endpoint shows the state of the appliance:

curl -sk https://127.0.0.1/api/status | jq '.data | {version, setup, register_enabled, self_use_mode_enabled}'

Expected output:

{ "version": "v1.0.0-rc.44", "setup": true, "register_enabled": false, "self_use_mode_enabled": true }
  • The setup wizard is closed. First boot completed it with your VM's administrator, so nobody else can claim the instance.
  • Open self-registration is off. Only the administrator can create accounts (Users in the sidebar). Turn registration on under System Settings > Authentication only if you intend to run a service that people sign up to.
  • Self-use mode is on. Models can be called without first entering a price for each one, which suits a private gateway for your own team. If you will bill users by usage, turn self-use mode off under System Settings > Operations and configure model prices.
  • Every API call needs a key. The OpenAI-compatible endpoints under /v1 refuse requests without a valid key.

Each of these refuses anonymous callers:

curl -sk -H 'Content-Type: application/json' -d '{"username":"someone","password":"Some-password-1","confirmPassword":"Some-password-1"}' https://127.0.0.1/api/setup | jq -r .message
curl -sk -H 'Content-Type: application/json' -d '{"username":"someone","password":"Some-password-1"}' https://127.0.0.1/api/user/register | jq -r .message
curl -sk -o /dev/null -w 'anonymous /v1/models -> HTTP %{http_code}\n' https://127.0.0.1/v1/models

Expected output:

The system is already initialized New user registration has been disabled by administrator anonymous /v1/models -> HTTP 401
8

Connect a model provider (a channel)

A channel is one upstream provider account. It has a type, a base URL if it is not the default, your API key for the provider, and the models it serves.

  1. In the console, open Channels and select Create Channel.
  2. Choose the provider. Built-in types include OpenAI, Anthropic, Gemini, Azure OpenAI, AWS Bedrock, Vertex AI and DeepSeek. For any OpenAI-compatible service, choose OpenAI and set its base URL.
  3. Paste your provider API key, select the models this channel should serve (or fetch them from the provider), and save.
  4. Use Test on the channel to send a real request through it.

Add several channels for the same model to spread load or fail over between accounts. Channel priority and weight control the routing. The appliance stores provider keys in its database on your VM's disk, where only the new-api service account can read them.

9

Create an API key for each application

Give every application its own key, so that you can see its usage and revoke it independently. In the console, open API Keys and select Create API Key. Give the key a name, and optionally a quota, an expiry date, an allowed model list or an IP allow list.

You can do the same from the command line on the VM. The following commands sign in with the administrator password from the credentials file, create a key named cli-app, print it, and use it:

PW=$(sudo sed -n 's/^NEWAPI_ADMIN_PASSWORD=//p' /root/new-api-credentials.txt) B=https://127.0.0.1
AT=$(printf '{"username":"admin","password":"%s"}' "$PW" \
  | curl -sk -H 'Content-Type: application/json' --data-binary @- "$B/api/user/login" | jq -r .data.access_token) printf '{"name":"cli-app","remain_quota":0,"expired_time":-1,"unlimited_quota":true}' \
  | curl -sk -H "Authorization: Bearer $AT" -H 'New-Api-User: 1' -H 'Content-Type: application/json' \
  --data-binary @- "$B/api/token/" | jq -r '"created: \(.success)"'
ID=$(curl -sk -H "Authorization: Bearer $AT" -H 'New-Api-User: 1' "$B/api/token/?p=1&size=100" \
  | jq -r '[(.data.items // .data)[] | select(.name=="cli-app")][-1].id') KEY="sk-$(curl -sk -X POST -H "Authorization: Bearer $AT" -H 'New-Api-User: 1' "$B/api/token/$ID/key" | jq -r .data.key)" echo "API key for cli-app: $KEY" curl -sk "$B/v1/models" -H "Authorization: Bearer $KEY"; echo curl -sk "$B/v1/chat/completions" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}' | jq .error

Expected output before any channel is connected (your key differs):

created: true API key for cli-app: sk-oXRYx0CMMPBYdCwbwFi141Ij6dRB1oSUWm8XdpeWWdWBbnvw {"data":[],"object":"list","success":true} { "code": "model_not_found", "message": "No available channel for model gpt-4o-mini under group default (distributor) (request id: ...)", "type": "new_api_error" }

The key is accepted and the request reaches the router. The router answers model_not_found because no channel serves that model yet. Once you have added a channel in Step 8, /v1/models lists its models and the same request returns the provider's answer.

10

Point your applications at the gateway

Any OpenAI-compatible client works. Set the base URL to https://<your VM's address>/v1 and the API key to the key you created. For example, with the OpenAI Python SDK:

from openai import OpenAI client = OpenAI( base_url="https://gateway.example.com/v1", api_key="sk-your-new-api-key", ) reply = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}], ) print(reply.choices[0].message.content)

Or use curl from your own machine:

curl https://<vm-ip>/v1/chat/completions \
  -H "Authorization: Bearer sk-your-new-api-key" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}],"stream":true}'

Streaming responses and WebSocket upgrades pass straight through nginx. New API also exposes provider-native endpoints, such as the Anthropic Messages API at /v1/messages, so clients written for those providers can use the gateway too.

Until you install a certificate from a public authority (Step 12), clients must either trust this VM's self-signed certificate or skip verification. Trusting the certificate is the safer choice. Copy /etc/new-api/tls/new-api.crt to the client and point the client at that file (for the Python SDK, set SSL_CERT_FILE).

11

Usage, users and quotas

  • Usage Logs records every call with the key, model, channel, tokens, cost and latency. Filter by key or model to see what each application used.
  • Users creates accounts for people who should manage their own keys. Each user's keys and usage are separate.
  • Quotas can be set on a user and on each key, so that a single application cannot exhaust your provider accounts.
  • Models shows which models your channels serve, and holds prices if you turn self-use mode off.
12

Use your own domain and certificate

Point a DNS name at the VM's public IP, then replace the self-signed certificate with one from a public authority. For example, use the webroot plugin of certbot (install certbot first):

sudo certbot certonly --webroot -w /var/www/html -d gateway.example.com
sudo ln -sf /etc/letsencrypt/live/gateway.example.com/fullchain.pem /etc/new-api/tls/new-api.crt
sudo ln -sf /etc/letsencrypt/live/gateway.example.com/privkey.pem /etc/new-api/tls/new-api.key
sudo nginx -t && sudo systemctl reload nginx

For the challenge to pass, add a location /.well-known/acme-challenge/ { root /var/www/html; } block to the port 80 server in /etc/nginx/sites-available/new-api.conf, and open port 80. Clients can then use https://gateway.example.com/v1 with normal certificate verification.

13

What is in the image, and under what licence

/opt/new-api/new-api --version sha256sum /opt/new-api/new-api cat /usr/share/doc/new-api/SOURCE

Expected output:

v1.0.0-rc.44 d16189ecc6f0597c05e33e5e7ab8ee02e8ad2cc5085a9475f83b4793966a2d96 /opt/new-api/new-api New API v1.0.0-rc.44, shipped UNMODIFIED as the official upstream release binary. Source: https://github.com/QuantumNous/new-api/tree/633b4c5b190dc1af99a2814391354d86948e7943 Release: https://github.com/QuantumNous/new-api/releases/tag/v1.0.0-rc.44 Binary sha256: d16189ecc6f0597c05e33e5e7ab8ee02e8ad2cc5085a9475f83b4793966a2d96 Licence: GNU Affero General Public License v3.0 (see LICENSE and NOTICE in this directory).

New API is licensed under the GNU Affero General Public License v3.0. Its NOTICE file adds attribution terms under section 7 of that licence, which the unmodified console already honours.

If you modify New API and let others use it over a network, the AGPL requires you to offer them the source of your modified version. Read /usr/share/doc/new-api/LICENSE and /usr/share/doc/new-api/NOTICE before you do. The upstream project's source is at the address in SOURCE above.

Day to day operation

sudo systemctl status new-api.service --no-pager sudo journalctl -u new-api.service -n 50 --no-pager sudo ls -l /var/lib/new-api/
  • Restart the gateway with sudo systemctl restart new-api.service, and nginx with sudo systemctl reload nginx.
  • Data lives in /var/lib/new-api/new-api.db (SQLite with a write-ahead log). Application logs are in /var/log/new-api.
  • Back up by stopping the service briefly and copying the database files:
sudo systemctl stop new-api.service
sudo tar czf /root/new-api-backup-$(date +%F).tgz -C /var/lib/new-api .
sudo systemctl start new-api.service

Azure Backup of the whole VM also captures the database. Keep /etc/new-api/new-api.env with any backup that you restore elsewhere, because New API needs the encryption secret in it to read what it stored.

  • Upgrades. Unattended upgrades keep Ubuntu and nginx patched. New API itself is a single binary. To move to a newer upstream release, back up first and read the release notes. Then replace /opt/new-api/new-api with the new release binary after checking its published checksum, and restart the service. New API migrates its database on start.

Security hardening

  • Restrict ports 443 and 80 to your own networks in the network security group. The gateway holds your provider keys.
  • Give each application its own key, with a quota and an expiry where it makes sense, and revoke keys you no longer use.
  • Keep registration off unless you intend to run a public service. If you turn it on, require email verification and set a quota for new users.
  • Use a certificate from a public authority for a real hostname (Step 12), so that clients can verify the gateway.
  • Keep unattended upgrades on. They are enabled in this image and patch nginx, the only internet-facing component.

Troubleshooting

Nothing answers on port 443. nginx starts only after first boot has completed. Check its status:

sudo systemctl status new-api-firstboot.service --no-pager sudo journalctl -u new-api-firstboot.service --no-pager | tail -30

The browser warns about the certificate. This is expected until you install your own certificate. Compare the fingerprint with NEWAPI_TLS_SHA256_FINGERPRINT in the credentials file.

The credentials file shows a private address. Azure did not expose the public IP to the VM when it first started. Use the VM's public IP from the Azure Portal instead. Everything else is unaffected.

A request returns model_not_found. No enabled channel serves that model for the key's group. Add the model to a channel (Step 8) or check the channel is enabled and its test passes.

A channel test fails. The error comes from the provider. Check the key, the base URL, and that your provider account can use the model.

Support

SecureAnyCloud publishes and supports this image. For help with the image, deployment or configuration, contact SecureAnyCloud support 24/7 through the Azure Marketplace listing.

Deploy on Azure

Launch New API on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure