Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Status Release License Language

Dito is an advanced, highly extensible reverse proxy server written in Go. It features a robust plugin-based architecture, custom certificate handling for backend connections, dynamic configuration reloading, and more. Plugins can manage their own dependencies and provide custom middleware functionality.

The official project repository is available on GitHub.

Features

  • Layer 7 Reverse Proxy: Handles HTTP and HTTPS requests efficiently.
  • WebSockets Support: Proxy WebSocket connections with ease.
  • Dynamic Configuration Reloading: Update configurations without restarting the server.
  • Extensible Plugin System: Enhance Dito with custom Go plugins for authentication, caching, rate limiting, request/response transformation, custom logging and more.
  • Plugin Security: Plugins are signed with Ed25519 keys and verified at startup.
  • Custom TLS Certificate Management: Support for mTLS and custom certificates for backend connections.
  • Header Manipulation: Add or remove HTTP headers as needed.
  • Advanced Logging: Asynchronous logging with customizable verbosity and performance optimizations.
  • Custom Transport Configuration: Fine-tune HTTP transport settings per location or globally.
  • Response Body Size Limits: Control maximum response body sizes globally and per location with proper error handling.
  • Response Buffering Control: Enable or disable response buffering per location for optimal performance.
  • Prometheus Metrics: Monitor performance and behavior with detailed metrics.

Project Structure

dito/
├── cmd/                   # Entry points (main application & plugin-signer)
├── app/                   # Core application logic
├── config/                # Configuration loader & hot-reload
├── handlers/              # Request routing & proxy handlers
├── middlewares/           # Built-in middlewares (plugins can add more)
├── plugin/                # Plugin loading, signing, and verification
├── plugins/               # Plugin implementations
├── transport/             # HTTP transport configuration
├── websocket/             # WebSocket proxy support
├── writer/                # Response writers and buffering
├── metrics/               # Prometheus metrics
├── logging/               # Structured logging
├── deployments/           # Deployment configurations
│   ├── kubernetes/        # Basic Kubernetes deployments
│   ├── openshift/         # OpenShift production deployments
│   └── docker/            # Docker Compose for development
├── configs/               # Configuration files and templates
│   └── templates/         # Configuration templates
├── scripts/               # Deployment and utility scripts
├── bin/                   # Built binaries and runtime files
├── plugins/               # Example and community plugins
├── transport/             # HTTP transport customization
├── websockets/            # WebSocket support
├── writer/                # Custom response writers
├── logging/               # Logging utilities
└── metrics/               # Prometheus metrics collection

Installation

Ensure you have Go 1.21+ and make installed.

Quick Start

# Clone repo
git clone https://github.com/andrearaponi/dito.git && cd dito

# One-command setup & start
make quick-start

This will build binaries, generate keys, sign plugins, update configuration and start the server.

Step-by-Step

# 1. Clone repo
git clone https://github.com/andrearaponi/dito.git && cd dito

# 2. Setup (build, keys, plugins, config)
make setup

# 3. Start server
make run

Makefile Commands

CategoryCommandDescription
Quickquick-startClean, setup everything and start
setupFull development setup (build, keys, plugins, config)
setup-prodFull production setup (persistent keys, prod config)
runStart the Dito server
fix-configQuick command to fix configuration after setup
BuildbuildBuild Dito binary only
build-pluginsBuild all plugins
build-plugin-signerBuild plugin-signer tool
Securitygenerate-keysGenerate Ed25519 key pair for development
generate-prod-keysGenerate persistent Ed25519 key pair for production
sign-pluginsSign all plugins with development keys
sign-plugins-prodSign all plugins with production keys
update-configUpdate bin/config.yaml with development key paths/hashes
update-prod-configUpdate bin/config-prod.yaml with production key paths/hashes
update-k8s-configCreate configs/config-prod-k8s.yaml for Kubernetes deployment
OpenShiftdeploy-ocpComplete OpenShift production deployment
deploy-ocp-devQuick development deployment to OpenShift
status-ocpCheck OpenShift deployment status
logs-ocpView OpenShift deployment logs
clean-ocpClean up OpenShift resources
Debugdebug-configDebug configuration issues
helpShow all commands
CleanupcleanRemove build artifacts
clean-pluginsClean plugin binaries only
DevelopmenttestRun tests
vetRun go vet
fmtFormat code
sonarRun SonarQube analysis

Manual Installation

  1. Build Dito
    go build -o bin/dito ./cmd/dito/main.go
    
  2. Build plugin-signer
    cd cmd/plugin-signer && go build -o ../../bin/plugin-signer . && cd ../..
    
  3. Generate keys
    ./bin/plugin-signer generate-keys
    
  4. Build plugins
    find plugins -mindepth 1 -maxdepth 1 -type d -exec sh -c 'cd "$1" && go build -buildmode=plugin -o "$(basename "$1").so"' sh {} \;
    
  5. Sign plugins
    find plugins -name "*.so" -exec ./bin/plugin-signer sign {} \;
    
  6. Update configuration Ensure public_key_path and public_key_hash in config.yaml are correct.
  7. Run Dito
    ./bin/dito
    

Usage

Start the server with the default configuration:

make run

Or directly:

./bin/dito -f /path/to/custom-config.yaml -enable-profiler

Configuration File

  • Template: cmd/config.yaml
  • Runtime: bin/config.yaml

Example configuration:

port: '8081'
hot_reload: true
metrics:
  enabled: true
  path: "/metrics"
logging:
  enabled: true
  verbose: false
  level: "info"
plugins:
  directory: "./plugins"
  public_key_path: "./ed25519_public.key"
  public_key_hash: "<SHA256_HASH>"
transport:
  http:
    idle_conn_timeout: 90s
    max_idle_conns: 1000
    max_idle_conns_per_host: 200
    max_conns_per_host: 0
    tls_handshake_timeout: 2s
    response_header_timeout: 2s
    expect_continue_timeout: 500ms
    disable_compression: false
    dial_timeout: 2s
    keep_alive: 30s
    force_http2: true
locations:
  - path: "^/test-ws$"
    target_url: "wss://echo.websocket.org"
    enable_websocket: true
    replace_path: true
  - path: "^/dito$"
    target_url: "https://httpbin.org/get"
    replace_path: true
    transport:
      http:
        disable_compression: true
    additional_headers:
      X-Custom: "true"
    excluded_headers:
      - Cookie
    middlewares:
      - hello-plugin

Response Limits

Dito allows configuring maximum response body sizes globally and per location.

Global Limits

response_limits:
  max_response_body_size: 100000 # 100KB default limit

Per-Location Limits

locations:
  - path: "^/api/small"
    target_url: "https://api.example.com"
    max_response_body_size: 1024
    disable_response_buffering: false
  - path: "^/api/large"
    target_url: "https://api.example.com"
    max_response_body_size: 52428800
    disable_response_buffering: true

Features

  • Automatic 413 status code when limits are exceeded
  • JSON error responses with details
  • Early detection using Content-Length
  • Works with buffered and streaming responses
  • Logging when limits are exceeded
  • Limits can be updated via hot reload

Error Format

{
  "error": {
    "code": 413,
    "message": "Response body size exceeds limit",
    "details": {
      "limit_bytes": 90,
      "path": "/api/endpoint"
    }
  }
}

Buffering Control

  • false (default): responses buffered in memory
  • true: responses streamed directly to the client

Plugin System

Dito uses Go plugins (.so files). Each plugin should be placed in its own subdirectory under plugins/ and typically contains the compiled plugin (<name>.so), a signature file and an optional config.yaml.

Signing & Verification

Plugin signing is mandatory and uses Ed25519 keys.

  1. Generate key pair
    ./bin/plugin-signer generate-keys -privateKey ed25519_private.key -publicKey ed25519_public.key
    
  2. Compute public key hash
    shasum -a 256 ed25519_public.key | awk '{print $1}'
    
  3. Update config.yaml with the public_key_path and computed hash.
  4. Sign plugin
    ./bin/plugin-signer sign -plugin path/to/plugin.so -privateKey path/to/ed25519_private.key
    

Troubleshooting

  • public key integrity validation failed: regenerate the hash and update the configuration.
  • failed to read public key: verify the path and file permissions.
  • plugin signature verification failed: re-sign with the correct key pair.

Custom Transport Configuration

Customize how Dito connects to backend services.

  • Timeouts and Connection Limits: adjust to match backend behavior.
  • TLS Settings: manage handshake timeouts and enforce HTTP/2 if needed.
  • Custom Certificates: specify client certificates for mTLS backends.

WebSocket Support

Add enable_websocket: true to a location to proxy WebSocket connections.

locations:
  - path: "^/test-ws$"
    target_url: "wss://echo.websocket.org"
    enable_websocket: true
    replace_path: true

Upcoming Enhancements

Future versions will provide enhanced TLS control, improved error handling and detailed metrics for WebSocket traffic.

TLS/SSL

Support for mTLS is built in. Specify cert_file, key_file and ca_file to secure backend connections.

Metrics

Dito exposes Prometheus metrics to monitor performance and behaviour.

Available Metrics

  • http_requests_total – total number of HTTP requests processed
  • http_request_duration_seconds – duration histogram
  • active_connections – number of active connections
  • data_transferred_bytes_total – bytes transferred
  • Standard Go runtime and promhttp metrics

Configuration

Enable metrics in config.yaml:

metrics:
   enabled: true
   path: "/metrics"

Reporting Issues

  1. Go Version – include the output of go version.
  2. Error Details – provide the error message, steps to reproduce and any logs.
  3. Configuration File – attach the config.yaml used when the issue occurred.

Contributing

  1. Fork the repository.
  2. Create your branch: git checkout -b feature/AmazingFeature.
  3. Commit your changes.
  4. Push to the branch.
  5. Open a pull request.

Containerization & OpenShift Deployment

Dito is containerized and optimized for OpenShift.

Quick Deployment

chmod +x scripts/deploy-ocp.sh
./scripts/deploy-ocp.sh

Custom namespace and version:

./scripts/deploy-ocp.sh -n my-dito -v latest

Other options include force key regeneration (-f), configuration only (-c) or deploy only (-d).

Manual Deployment Steps

1. Build and Push Container Image

./docker-build.sh

2. Generate Production Keys

make generate-prod-keys

3. Create OpenShift Resources

oc new-project dito
oc create secret generic dito-keys \
    --from-file=ed25519_public.key=bin/ed25519_public_prod.key \
    --from-file=ed25519_private.key=bin/ed25519_private_prod.key

HASH=$(shasum -a 256 bin/ed25519_public_prod.key | awk '{print $1}')
sed "s/PLACEHOLDER_HASH_TO_BE_REPLACED/$HASH/" configs/templates/application.yaml > configs/config-prod-k8s.yaml

oc create configmap dito-config \
    --from-file=config.yaml=configs/config-prod-k8s.yaml

4. Deploy Application

oc apply -f deployments/openshift/production-deployment.yaml

Deployment Models

FileUse CaseFeatures
deployments/kubernetes/basic-deployment.yamlBasic deploymentSimple setup
deployments/openshift/production-deployment.yamlProduction deploymentPlugin signing, proper secrets, health checks

Security Features

Container Security

  • Non-root execution (user ID 1001)
  • Read-only root filesystem
  • Dropped capabilities
  • OpenShift security contexts

Key Management

  • External key generation
  • Runtime plugin signing
  • Secure secret mounting
  • Proper file permissions

Configuration Management

Dito supports template-based configs, environment-specific configs and hot reload via ConfigMaps. See configs/README.md for details.

License

This project is licensed under the Apache License 2.0. See the LICENSE file for details.