Configure HTTP server settings including host, port, CORS, and HTTPS.

Help: { "command": "admin config server show" } via systemprompt_help Requires: Profile configured -> See Profiles Playbook

ServerConfig defines HTTP server settings: host, port, API URLs, CORS, and HTTPS.


ServerConfig Struct

Source: crates/shared/models/src/profile/server.rs:5-22

pub struct ServerConfig {
    pub host: String,                          // Required: Bind address
    pub port: u16,                             // Required: Listen port
    pub api_server_url: String,                // Required: Primary API URL
    pub api_internal_url: String,              // Required: Internal service URL
    pub api_external_url: String,              // Required: Public/external URL
    #[serde(default)]
    pub use_https: bool,                       // Default: false
    #[serde(default)]
    pub cors_allowed_origins: Vec<String>,     // Default: empty
}

Field Details

Field Type Required Default Description
host String Yes - Network interface to bind
port u16 Yes - TCP port number (> 0)
api_server_url String Yes - Primary API endpoint
api_internal_url String Yes - Internal service-to-service URL
api_external_url String Yes - Public URL for external clients
use_https bool No false Enable HTTPS
cors_allowed_origins Vec No [] Allowed CORS origins

Host Configuration

Common Values

Value Use Case
127.0.0.1 Local development only
0.0.0.0 Accept connections from any interface
Specific IP Bind to specific network interface

Example

server:
  host: "0.0.0.0"  # Accept external connections
  port: 8080

The 3 API URLs

SystemPrompt uses three distinct URLs for different purposes.

api_server_url

Primary API endpoint used for:

  • Client applications
  • Browser requests
  • Default URL when others not specified
server:
  api_server_url: "http://localhost:8080"

api_internal_url

Internal service-to-service communication:

  • Background jobs calling API
  • Health checks
  • Internal service mesh
server:
  api_internal_url: "http://localhost:8080"

In cloud deployments, this might be a private network address:

server:
  api_internal_url: "http://sp-tenant.internal:8080"

api_external_url

Public URL for external access:

  • OAuth callbacks
  • Webhook URLs
  • Public documentation links
  • External API references
server:
  api_external_url: "https://api.example.com"

URL Relationship

Scenario api_server_url api_internal_url api_external_url
Local dev http://localhost:8080 http://localhost:8080 http://localhost:8080
Docker http://0.0.0.0:8080 http://app:8080 http://localhost:8080
Production https://api.example.com http://internal:8080 https://api.example.com

CORS Configuration

Cross-Origin Resource Sharing (CORS) allows frontend applications to make API requests.

Basic Setup

server:
  cors_allowed_origins:
    - "http://localhost:8080"       # API origin
    - "http://localhost:5173"       # Vite dev server
    - "http://localhost:3000"       # React dev server

Production Setup

server:
  cors_allowed_origins:
    - "https://app.example.com"
    - "https://www.example.com"

Validation Rules

Source: crates/shared/models/src/profile/validation.rs:151-166

Each CORS origin must:

  1. Be non-empty
  2. Start with http:// or https://
fn validate_cors_origins(&self) -> Result<()> {
    for origin in &self.server.cors_allowed_origins {
        if origin.is_empty() {
            return Err(ProfileError::EmptyCorsOrigin);
        }
        if !origin.starts_with("http://") && !origin.starts_with("https://") {
            return Err(ProfileError::InvalidCorsOrigin(origin.clone()));
        }
    }
    Ok(())
}

Common Mistakes

Invalid Why Fix
localhost:5173 Missing protocol http://localhost:5173
http://localhost:5173/ Trailing slash http://localhost:5173
* Wildcard not supported List specific origins
Empty string Not allowed Remove or specify origin

HTTPS Configuration

Enable HTTPS

server:
  use_https: true
  api_server_url: "https://api.example.com"
  api_external_url: "https://api.example.com"

Development (No HTTPS)

server:
  use_https: false
  api_server_url: "http://localhost:8080"

Cloud Deployment

In cloud deployments, TLS is typically terminated at the proxy:

server:
  host: "0.0.0.0"
  port: 8080
  use_https: false                    # TLS at proxy level
  api_server_url: "http://0.0.0.0:8080"
  api_internal_url: "http://0.0.0.0:8080"
  api_external_url: "https://tenant.systemprompt.io"

Complete Configuration Examples

Local Development

server:
  host: "127.0.0.1"
  port: 8080
  api_server_url: "http://localhost:8080"
  api_internal_url: "http://localhost:8080"
  api_external_url: "http://localhost:8080"
  use_https: false
  cors_allowed_origins:
    - "http://localhost:8080"
    - "http://localhost:5173"

Docker Development

server:
  host: "0.0.0.0"
  port: 8080
  api_server_url: "http://0.0.0.0:8080"
  api_internal_url: "http://systemprompt:8080"
  api_external_url: "http://localhost:8080"
  use_https: false
  cors_allowed_origins:
    - "http://localhost:8080"
    - "http://localhost:5173"

Production Cloud

server:
  host: "0.0.0.0"
  port: 8080
  api_server_url: "https://api.example.com"
  api_internal_url: "http://app.internal:8080"
  api_external_url: "https://api.example.com"
  use_https: false                    # TLS at load balancer
  cors_allowed_origins:
    - "https://app.example.com"
    - "https://www.example.com"

Validation Rules

Source: crates/shared/models/src/profile/validation.rs:113-133

Required Fields

All server fields are required:

fn validate_required_fields(&self) -> Result<()> {
    if self.server.host.is_empty() {
        return Err(ProfileError::MissingField("server.host"));
    }
    if self.server.port == 0 {
        return Err(ProfileError::InvalidPort);
    }
    if self.server.api_server_url.is_empty() {
        return Err(ProfileError::MissingField("server.api_server_url"));
    }
    if self.server.api_internal_url.is_empty() {
        return Err(ProfileError::MissingField("server.api_internal_url"));
    }
    if self.server.api_external_url.is_empty() {
        return Err(ProfileError::MissingField("server.api_external_url"));
    }
    Ok(())
}

Port Validation

Port must be greater than 0:

if self.server.port == 0 {
    return Err(ProfileError::InvalidPort);
}

Environment Variables

When using Profile::from_env():

Env Variable Maps To
HOST server.host
PORT server.port
API_SERVER_URL server.api_server_url
API_INTERNAL_URL server.api_internal_url
API_EXTERNAL_URL server.api_external_url
USE_HTTPS server.use_https
CORS_ALLOWED_ORIGINS server.cors_allowed_origins (comma-separated)

Config Access

After bootstrap, server config is available via Config struct:

let config = Config::get()?;
println!("Host: {}", config.host);
println!("Port: {}", config.port);
println!("API URL: {}", config.api_server_url);
println!("Internal URL: {}", config.api_internal_url);
println!("External URL: {}", config.api_external_url);
println!("HTTPS: {}", config.use_https);
println!("CORS: {:?}", config.cors_allowed_origins);

Troubleshooting

"Port already in use"

  • Another process is using the port
  • Check with lsof -i :8080
  • Change port or stop conflicting process

"CORS error in browser"

  • Add frontend origin to cors_allowed_origins
  • Check for typos (no trailing slashes)
  • Ensure protocol matches (http vs https)

"Connection refused"

  • Check host is 0.0.0.0 for external access
  • Verify port is not firewalled
  • Check service is running

"Invalid CORS origin"

  • Origin must start with http:// or https://
  • Cannot be empty string
  • No wildcards (*)

"api_internal_url missing"

  • All three URL fields are required
  • Even if same as api_server_url

Quick Reference

Setting Development Production
host 127.0.0.1 0.0.0.0
port 8080 8080
api_server_url http://localhost:8080 https://api.example.com
api_internal_url http://localhost:8080 http://internal:8080
api_external_url http://localhost:8080 https://api.example.com
use_https false false (TLS at LB)
cors_allowed_origins Dev URLs Production domains