How to Build and Secure a REST API on a VPS

This guide covers the essential security and architecture practices for deploying a REST API on your own VPS, complementing your framework-specific development work with infrastructure-level best practices.

Basic Architecture

Client → Nginx (reverse proxy, SSL, rate limiting) → Application (API logic) → Database

Step 1 — Bind Your API to Localhost Only

Never expose your application's raw port directly to the internet — run it behind Nginx:

app.listen(3000, '127.0.0.1');

Step 2 — Configure Nginx as a Reverse Proxy

See Nginx as a Reverse Proxy for Node.js/Docker Apps for the full setup, including proper header forwarding.

Step 3 — Always Use HTTPS

sudo certbot --nginx -d api.yourdomain.com

Never accept API credentials or data over plain HTTP.

Step 4 — Implement Authentication

See How to Set Up API Authentication with JWT for token-based authentication, the most common approach for modern APIs.

Step 5 — Validate All Input

Never trust client input — validate types, lengths, and formats server-side, regardless of any client-side validation already performed:

const { body, validationResult } = require('express-validator');

app.post('/users',
  body('email').isEmail(),
  body('age').isInt({ min: 0, max: 150 }),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // ... process valid input
  }
);

Step 6 — Rate Limit API Endpoints

See How to Rate Limit an API with Nginx to prevent abuse and protect backend resources.

Step 7 — Set Appropriate CORS Policy

app.use(cors({
  origin: 'https://yourfrontend.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

Avoid overly permissive CORS (origin: '*') for APIs handling authenticated/sensitive data.

Step 8 — Return Consistent, Non-Leaky Error Responses

app.use((err, req, res, next) => {
  console.error(err); // log the full detail server-side
  res.status(500).json({ error: 'Internal server error' }); // don't leak stack traces to clients
});

Detailed error messages/stack traces should go to server-side logs, never directly to API responses in production.

Step 9 — Use Parameterized Queries (Prevent SQL Injection)

// Vulnerable
db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Safe
db.query('SELECT * FROM users WHERE email = ?', [email]);

Step 10 — Log API Requests for Monitoring and Debugging

app.use(morgan('combined'));

Step 11 — Version Your API

See How to Version an API Without Breaking Existing Clients.

Step 12 — Add Health Check Endpoints

See How to Add Health Check Endpoints to Your Application.

Security Checklist for Production APIs

  • HTTPS enforced everywhere
  • Authentication and authorization properly implemented
  • All input validated server-side
  • Rate limiting configured
  • Parameterized database queries throughout
  • No sensitive information leaked in error responses
  • CORS configured restrictively

Common Errors

API works locally but 502s in production — verify the app is actually running and bound to the port Nginx is proxying to; see How to Fix Common Nginx Errors (502/504/403).

Continue Reading

Browse more articles in Object Storage, Messaging & APIs.

  • rest api, api security, api deployment, backend security
  • 0 Utilisateurs l'ont trouvée utile
Cette réponse était-elle pertinente?

Articles connexes

How to Set Up Self-Hosted S3-Compatible Object Storage with MinIO

MinIO is a high-performance, self-hosted object storage server compatible with the S3 API —...

How to Use Object Storage for Application File Uploads

Storing user-uploaded files directly on your application server's disk creates scaling and...

How to Install and Configure RabbitMQ on a VPS

RabbitMQ is a widely-used, robust message broker — enabling applications to communicate...

How to Install and Configure Redis as a Message Queue

Redis, primarily known as a cache, also works well as a lightweight message queue for simpler use...

How to Design and Secure Webhook Endpoints

Webhooks let external services notify your application of events in real time. Since they accept...