Deployment
Deploy Suave applications to production with various hosting strategies.
Building for Production
Prepare your Suave application for production deployment:
// Build in Release mode
dotnet build -c Release
// Publish for standalone deployment
dotnet publish -c Release -o ./publish
// Create self-contained deployment
dotnet publish -c Release -o ./publish \
--self-contained true \
-r linux-x64
Docker Deployment
Deploy Suave in Docker containers:
# Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS builder
WORKDIR /build
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app
COPY --from=builder /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "Suave.Website.dll"]
Docker Compose Setup
Manage Suave with Docker Compose:
version: '3.8'
services:
suave:
build: .
ports:
- "8080:8080"
environment:
ASPNETCORE_ENVIRONMENT: Production
SUAVE_PORT: 8080
SUAVE_IP: 0.0.0.0
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- suave
Linux Systemd Service
Run Suave as a systemd service:
# /etc/systemd/system/suave.service
[Unit]
Description=Suave Web Application
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/suave
ExecStart=/usr/bin/dotnet /opt/suave/Suave.Website.dll
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
# Commands to manage the service
sudo systemctl enable suave
sudo systemctl start suave
sudo systemctl status suave
sudo systemctl restart suave
IIS Hosting
Host Suave on IIS with ASP.NET Core Module:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\Suave.Website.dll"
stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout" />
</system.webServer>
</location>
</configuration>
Nginx Reverse Proxy
Use Nginx as a reverse proxy for Suave:
upstream suave {
server localhost:8080;
server localhost:8081;
server localhost:8082;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://suave;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# WebSocket support
location /ws {
proxy_pass http://suave;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
HTTPS/SSL Configuration
Configure HTTPS in Suave for production:
open System.Security.Cryptography.X509Certificates
open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
let cert = new X509Certificate2("/etc/ssl/certs/server.pfx", "password")
let httpsConfig =
{ defaultConfig with
bindings = [
HttpBinding.createSimple HTTP "0.0.0.0" 80
HttpBinding.createSimple (HTTPS cert) "0.0.0.0" 443
]
}
let app =
choose [
path "/" >=> OK "Hello World"
]
[<EntryPoint>]
let main argv =
startWebServer httpsConfig app
0
Environment Configuration
Configure Suave for different environments:
open Suave
open Suave.Operators
open System
let getConfig () =
let env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")
let port =
match Environment.GetEnvironmentVariable("SUAVE_PORT") with
| null -> 8080
| p -> int p
let config =
{ defaultConfig with
bindings = [HttpBinding.createSimple HTTP "0.0.0.0" port]
}
match env with
| "Production" ->
{ config with bufferSize = 4096; maxOps = 10000 }
| "Development" ->
{ config with bufferSize = 2048 }
| _ -> config
[<EntryPoint>]
let main argv =
startWebServer (getConfig ()) app
0
Load Balancing
Scale Suave with multiple instances:
# docker-compose with load balancing
version: '3.8'
services:
suave1:
build: .
ports:
- "8081:8080"
environment:
SUAVE_PORT: 8080
suave2:
build: .
ports:
- "8082:8080"
environment:
SUAVE_PORT: 8080
suave3:
build: .
ports:
- "8083:8080"
environment:
SUAVE_PORT: 8080
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx-lb.conf:/etc/nginx/nginx.conf:ro
depends_on:
- suave1
- suave2
- suave3
Monitoring and Logging
Monitor Suave applications in production:
open Suave
open Suave.Operators
open System
let monitoredConfig =
{ defaultConfig with
bindings = [HttpBinding.createSimple HTTP "0.0.0.0" 8080]
maxOps = 1000
}
let loggingMiddleware =
fun (ctx: HttpContext) ->
async {
let startTime = System.DateTime.UtcNow
printfn "[%s] %s %s"
(startTime.ToString("yyyy-MM-dd HH:mm:ss"))
ctx.request.method
ctx.request.path
let! result = ctx.request.rawForm |> Async.AwaitTask
let duration = System.DateTime.UtcNow - startTime
printfn "[Response] %s %s - %dms"
ctx.request.method
ctx.request.path
(int duration.TotalMilliseconds)
return result
}
let app =
choose [
path "/" >=> OK "Hello World"
]
[<EntryPoint>]
let main argv =
startWebServer monitoredConfig (loggingMiddleware >=> app)
0
Performance Tuning
Optimize Suave for high performance:
open Suave
// Production-optimized configuration
let productionConfig =
{ defaultConfig with
bindings = [HttpBinding.createSimple HTTP "0.0.0.0" 8080]
// Increase concurrent operations
maxOps = 10000
// Optimize buffer sizes
bufferSize = 8192
// Connection settings
exposeServerHeader = false
// Keep-alive timeout
homeFolder = Some (System.IO.Directory.GetCurrentDirectory())
// Cancellation token timeout
cancellationToken = System.Threading.CancellationToken.None
}
[<EntryPoint>]
let main argv =
let config = productionConfig
startWebServer config app
0