Configuration Guide

Overview

Weber uses JSON-based configuration files to manage settings across different environments. This approach allows you to easily customize behavior for development, testing, and production environments.

Configuration Files

Configuration files are stored in the config/ directory:

config/
├── dev.json      # Development environment
├── test.json     # Testing environment
└── prod.json     # Production environment

Selecting Environment

Set the environment using the WEBER_ENV variable:

# Development
export WEBER_ENV=dev

# Production
export WEBER_ENV=prod

# Testing
export WEBER_ENV=test

Configuration Structure

Complete Example

{
    "server": {
        "port": 8080,
        "host": "localhost",
        "debug": true,
        "read_timeout": 30,
        "write_timeout": 30
    },
    "database": {
        "driver": "postgres",
        "host": "localhost",
        "port": 5432,
        "name": "weber_db",
        "user": "weber",
        "password": "password",
        "ssl_mode": "disable",
        "max_open_conns": 25,
        "max_idle_conns": 5
    },
    "cache": {
        "enabled": true,
        "driver": "memory",
        "ttl": 3600,
        "max_size": 100
    },
    "logging": {
        "level": "debug",
        "output": "stdout",
        "file": "logs/app.log",
        "max_size": 100,
        "max_backups": 3,
        "max_age": 28
    },
    "templates": {
        "path": "./webroot",
        "cache": true,
        "reload": false
    },
    "static": {
        "path": "./webroot/static",
        "url_prefix": "/static",
        "max_age": 31536000
    },
    "api": {
        "news_endpoint": "https://api.example.com/news",
        "football_endpoint": "https://api.example.com/football",
        "api_key": "your-api-key",
        "timeout": 10,
        "retry_attempts": 3
    },
    "cors": {
        "enabled": true,
        "allowed_origins": ["http://localhost:3000"],
        "allowed_methods": ["GET", "POST", "PUT", "DELETE"],
        "allowed_headers": ["Content-Type", "Authorization"],
        "max_age": 86400
    },
    "session": {
        "secret": "change-this-secret-key",
        "cookie_name": "weber_session",
        "max_age": 86400,
        "secure": false,
        "http_only": true
    },
    "oauth": {
        "google": {
            "client_id": "your-client-id",
            "client_secret": "your-client-secret",
            "redirect_url": "http://localhost:8080/auth/google/callback"
        }
    }
}

Server Configuration

Development (dev.json)

{
    "server": {
        "port": 8080,
        "host": "localhost",
        "debug": true,
        "read_timeout": 30,
        "write_timeout": 30
    }
}

Production (prod.json)

{
    "server": {
        "port": 80,
        "host": "0.0.0.0",
        "debug": false,
        "read_timeout": 15,
        "write_timeout": 15
    }
}

Configuration Options

  • port - Server port (default: 8080)
  • host - Server host (default: localhost)
  • debug - Enable debug mode (default: false)
  • read_timeout - HTTP read timeout in seconds
  • write_timeout - HTTP write timeout in seconds

Database Configuration

{
    "database": {
        "driver": "postgres",
        "host": "localhost",
        "port": 5432,
        "name": "weber_db",
        "user": "weber",
        "password": "password",
        "ssl_mode": "disable",
        "max_open_conns": 25,
        "max_idle_conns": 5,
        "conn_max_lifetime": 300
    }
}

Options

  • driver - Database driver (postgres, mysql, sqlite)
  • host - Database host
  • port - Database port
  • name - Database name
  • user - Database user
  • password - Database password
  • ssl_mode - SSL mode (disable, require, verify-full)
  • max_open_conns - Maximum open connections
  • max_idle_conns - Maximum idle connections
  • conn_max_lifetime - Connection max lifetime in seconds

Cache Configuration

{
    "cache": {
        "enabled": true,
        "driver": "memory",
        "ttl": 3600,
        "max_size": 100,
        "redis": {
            "host": "localhost",
            "port": 6379,
            "password": "",
            "db": 0
        }
    }
}

Cache Drivers

  • memory - In-memory cache (default)
  • redis - Redis cache
  • file - File-based cache

Logging Configuration

{
    "logging": {
        "level": "debug",
        "output": "stdout",
        "file": "logs/app.log",
        "format": "json",
        "max_size": 100,
        "max_backups": 3,
        "max_age": 28,
        "compress": true
    }
}

Log Levels

  • debug - All messages including debug
  • info - Informational messages and above
  • warn - Warning messages and above
  • error - Error messages only

Output Options

  • stdout - Console output
  • file - File output
  • both - Both console and file

Template Configuration

{
    "templates": {
        "path": "./webroot",
        "cache": true,
        "reload": false,
        "extensions": [".html", ".tmpl"],
        "delimiters": {
            "left": "{{",
            "right": "}}"
        }
    }
}

Options

  • path - Template directory path
  • cache - Enable template caching
  • reload - Auto-reload templates on change (dev only)
  • extensions - Template file extensions

API Configuration

{
    "api": {
        "news_endpoint": "https://api.example.com/news",
        "football_endpoint": "https://api.example.com/football",
        "api_key": "your-api-key",
        "timeout": 10,
        "retry_attempts": 3,
        "retry_delay": 1,
        "rate_limit": 100,
        "rate_limit_window": 60
    }
}

External API Settings

  • endpoint - API endpoint URL
  • api_key - API authentication key
  • timeout - Request timeout in seconds
  • retry_attempts - Number of retry attempts
  • retry_delay - Delay between retries in seconds

CORS Configuration

{
    "cors": {
        "enabled": true,
        "allowed_origins": [
            "http://localhost:3000",
            "https://example.com"
        ],
        "allowed_methods": [
            "GET",
            "POST",
            "PUT",
            "DELETE",
            "OPTIONS"
        ],
        "allowed_headers": [
            "Content-Type",
            "Authorization",
            "X-Requested-With"
        ],
        "exposed_headers": [
            "X-Total-Count"
        ],
        "allow_credentials": true,
        "max_age": 86400
    }
}

Session Configuration

{
    "session": {
        "secret": "change-this-secret-key-in-production",
        "cookie_name": "weber_session",
        "max_age": 86400,
        "secure": false,
        "http_only": true,
        "same_site": "lax",
        "domain": "",
        "path": "/"
    }
}

Security Settings

  • secret - Session encryption key (change in production!)
  • secure - Send cookie only over HTTPS
  • http_only - Prevent JavaScript access to cookie
  • same_site - SameSite cookie attribute (strict, lax, none)

OAuth Configuration

{
    "oauth": {
        "google": {
            "enabled": true,
            "client_id": "your-google-client-id",
            "client_secret": "your-google-client-secret",
            "redirect_url": "http://localhost:8080/auth/google/callback",
            "scopes": ["email", "profile"]
        },
        "github": {
            "enabled": false,
            "client_id": "your-github-client-id",
            "client_secret": "your-github-client-secret",
            "redirect_url": "http://localhost:8080/auth/github/callback"
        }
    }
}

Loading Configuration

In Code

import "weber/backend/app/config"

func main() {
    // Load configuration
    cfg, err := config.Load()
    if err != nil {
        log.Fatal(err)
    }
    
    // Access configuration
    port := cfg.Server.Port
    dbHost := cfg.Database.Host
    debugMode := cfg.Server.Debug
    
    // Use configuration
    log.Printf("Starting server on port %d", port)
}

Configuration Struct

type Config struct {
    Server    ServerConfig
    Database  DatabaseConfig
    Cache     CacheConfig
    Logging   LoggingConfig
    Templates TemplatesConfig
    API       APIConfig
    CORS      CORSConfig
    Session   SessionConfig
    OAuth     OAuthConfig
}

// Access nested values
timeout := cfg.API.Timeout
logLevel := cfg.Logging.Level

Environment Variables

Override configuration with environment variables:

# Override server port
export WEBER_PORT=3000

# Override debug mode
export WEBER_DEBUG=true

# Override database host
export WEBER_DB_HOST=db.example.com

# Override API key
export WEBER_API_KEY=secret-key

Priority Order

  1. Environment variables (highest priority)
  2. Configuration file
  3. Default values (lowest priority)

Environment-Specific Settings

Development

{
    "server": {
        "debug": true
    },
    "logging": {
        "level": "debug",
        "output": "stdout"
    },
    "templates": {
        "cache": false,
        "reload": true
    },
    "cache": {
        "ttl": 60
    }
}

Production

{
    "server": {
        "debug": false
    },
    "logging": {
        "level": "info",
        "output": "file",
        "file": "/var/log/weber/app.log"
    },
    "templates": {
        "cache": true,
        "reload": false
    },
    "cache": {
        "ttl": 3600,
        "driver": "redis"
    },
    "session": {
        "secure": true
    }
}

Validation

Validate configuration on startup:

func ValidateConfig(cfg *Config) error {
    if cfg.Server.Port < 1 || cfg.Server.Port > 65535 {
        return errors.New("invalid port number")
    }
    
    if cfg.Session.Secret == "change-this-secret-key" {
        return errors.New("please change session secret")
    }
    
    if cfg.Server.Debug && cfg.Logging.Level != "debug" {
        log.Warn("Debug mode enabled but log level is not debug")
    }
    
    return nil
}

Secrets Management

Using Environment Variables

# .env file (don't commit to git!)
WEBER_DB_PASSWORD=secret-password
WEBER_API_KEY=secret-api-key
WEBER_SESSION_SECRET=secret-session-key
WEBER_OAUTH_CLIENT_SECRET=oauth-secret

Using Secret Files

# Store secrets in separate files
/run/secrets/db_password
/run/secrets/api_key

# Load in application
dbPassword, _ := ioutil.ReadFile("/run/secrets/db_password")
cfg.Database.Password = string(dbPassword)

Using Key Management Services

Integrate with services like AWS Secrets Manager, HashiCorp Vault, etc.

Best Practices

  • Never commit secrets - Use environment variables or secret management
  • Use different configs per environment - dev, test, prod
  • Validate configuration - Check values on startup
  • Document settings - Explain what each setting does
  • Use sensible defaults - Provide default values when possible
  • Environment variables for secrets - Never hardcode sensitive data
  • Version control config structure - But not sensitive values
  • Test configuration loading - Ensure configs load correctly

Example: Configuration Setup

// main.go
package main

import (
    "log"
    "weber/backend/app"
    "weber/backend/app/config"
    "weber/backend/route"
)

func main() {
    // Load configuration
    cfg, err := config.Load()
    if err != nil {
        log.Fatal("Failed to load config:", err)
    }
    
    // Validate configuration
    if err := config.Validate(cfg); err != nil {
        log.Fatal("Invalid config:", err)
    }
    
    // Create app with config
    webApp := app.NewWithConfig(cfg)
    
    // Setup routes
    route.Setup(webApp)
    
    // Start server
    addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
    log.Printf("Starting server on %s (debug: %v)", addr, cfg.Server.Debug)
    
    if err := webApp.Run(addr); err != nil {
        log.Fatal("Server error:", err)
    }
}

Next Steps