Configure your server
The httpserver package provides flexible configuration options through YAML config files. All settings live under httpserver.<name> where <name> is the server name you pass to NewServer.
Default server
The simplest configuration is a single server named "default":
httpserver:
default:
port: 8080
httpserver.RunDefaultServer(func(ctx context.Context, config cfg.Config, logger log.Logger, router *httpserver.Router) error {
router.GET("/ping", handler)
return nil
})
Multiple named servers
You can run multiple HTTP servers in one application, each with its own configuration:
httpserver:
public:
port: 8080
admin:
port: 8090
mode: release
httpserver.RunServers(map[string]httpserver.RouterFactory{
"public": publicDefiner,
"admin": adminDefiner,
})
Or register them individually as module factories:
application.WithModuleFactory("http-public", httpserver.NewServer("public", publicDefiner))
application.WithModuleFactory("http-admin", httpserver.NewServer("admin", adminDefiner))
Full configuration reference
Settings
| Field | Type | Default | Description |
|---|---|---|---|
compression | CompressionSettings | - | Gzip compression settings. |
concurrency | ConcurrencySettings | - | Concurrent request and connection pressure limits. See Concurrency and connection pressure. |
cors | CorsSettings | - | CORS middleware settings. |
errors | ErrorsSettings | - | Error response privacy settings. |
logging | LoggingSettings | - | Request logging settings. |
max_body_bytes | int | 10485760 | Maximum incoming request body size in bytes. 0 disables the limit. |
mode | string | "release" | Gin mode: debug, release, or test. |
port | string | "8080" | Port the server listens on. Use "0" for a random port (useful in tests). |
router | RouterSettings | - | Gin router settings. |
timeout | TimeoutSettings | - | IO timeout settings. |
Compression settings
httpserver:
default:
compression:
level: default
decompression: true
exclude:
path:
- /api/events
extension:
- .png
pathRegex:
- \.json$
| Field | Type | Default | Description |
|---|---|---|---|
decompression | bool | true | Whether to decompress gzip-encoded request bodies. |
exclude | CompressionExcludeSettings | - | Paths/extensions/regexes to exclude from compression. |
level | string | "default" | Compression level: "none", "default", "fast", "best", or "0"–"9". |
Compression exclude settings
| Field | Type | Description |
|---|---|---|
extension | string array | File extensions to exclude (e.g., .png). |
path | string array | Exact paths to exclude (e.g., /api/events). |
pathRegex | string array | Regex patterns to exclude (e.g., \.json$). |
Always exclude SSE endpoints from compression. Gzip buffering will break real-time streaming. See Stream with SSE for details.
CORS settings
httpserver:
default:
cors:
allowed_origin_pattern: "https://example\\.com"
allowed_headers:
- Content-Type
- Authorization
allowed_methods:
- GET
- POST
- PUT
- DELETE
| Field | Type | Description |
|---|---|---|
allowed_headers | string array | Allowed request headers for CORS requests. |
allowed_methods | string array | Allowed HTTP methods for CORS requests. |
allowed_origin_pattern | string | Regular expression matched against the full Origin value. |
Register the package middleware with router.UseFactory(httpserver.CorsFactory). The factory reads httpserver.<name>.cors for the server currently being built.
The origin pattern is anchored internally. For example, https://example\\.com allows https://example.com, but not https://example.com.evil.com.
Error settings
httpserver:
default:
errors:
privacy: private
| Field | Type | Default | Description |
|---|---|---|---|
privacy | string | "private" | Error detail policy for 5xx responses. Use "private" to hide internal details, or "public" to return the original error message. |
With the default private setting, internal 5xx errors return {"err":"internal server error"}. Status errors below 500 still expose their message, so client errors returned through NewErrorWithStatus or GetErrorHandler()(status, err) remain useful to API clients.
Set privacy to public only when exposing internal 5xx error messages is intentional:
httpserver:
default:
errors:
privacy: public
Logging settings
The server logs request metadata by default. Use logging when you need to add selected headers or request bodies to the request log:
httpserver:
default:
logging:
request_body: true
request_body_base64: false
request_headers:
- Content-Type
- X-Correlation-Id
| Field | Type | Default | Description |
|---|---|---|---|
request_body | bool | false | Read and log the full request body as request_body. |
request_body_base64 | bool | false | Base64-encode request_body. Only applies when request_body is enabled. Useful for binary or non-UTF-8 payloads. |
request_headers | string array | [] | Header names to include under request_headers. Only the configured headers are logged. |
Request logs already include standard metadata such as method, path, raw path, query string, status, duration, client IP, host, referer, user agent, response bytes, and compression/request-size fields when available. Incoming X-Request-Id and X-Session-Id headers are also added to the log context automatically when present.
Only enable request body or sensitive header logging deliberately. Request bodies, cookies, authorization headers, API keys, tokens, and query parameters may contain secrets or personal data. Body logging also reads the full request body into memory and can significantly increase log volume. Validation bind errors are logged at warning level and may log invalid field values even when request body logging is disabled; these values are truncated before logging.
Request body size limit
By default, each server limits incoming request bodies to 10 MiB. The limit is applied after request decompression, so compressed uploads are checked by their decompressed size.
httpserver:
default:
max_body_bytes: 10485760
Set max_body_bytes to 0 to disable the limit, or raise it for endpoints that intentionally accept larger bodies.
Router settings
httpserver:
default:
router:
use_raw_path: false
| Field | Type | Default | Description |
|---|---|---|---|
use_raw_path | bool | false | Use Gin's raw escaped URL path for route matching when available. |
By default, Gin matches routes against the decoded request path. Enable use_raw_path only when your routes need to distinguish escaped path segments, for example when %2F should stay part of a path parameter instead of being treated like /.
Timeout settings
httpserver:
default:
timeout:
read: 60s
write: 60s
idle: 60s
drain: 0s
shutdown: 60s
| Field | Type | Default | Description |
|---|---|---|---|
drain | duration | 0s | Time to wait after receiving a shutdown signal before starting graceful shutdown. Useful for load balancer deregistration. |
idle | duration | 60s | Maximum time to wait for the next request when keep-alives are enabled. Minimum 1s. |
read | duration | 60s | Maximum duration for reading the entire request, including the body. Minimum 1s. |
shutdown | duration | 60s | Maximum time for graceful shutdown. Minimum 1s. |
write | duration | 60s | Maximum duration before timing out writes of the response. Minimum 1s. |
For long-running operations, increase the timeouts:
httpserver:
default:
port: 8081
timeout:
read: 10m
write: 10m
Health check server
The health check server runs on a separate port and is useful for load balancer health checks:
httpserver:
default:
port: 8080
The main server automatically registers a /health endpoint. Unhealthy modules are returned as "unhealthy"; underlying error messages are logged but not exposed in the HTTP response. For a separate health check server, the health check module is available separately. See Write health checks for details.
Profiling
Enable Go's built-in profiling endpoints (pprof) on a separate port:
profiling:
enabled: true
api:
port: 8091
When enabled, profiling endpoints are available at /debug/profiling/*. The profiling server binds to 127.0.0.1:<port>.
Graceful shutdown
The httpserver supports graceful shutdown:
- When the application context is cancelled, the server sets its healthy flag to
false - It waits for the
drainduration (useful for load balancer deregistration) - It calls
server.Shutdownwith theshutdowntimeout - In-flight requests are given time to complete
Connection lifecycle
In Kubernetes environments where load balancing only happens on new connections, you can configure the connection lifecycle advisor to periodically close connections:
httpserver:
default:
connection_lifecycle:
enabled: true
max_age: 1m
max_request_count: 0
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable/disable the connection lifecycle advisor. |
max_age | duration | 1m | Maximum age of a connection before it is closed. |
max_request_count | int | 0 | Maximum number of requests per connection. 0 means disabled. |
For full details on connection lifecycle, connection pressure management, and concurrent request limiting, see Concurrency and connection pressure.