---
title: Add SSL via NGINX
description: Set up SSL for secure SuperTokens Core connections using NGINX as a reverse proxy.
sidebar:
  order: 5
---

## Overview

SuperTokens Core does not terminate TLS. This guide configures NGINX as a trusted TLS edge and redirects HTTP traffic to
HTTPS.

## Before you start

:::warning
This page is only relevant if you are self-hosting SuperTokens.
:::

This guide assumes NGINX is installed and Core listens on `127.0.0.1:3567`.

:::danger
Bind Core's port 3567 to `127.0.0.1` or a private network and block it from public ingress. If clients can connect to Core
directly, they can bypass TLS and controls enforced by NGINX. Core is a trusted backend component and must never be
directly reachable by browsers or clients you do not trust.
:::

## Steps

### 1. Obtain a certificate

For a local test only, create a self-signed certificate:

```bash
sudo install -d -m 700 /etc/nginx/ssl
sudo openssl req -x509 -nodes -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/server.key \
  -out /etc/nginx/ssl/server.crt \
  -subj "/CN=localhost"
```

Use a CA-issued certificate valid for the production hostname in production.

### 2. Configure NGINX

Add separate HTTP and HTTPS server blocks. Replace `localhost` and certificate paths with production values when needed.

```text title="/etc/nginx/sites-available/default"
server {
  listen 80;
  server_name localhost;
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl;
  server_name localhost;

  ssl_certificate /etc/nginx/ssl/server.crt;
  ssl_certificate_key /etc/nginx/ssl/server.key;

  location / {
    proxy_pass http://127.0.0.1:3567;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
  }
}
```

Test and apply the configuration:

```bash
sudo nginx -t
sudo service nginx reload
```

Verify that `http://localhost/hello` redirects to HTTPS and `https://localhost/hello` reaches Core. `/hello` is
unauthenticated and is only a basic process/storage signal; success does not prove API-key enforcement or that direct port
3567 is private. Test externally that port 3567 is unreachable, and test a protected Core API with no, wrong, and current
API keys.
