Application Settings
Application settings control the core behavior of Portway, including logging, security, rate limiting, and service configuration. These settings are defined in appsettings.json and can be overridden for different environments.
Configuration Files
| File | Purpose | Priority |
|---|---|---|
appsettings.json |
Base configuration | Lowest |
appsettings.Development.json |
Development overrides | Medium |
appsettings.Production.json |
Production overrides | Highest |
| Environment variables | Runtime overrides | Highest |
Core Configuration Structure
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"PathBase": "",
"WebUi": {
"AdminApiKey": "",
"PublicOrigins": [],
"SecureCookies": false
},
"OpenApi": { ... },
"RateLimiting": { ... },
"RequestTrafficLogging": { ... },
"SqlConnectionPooling": { ... }
}Logging Configuration
Portway uses Serilog for structured logging with configurable sinks and filtering.
Basic Structure
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"System": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "log/portwayapi-.log",
"rollingInterval": "Day",
"fileSizeLimitBytes": 10485760,
"rollOnFileSizeLimit": true,
"retainedFileCountLimit": 10,
"buffered": true,
"flushToDiskInterval": "00:00:30"
}
}
]
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}Log Levels
| Level | Description | Use Case |
|---|---|---|
Debug |
Debugging information | Development troubleshooting |
Information |
General flow of events | Normal operations |
Warning |
Abnormal or unexpected events | Potential issues |
Error |
Error events | Application errors |
Fatal |
Critical failures | System failures |
Changing Log Levels
To change the logging level, modify the Default value in appsettings.json:
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug" // Change to Debug, Information, Warning, Error, or Fatal
}
}
}OpenAPI Configuration
Portway generates OpenAPI documentation from your configured endpoints and exposes it through the Scalar UI at /docs.
Full Configuration
{
"OpenApi": {
"Enabled": true,
"BaseProtocol": "https",
"Title": "Portway: API Gateway",
"Version": "v1",
"Description": "This is Portway. A lightweight API gateway designed to integrate your platforms with your Windows environment. It provides a simple, fast and efficient way to connect various data sources and services.",
"Contact": {
"Name": "Jay Doe (Demo Company)",
"Email": "support@democompany.local"
},
"Footer": {
"Text": "Powered by Scalar",
"Target": "_blank",
"Url": "#"
},
"SecurityDefinition": {
"Name": "Bearer",
"Description": "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
"In": "Header",
"Type": "ApiKey",
"Scheme": "Bearer"
},
"ScalarTheme": "default",
"ScalarLayout": "modern",
"ScalarShowSidebar": true,
"ScalarHideDownloadButton": true,
"ScalarHideModels": true,
"ScalarHideClientButton": true,
"ScalarHideTestRequestButton": false
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | true |
Enable/disable API documentation |
BaseProtocol |
string | "https" |
Protocol for API base URLs |
Title |
string | - | Main title displayed in documentation |
Version |
string | "v1" |
API version identifier |
Description |
string | - | Main description (supports markdown) |
Contact |
object | - | Contact information for API support |
Footer |
object | - | Footer text shown in Scalar |
SecurityDefinition |
object | - | Authentication method configuration |
ScalarTheme |
string | "default" |
Scalar theme: "default", "alternate", "moon", "purple", "solarized" |
ScalarLayout |
string | "modern" |
Scalar layout: "modern", "classic" |
ScalarShowSidebar |
boolean | true |
Display navigation sidebar |
ScalarHideDownloadButton |
boolean | true |
Hide OpenAPI spec download button |
ScalarHideModels |
boolean | true |
Hide data models section |
ScalarHideClientButton |
boolean | true |
Hide client generation button |
ScalarHideTestRequestButton |
boolean | false |
Hide test request button |
Rate Limiting Configuration
Configuration Structure
{
"RateLimiting": {
"Enabled": true,
"IpLimit": 100,
"IpWindow": 60,
"TokenLimit": 100,
"TokenWindow": 60
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | true |
Enable rate limiting |
IpLimit |
integer | 100 |
Requests per IP |
IpWindow |
integer | 60 |
Time window in seconds |
TokenLimit |
integer | 100 |
Requests per token |
TokenWindow |
integer | 60 |
Time window in seconds |
Rate Limiting Behavior
- IP-based limiting applies to all requests
- Token-based limiting applies per authentication token
- Exceeding limits results in 429 Too Many Requests
- Limits reset after the time window expires
Request Traffic Logging
Full Configuration
{
"RequestTrafficLogging": {
"Enabled": false,
"QueueCapacity": 10000,
"StorageType": "file",
"SqlitePath": "log/traffic_logs.db",
"LogDirectory": "log/traffic",
"MaxFileSizeMB": 50,
"MaxFileCount": 5,
"FilePrefix": "proxy_traffic_",
"BatchSize": 100,
"FlushIntervalMs": 1000,
"IncludeRequestBodies": false,
"IncludeResponseBodies": false,
"MaxBodyCaptureSizeBytes": 4096,
"CaptureHeaders": true,
"EnableInfoLogging": true
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | false |
Enable traffic logging |
QueueCapacity |
integer | 10000 |
Log queue size |
StorageType |
string | "file" |
Storage type: "file" or "sqlite" |
SqlitePath |
string | "log/traffic_logs.db" |
SQLite database path |
LogDirectory |
string | "log/traffic" |
Log file directory |
MaxFileSizeMB |
integer | 50 |
Maximum log file size |
MaxFileCount |
integer | 5 |
Maximum log files |
FilePrefix |
string | "proxy_traffic_" |
Log file prefix |
BatchSize |
integer | 100 |
Batch write size |
FlushIntervalMs |
integer | 1000 |
Flush interval (ms) |
IncludeRequestBodies |
boolean | false |
Log request bodies |
IncludeResponseBodies |
boolean | false |
Log response bodies |
MaxBodyCaptureSizeBytes |
integer | 4096 |
Max body size to log |
CaptureHeaders |
boolean | true |
Log request headers |
EnableInfoLogging |
boolean | true |
Enable info-level logs |
SQL Connection Pooling
Configuration Structure
{
"SqlConnectionPooling": {
"ApplicationName": "Portway API - Remote integration gateway",
"MinPoolSize": 5,
"MaxPoolSize": 100,
"ConnectionTimeout": 15,
"CommandTimeout": 30,
"Enabled": true
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
ApplicationName |
string | - | Application identifier |
MinPoolSize |
integer | 5 |
Minimum pool connections |
MaxPoolSize |
integer | 100 |
Maximum pool connections |
ConnectionTimeout |
integer | 15 |
Connection timeout (seconds) |
CommandTimeout |
integer | 30 |
Command timeout (seconds) |
Enabled |
boolean | true |
Enable connection pooling |
Caching Configuration
Portway caches proxy and SQL responses in memory or Redis to reduce upstream load and improve response times.
Configuration Structure
{
"Caching": {
"Enabled": true,
"DefaultCacheDurationSeconds": 300,
"ProviderType": "Memory",
"MemoryCacheMaxItems": 10000,
"MemoryCacheSizeLimitMB": 100,
"CacheableContentTypes": [
"application/json",
"text/json"
],
"EndpointCacheDurations": {
"Products": 600,
"Customers": 300
},
"Redis": {
"ConnectionString": "localhost:6379",
"InstanceName": "Portway:",
"Database": 0,
"UseSsl": false,
"ConnectTimeoutMs": 5000,
"AbortOnConnectFail": false,
"FallbackToMemoryCache": true,
"MaxRetryAttempts": 3,
"RetryDelayMs": 200
}
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | true |
Enable response caching |
DefaultCacheDurationSeconds |
integer | 300 |
Default TTL for cached responses |
ProviderType |
string | "Memory" |
Cache backend: "Memory" or "Redis" |
MemoryCacheMaxItems |
integer | 10000 |
Maximum number of items in the memory cache |
MemoryCacheSizeLimitMB |
integer | 100 |
Memory cap for the cache in MB |
CacheableContentTypes |
array | ["application/json", ...] |
Only responses with these content types are cached |
EndpointCacheDurations |
object | {} |
Per-endpoint TTL overrides keyed by endpoint name |
Redis Properties
| Property | Type | Default | Description |
|---|---|---|---|
ConnectionString |
string | "localhost:6379" |
Redis connection string |
InstanceName |
string | "Portway:" |
Key prefix to namespace cache entries |
Database |
integer | 0 |
Redis logical database index |
UseSsl |
boolean | false |
Use TLS for the Redis connection |
ConnectTimeoutMs |
integer | 5000 |
Connection timeout in milliseconds |
AbortOnConnectFail |
boolean | false |
Throw on connection failure instead of retrying |
FallbackToMemoryCache |
boolean | true |
Fall back to in-process memory cache if Redis is unavailable |
MaxRetryAttempts |
integer | 3 |
Retry attempts on transient Redis errors |
RetryDelayMs |
integer | 200 |
Delay between retry attempts in milliseconds |
File Storage Configuration
Controls how Portway stores and serves files for File-type endpoints.
Configuration Structure
{
"FileStorage": {
"StorageDirectory": "storage/files",
"MaxFileSizeBytes": 52428800,
"UseMemoryCache": true,
"MemoryCacheTimeSeconds": 60,
"MaxTotalMemoryCacheMB": 200,
"BlockedExtensions": [".exe", ".dll", ".bat", ".sh", "..."]
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
StorageDirectory |
string | "storage/files" |
Directory where uploaded files are stored |
MaxFileSizeBytes |
integer | 52428800 |
Maximum upload size (default 50 MB) |
UseMemoryCache |
boolean | true |
Cache frequently accessed files in memory |
MemoryCacheTimeSeconds |
integer | 60 |
How long a file stays in the memory cache |
MaxTotalMemoryCacheMB |
integer | 200 |
Total memory budget for the file cache |
BlockedExtensions |
array | [".exe", ".dll", ...] |
File extensions that are refused on upload |
INFO
The default block list covers executable, script, and macro-enabled office formats. Extend it to suit your security policy; shrink it only with caution.
Endpoint Reloading Configuration
Controls hot-reload behaviour when endpoint JSON files change on disk.
Configuration Structure
{
"EndpointReloading": {
"Enabled": true,
"DebounceMs": 2000,
"LogLevel": "Information"
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | true |
Watch endpoint files and reload on change without restart |
DebounceMs |
integer | 2000 |
Minimum milliseconds between reloads for the same file (prevents double-fires from editors) |
LogLevel |
string | "Information" |
Log level for reload events ("Debug", "Information", "Warning") |
Telemetry
Controls OpenTelemetry export over OTLP (gRPC). Disabled by default — no collector connection is attempted unless Enabled is true.
| Field | Required | Type | Description |
|---|---|---|---|
Enabled |
No | boolean | Activates OTLP export. Defaults to false |
OtlpEndpoint |
No | string | gRPC endpoint of your OTLP collector. Defaults to http://localhost:4317 |
ServiceName |
No | string | Service name reported to the collector. Defaults to Portway.Api |
ResourceAttributes |
No | string | Comma-separated key=value pairs attached as resource attributes |
"Telemetry": {
"Enabled": true,
"OtlpEndpoint": "http://otel-collector.internal:4317",
"ServiceName": "portway-prod",
"ResourceAttributes": "deployment.environment=production,host.name=gw01"
}ResourceAttributes follows the same key=value,key=value format as the OTEL_RESOURCE_ATTRIBUTES environment variable. Environment variables with the OTEL_ prefix still override appsettings.json values when set, following standard .NET configuration precedence.
MCP Configuration
Controls the Model Context Protocol server and built-in Chat feature.
Configuration Structure
{
"Mcp": {
"Enabled": true,
"Path": "/mcp",
"RequireAuthentication": true,
"AppsEnabled": true,
"ChatEnabled": false,
"DefaultPageSize": 50,
"MaxPageSize": 200,
"ToolTimeoutSeconds": 30,
"MaxToolResultChars": 12000
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
boolean | false |
Activate the MCP HTTP server |
Path |
string | "/mcp" |
HTTP path the MCP server is mounted on |
RequireAuthentication |
boolean | true |
Require a valid Portway Bearer token on MCP requests |
AppsEnabled |
boolean | true |
Register embedded UI resources as MCP resource URIs |
ChatEnabled |
boolean | false |
Activate the Chat UI and SSE endpoint. Provider and credentials are configured via the setup wizard, not in this file |
DefaultPageSize |
integer | 50 |
Rows added as $top when the AI model omits a page size |
MaxPageSize |
integer | 200 |
Maximum $top value; the server clamps higher values to this limit |
ToolTimeoutSeconds |
integer | 30 |
HTTP timeout for internal tool-execution calls |
MaxToolResultChars |
integer | 12000 |
Maximum characters kept from a single tool result; longer results are truncated |
INFO
Chat credentials (provider, model, API key) are stored in the encrypted mcp.db database and managed through the Chat setup wizard. They are not configured in appsettings.json. An environment variable PORTWAY_CHAT_API_KEY can be used instead of the database entry; it takes precedence if set.
Log Settings
Configuration Structure
{
"LogSettings": {
"LogResponseToFile": false
}
}| Property | Type | Default | Description |
|---|---|---|---|
LogResponseToFile |
boolean | false |
Write raw response bodies to the log file (useful for debugging; disable in production) |
General Settings
AllowedHosts
{
"AllowedHosts": "*"
}Configure which hosts can access the application:
"*"- Allow all hosts"example.com"- Allow specific domain"*.example.com"- Allow subdomains"example.com;api.example.com"- Multiple hosts
PathBase
{
"PathBase": ""
}Base path for the application (e.g., /api).
Web UI Configuration
The built-in admin interface settings.
{
"WebUi": {
"AdminApiKey": "your-secure-password",
"PublicOrigins": ["https://example.com"],
"SecureCookies": true,
"EnableLandingPage": true
}
}Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
AdminApiKey |
string | "" |
Password for web UI login (empty = disabled) |
PublicOrigins |
array | [] |
Allowed CORS origins for external access |
SecureCookies |
boolean | false |
Require HTTPS for auth cookies |
EnableLandingPage |
boolean | true |
Show the landing page at / for local/allowed clients. Set to false to redirect all root requests straight to /docs (useful for production systems where the UI should not be discoverable). |
Customization.PromoText |
string | "" |
Markdown banner shown at the top of the login page |
Customization.PromoLogin |
boolean | false |
Allow the promo-bar to be shown at /login |
Customization.LoginFooter |
string | "" |
Markdown text shown below the login form |
Security
- Without
AdminApiKey, the web UI is disabled - Without
PublicOrigins, only local network IPs can access the UI - Cookie auth uses HMAC-SHA256 signing
- Set
EnableLandingPage: falseon internet-facing or production deployments to prevent the admin UI from being surfaced at the root path
Customization Example
{
"WebUi": {
"Customization": {
"PromoText": "Welcome to **Portway**. Check the [documentation](https://github.com/melosso/portway) to get started.",
"LoginFooter": "No account? Contact your [administrator](mailto:admin@example.com)."
}
}
}Both fields support standard Markdown (bold, links, inline code).
Environment-Specific Configuration
Development Settings
appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
},
"RequestTrafficLogging": {
"Enabled": true,
"IncludeRequestBodies": true,
"IncludeResponseBodies": true
}
}Production Settings
appsettings.Production.json:
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"PortwayApi": "Information"
}
},
"RateLimiting": {
"IpLimit": 200,
"TokenLimit": 1000
},
"AllowedHosts": "api.company.com"
}Security Settings
CORS Configuration
CORS is configured to allow all origins in the default configuration:
{
"AllowedHosts": "*"
}For production, restrict to specific domains:
{
"AllowedHosts": "api.company.com;app.company.com"
}Performance Tuning
Connection Pool Optimization
{
"SqlConnectionPooling": {
"MinPoolSize": 10,
"MaxPoolSize": 200,
"ConnectionTimeout": 30,
"CommandTimeout": 60,
"Enabled": true
}
}Rate Limiting for High Traffic
{
"RateLimiting": {
"Enabled": true,
"IpLimit": 500,
"IpWindow": 60,
"TokenLimit": 5000,
"TokenWindow": 60
}
}Traffic Logging for Debugging
{
"RequestTrafficLogging": {
"Enabled": true,
"StorageType": "sqlite",
"IncludeRequestBodies": true,
"IncludeResponseBodies": true,
"MaxBodyCaptureSizeBytes": 8192
}
}Environment Variables
Common Variables
| Variable | Description | Example |
|---|---|---|
PORTWAY_ENCRYPTION_KEY |
Encryption secret | (Hardcoded) |
PORTWAY_CHAT_API_KEY |
AI provider API key for Chat. Takes precedence over the encrypted database entry when set. | sk-ant-... |
Use_HTTPS |
Whether Kestrel serves HTTPS directly (see note) | false |
KEYVAULT_URI |
Azure Key Vault URI | https://vault.azure.net |
PROXY_USERNAME |
Proxy authentication user | domain\user |
PROXY_PASSWORD |
Proxy authentication password | password |
PROXY_DOMAIN |
Proxy domain | CONTOSO |
AllowedHosts |
Allowed host names | * |
PathBase |
Base path | /api |
Mcp__ChatEnabled |
Override Mcp:ChatEnabled at runtime |
true |
WebUi__AdminApiKey |
Web UI password | secret |
WebUi__PublicOrigins__0 |
CORS origin (array) | https://example.com |
WebUi__SecureCookies |
Secure cookies | true |
WebUi__EnableLandingPage |
Show landing page at root | false |
WARNING
Use_HTTPS=true requires a TLS certificate reachable by Kestrel. Without one the container fails immediately at startup with BackgroundService failed / Hosting failed to start. In Docker deployments where an external reverse proxy (nginx, Caddy, Cloudflare Tunnel, etc.) handles SSL termination, leave this unset or set it to false. Only enable it when Portway is directly internet-facing and a certificate is supplied (e.g. via Kestrel__Certificates__Default__Path).
Configuration Priority
- Environment variables
appsettings.{Environment}.jsonappsettings.json- Default values
Troubleshooting Configuration
Common Issues
Application Won't Start
- Check JSON syntax in appsettings files
- Verify required environment variables
- Review startup logs
Database Connection Failures
- Verify connection strings
- Check SQL Server availability
- Review firewall settings
Rate Limiting Too Restrictive
- Adjust IpLimit and TokenLimit
- Increase time windows
- Monitor traffic patterns
Logging Not Working
- Check log file permissions
- Verify log directory exists
- Review LogLevel settings
Configuration Debugging
- Enable detailed logging:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information"
}
}
}- Check environment variable:
echo %ASPNETCORE_ENVIRONMENT%- Review startup logs for configuration issues
Complete Example Configuration
Production appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
},
"AllowedHosts": "api.company.com",
"OpenApi": {
"Enabled": true,
"BaseProtocol": "https",
"Title": "Company API Gateway",
"Version": "v1",
"Description": "Production API Gateway",
"Contact": {
"Name": "API Support",
"Email": "api-support@company.com"
},
"SecurityDefinition": {
"Name": "Bearer",
"Description": "Enter 'Bearer' [space] and then your token",
"In": "Header",
"Type": "ApiKey",
"Scheme": "Bearer"
}
},
"RateLimiting": {
"Enabled": true,
"IpLimit": 200,
"IpWindow": 60,
"TokenLimit": 2000,
"TokenWindow": 60
},
"RequestTrafficLogging": {
"Enabled": false,
"StorageType": "sqlite",
"SqlitePath": "log/traffic.db",
"CaptureHeaders": true,
"IncludeRequestBodies": false,
"IncludeResponseBodies": false
},
"SqlConnectionPooling": {
"ApplicationName": "Company API Gateway",
"MinPoolSize": 10,
"MaxPoolSize": 150,
"ConnectionTimeout": 30,
"CommandTimeout": 30,
"Enabled": true
}
}Related Topics
- Environment Settings - Environment-specific configuration
- Security Guide - Security configuration
- Deployment Guide - Production deployment
- Logging - Logging configuration