A self-signed HTTPS reverse proxy for Svelte/Vite dev servers that routes /api/* requests to a configurable local or staging backend while preserving cookies, headers, and SPA fallback.
/api/* requests to local or remote APIx-app-environment: local header to staging requestsnpm install --save-dev svelte-api-proxy concurrently
See QUICK_START.md for a complete installation and configuration guide.
Browser (https://dev-example.com:8443)
↓
HTTPS Proxy Server (port 8443)
↓
├── /api/* requests → Remote/Local API (e.g., https://api.example.com)
└── All other requests → Vite Dev Server (http://localhost:5173)
https://dev-example.com:8443/api/ → Forward to configured API/, /@vite/*, or contains . → Forward to Vite/)Host header to avoid routing conflictsx-app-environment: local for non-local APIsThe proxy automatically upgrades WebSocket connections:
/api/* WebSockets → Forwarded to APIAll configuration is done via environment variables with the PROXY_ prefix.
| Variable | Required | Default | Description |
|---|---|---|---|
PROXY_APP_PORT |
Yes | - | Port where your Vite dev server runs (e.g., 5173) |
PROXY_PORT |
Yes | - | Port where the HTTPS proxy listens (e.g., 8443) |
PROXY_DEV_DOMAIN |
Yes | - | Domain alias for local dev. Must match SSL certificate common name |
PROXY_API_LOCAL |
No | false |
When true, disables SSL verification for local self-signed API certs |
PROXY_API_BASE_URL |
Yes | - | Full base URL of the API (e.g., https://api.example.com) |
PROXY_CERTS_PATH |
Yes | - | Relative or absolute path to directory containing SSL certificates |
PROXY_SHOW_LOGS |
No | true |
When true, logs all proxy requests and responses to console |
Create a .env file in your project root:
# Proxy Configuration
PROXY_APP_PORT=5173
PROXY_PORT=8443
PROXY_DEV_DOMAIN=dev-example.com
PROXY_API_LOCAL=false
PROXY_API_BASE_URL=https://api.example.com
PROXY_CERTS_PATH=./certs
PROXY_SHOW_LOGS=true
This package expects environment variables to be set before the CLI runs. Use one of these approaches:
Option 1: dotenv with node -r flag
{
"scripts": {
"dev:proxy": "node -r dotenv/config ./node_modules/.bin/svelte-api-proxy"
}
}
Option 2: dotenv-cli
npm install --save-dev dotenv-cli
{
"scripts": {
"dev:proxy": "dotenv -- svelte-api-proxy"
}
}
Option 3: Shell export
export PROXY_APP_PORT=5173
export PROXY_PORT=8443
# ... etc
svelte-api-proxy
Important: Add .env to your .gitignore:
echo ".env" >> .gitignore
The proxy requires two files in your certsPath directory:
{devDomain}-key.pem - Private key{devDomain}.pem - CertificateExample: If devDomain is dev-example.com:
dev-example.com-key.pemdev-example.com.pemInstall mkcert:
# macOS
brew install mkcert
# Linux
sudo apt install mkcert
# Windows
choco install mkcert
Generate certificates:
cd certs
mkcert -install
mkcert dev-example.com
This creates:
dev-example.com.pem (certificate)dev-example.com-key.pem (private key)Important: Add ./certs to your .gitignore to avoid committing certificates.
The main proxy server class.
import { DevProxy } from "svelte-api-proxy";
const proxy = new DevProxy(config);
Parameters:
config (object) - Configuration object with required fields:appPort (number)proxyPort (number)devDomain (string)apiBaseUrl (string)certsPath (string)apiLocal (boolean, optional, default: false)showLogs (boolean, optional, default: true)Throws:
start()Starts the HTTPS proxy server.
proxy.start();
Output:
[PROXY] Starting HTTPS dev proxy...
[PROXY] API target → REMOTE (https://api.example.com)
[PROXY] HTTPS server → https://dev-example.com:8443
[PROXY] App → http://localhost:5173
[PROXY] API → https://api.example.com
stop()Stops the proxy server.
proxy.stop();
The proxy automatically strips the Host header from forwarded requests to prevent routing conflicts. When you access https://dev-example.com:8443, the browser sends:
Host: dev-example.com:8443
If forwarded as-is to api.example.com, the remote server would reject it. The proxy strips this header and lets http-proxy's changeOrigin: true set the correct Host header.
When apiLocal is false (staging/production API), the proxy adds:
x-app-environment: local
This allows your API to differentiate between requests from local development vs deployed apps.
When showLogs is true, the proxy logs:
Request:
[PROXY] GET /api/users → https://api.example.com/api/users
Response:
[PROXY] Response: 200 GET /api/users
Set showLogs: false to disable logging.
For advanced use cases, you can use the proxy programmatically:
import { DevProxy } from "svelte-api-proxy";
const proxy = new DevProxy({
appPort: 5173,
proxyPort: 8443,
devDomain: "dev-example.com",
apiLocal: false,
apiBaseUrl: "https://api.example.com",
certsPath: "./certs",
showLogs: true,
});
proxy.start();
// Later...
proxy.stop();
Cause: Required environment variables are not set.
Solution:
.env file in your project root with all required PROXY_* variablesnode -r dotenv/config or dotenv --Cause: SSL certificates are missing or incorrectly named.
Solution:
certsPath points to the correct directory{devDomain}-key.pem and {devDomain}.pemCause: The remote API is not responding.
Solution:
apiBaseUrl is correctcurl https://api.example.com/api/healthCause: Browser doesn't trust self-signed certificate.
Solution: Run mkcert -install to install the local CA in your browser's trust store.
Cause: API is rejecting requests due to CORS policy.
Solution: Since the proxy forwards requests from localhost, your API must allow requests from your dev domain origin. Configure CORS on your API to allow https://dev-example.com:8443.
Cause: WebSocket upgrade not being handled correctly.
Solution:
appPortYou can run multiple Svelte apps with different domain aliases using separate .env files:
App 1 (.env.app1):
PROXY_APP_PORT=5173
PROXY_PORT=8443
PROXY_DEV_DOMAIN=app1.dev-example.com
PROXY_API_BASE_URL=https://api.example.com
PROXY_CERTS_PATH=./certs
App 2 (.env.app2):
PROXY_APP_PORT=5174
PROXY_PORT=8444
PROXY_DEV_DOMAIN=app2.dev-example.com
PROXY_API_BASE_URL=https://api.example.com
PROXY_CERTS_PATH=./certs
Run with specific env file:
{
"scripts": {
"dev:app1": "dotenv -e .env.app1 -- svelte-api-proxy",
"dev:app2": "dotenv -e .env.app2 -- svelte-api-proxy"
}
}
Use a common parent domain for cookie sharing:
# /etc/hosts
127.0.0.1 dev-example.com
127.0.0.1 app1.dev-example.com
127.0.0.1 app2.dev-example.com
127.0.0.1 api.dev-example.com
Set cookies with domain=.dev-example.com to share across all subdomains.
Version 2.0 changes configuration from package.json to environment variables.
Move your proxyConfig values to a .env file:
Before (package.json):
{
"proxyConfig": {
"appPort": 5173,
"proxyPort": 8443,
"devDomain": "dev-example.com",
"apiLocal": false,
"apiBaseUrl": "https://api.example.com",
"certsPath": "./certs",
"showLogs": true
}
}
After (.env):
PROXY_APP_PORT=5173
PROXY_PORT=8443
PROXY_DEV_DOMAIN=dev-example.com
PROXY_API_LOCAL=false
PROXY_API_BASE_URL=https://api.example.com
PROXY_CERTS_PATH=./certs
PROXY_SHOW_LOGS=true
npm install --save-dev dotenv
{
"scripts": {
"dev:proxy": "node -r dotenv/config ./node_modules/.bin/svelte-api-proxy"
}
}
Delete the proxyConfig section from your package.json.
echo ".env" >> .gitignore
MIT
Issues and PRs welcome at https://github.com/eduardocgarza/svelte-api-proxy