Skip to content

Deploy an API service

Tutorial · Updated Jun 2026

Deploy an API service

Run a lightweight API server on a Quake AI VM: either Node.js (Express) or Python (Flask). The API runs as a systemd service so it starts automatically on boot and restarts on failure.

What you will learn:

  • How to open a custom application port in a security group
  • How to install a Node.js or Python runtime on Ubuntu
  • How to register a long-running process as a systemd service
  • How to update and restart the service from your local machine
  • How to put Nginx in front of the API as a reverse proxy
API clientPublic IP(PublicEphemeral)Security groupSSH + API portUbuntu instanceNginx(reverse proxy)API processNode.js or Flask(systemd) localhostHTTPS
Click to zoom
What you'll build: an API process behind Nginx on a single Ubuntu instance, reachable through its PublicEphemeral public IP and a security group

Prerequisites#

Step 1. Create a security group#

Create a security group allowing SSH and your API port:

Step 2. Launch the instance#

Follow Launch your first server to launch an Ubuntu 24.04 instance on the PublicEphemeral network with the s1a.micro flavor, but attach the dev-api security group from Step 1 instead of web-access. The PublicEphemeral network gives the instance a public IP at boot, so no floating IP is needed.

Step 3. Install a runtime and deploy your API#

SSH into the instance and choose one of the two paths below.

Install Node.js and create a minimal API:

bash
# Install Node.js 22 LTS
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs

# Create the app
mkdir -p ~/api && cd ~/api
npm init -y
npm install express

Create ~/api/server.js:

bash
cat > ~/api/server.js << 'EOF'
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;

app.get("/", (req, res) => {
  res.json({ status: "ok", message: "Hello from Quake AI" });
});

app.get("/health", (req, res) => {
  res.json({ status: "healthy", uptime: process.uptime() });
});

app.listen(PORT, "0.0.0.0", () => {
  console.log(`API listening on port ${PORT}`);
});
EOF

Create a systemd service:

bash
sudo tee /etc/systemd/system/api.service > /dev/null << 'EOF'
[Unit]
Description=Node.js API
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/api
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
Environment=PORT=3000
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable api
sudo systemctl start api

Step 4. Verify#

Test the API from your local machine:

bash
curl http://YOUR_INSTANCE_IP:3000/
# {"status":"ok","message":"Hello from Quake AI"}

curl http://YOUR_INSTANCE_IP:3000/health
# {"status":"healthy","uptime":42.7}

Check the service status on the instance:

bash
sudo systemctl status api
journalctl -u api -f

Step 5. Deploy updates#

Push new code to the instance and restart the service:

bash
# From your local machine
scp -r ./api/* ubuntu@YOUR_INSTANCE_IP:~/api/

# On the instance
ssh ubuntu@YOUR_INSTANCE_IP
sudo systemctl restart api

Adding a reverse proxy (optional)#

For production-style deployments, put Nginx in front of your API to serve it on port 80. This example uses plain HTTP; add a TLS certificate and a port 443 listener as a follow-up.

The dev-api security group from Step 1 allows only SSH and port 3000, so external requests to plain http://YOUR_INSTANCE_IP/ time out until you open port 80. Add the rule from your local machine, where the OpenStack CLI is configured:

bash
# Open port 80 to allow external HTTP through Nginx
openstack security group rule create \
  --protocol tcp --dst-port 80 --remote-ip 0.0.0.0/0 dev-api

Then install and configure Nginx on the instance:

bash
sudo apt install -y nginx
sudo tee /etc/nginx/sites-available/api > /dev/null << 'EOF'
server {
    listen 80;
    server_name _;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

sudo ln -sf /etc/nginx/sites-available/api /etc/nginx/sites-enabled/api
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Next steps#

See also#

Usage Guidelines

The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.

For the full policy, see Usage Guidelines.

Last validated: 04.06.2026

Quick answers

Was this page helpful?