Why a hosted API is often the right choice
A CPU-only VPS cannot run large models at useful speed. A hosted API gives you strong models on demand, and your small server only needs to send requests and handle the answers. That keeps the plan cheap and the application simple. The costs are per-request charges, data leaving your server and dependence on a provider.
This guide uses placeholder names and a generic request, because every provider documents its own endpoint and fields. Read your provider's documentation for the exact URL, headers and model names.
Keep the key out of your code
An API key is a password that spends money. Never write it into source files, commit it to a repository or paste it into a chat or ticket. Store it in a file that only root and the service can read, and load it into the process as an environment variable.
This example uses the myapp service account from the Node application guide. Create that service account first or replace the group with the actual application group. Administrators use sudo to manage the file; do not make it world-readable to run a shell test.
sudo mkdir -p /etc/myapp
sudo tee /etc/myapp/ai.env >/dev/null <<'EOF'
AI_API_KEY=PASTE_YOUR_KEY_HERE
AI_API_URL=https://api.example-provider.com/v1/chat/completions
AI_MODEL=model-name-from-the-provider
EOF
sudo chown root:myapp /etc/myapp/ai.env
sudo chmod 640 /etc/myapp/ai.env
ls -l /etc/myapp/ai.envLoad it with systemd
Reference the file from the service unit with EnvironmentFile. The process then sees the key as an environment variable and no other user can read the file. Avoid putting the key on the command line, where other users can see it with ps.
EnvironmentFile=/etc/myapp/ai.envsudo systemctl daemon-reload
sudo systemctl restart myapp
sudo systemctl show myapp -p EnvironmentFilesMake a request from the shell
Test the key and the endpoint with curl before you write application code. Using a variable keeps the key out of your shell history if you read it from the file. The request body depends on the provider; this is the common chat-style shape.
sudo bash <<'EOF'
set -a; . /etc/myapp/ai.env; set +a
curl --fail-with-body -sS -m 60 "$AI_API_URL" \
-H "Authorization: Bearer $AI_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"model\":\"$AI_MODEL\",\"max_tokens\":100,\"messages\":[{\"role\":\"user\",\"content\":\"Say hello in five words.\"}]}"
EOFSet timeouts, retries and limits in your code
Network calls fail and AI calls are slow. Always set a request timeout. Retry only on temporary errors such as timeouts, rate limits and server errors, with a growing delay and a small maximum number of attempts. Cap the output length with the provider's max-tokens setting, and limit how much text your users can send, since the length of the prompt is part of the cost.
Do not let the public call your API endpoint freely. Put rate limits in front of any route that triggers a paid request, and require a login for anything that is not a demo.
Control cost and watch usage
Set a monthly spending limit and an alert in the provider's dashboard, if it offers them, and use a separate key for each application so one project's usage and leaks are easy to isolate. Log the number of requests and tokens for each call, not the prompts, and check the totals. A loop or a bot can spend your budget in hours.
sudo journalctl -u myapp --since today --no-pager | grep -c "ai request"
sudo journalctl -u myapp --since today --no-pager | grep -ci "rate limit"Protect private data
Anything in the prompt leaves your server and is processed by the provider under its terms. Do not send passwords, customer personal data or confidential documents unless the provider's terms and your own obligations allow it. If you must work with sensitive text, consider a local model, and read the Ollama and sizing guides.
Rotate a leaked key
If a key appears in a repository, a log or a screenshot, treat it as compromised. Create a new key in the provider's dashboard, put it in the environment file, restart the service, then delete the old key. Check the provider's usage page for unexpected requests, and search your files and logs for any other copy.
sudo nano /etc/myapp/ai.env
sudo systemctl restart myapp
sudo grep -rIl "sk-" /home /opt /var/www 2>/dev/null | headOfficial documentation
These upstream references provide more detail on the commands and workflows in this guide.