> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/trailbaseio/trailbase/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Deployment

> Production checklist, security best practices, backup strategies, monitoring, and scaling for TrailBase

Deploying TrailBase to production requires careful consideration of security, reliability, and performance. This guide covers best practices and essential configuration for production environments.

## Production Checklist

Before deploying TrailBase to production, ensure you've completed these essential steps:

<Steps>
  <Step title="Set a public URL">
    Configure the public URL for OAuth redirects and email links:

    ```bash theme={null}
    trail --public-url https://yourdomain.com run
    ```

    Or via environment variable:

    ```bash theme={null}
    export PUBLIC_URL=https://yourdomain.com
    trail run
    ```
  </Step>

  <Step title="Bind to the correct address">
    For production behind a reverse proxy:

    ```bash theme={null}
    trail run --address 0.0.0.0:4000
    ```

    For direct internet exposure, bind to localhost and use a reverse proxy:

    ```bash theme={null}
    trail run --address localhost:4000
    ```
  </Step>

  <Step title="Configure CORS">
    Restrict CORS origins to your domains:

    ```bash theme={null}
    trail run --cors-allowed-origins "https://yourdomain.com,https://www.yourdomain.com"
    ```
  </Step>

  <Step title="Set up SMTP for emails">
    Configure email delivery for auth verification and password resets. Edit `traildepot/config.textproto`:

    ```protobuf theme={null}
    email: {
      smtp_host: "smtp.example.com"
      smtp_port: 587
      smtp_encryption: STARTTLS
      smtp_username: "user@example.com"
      smtp_password: "<REDACTED>"  # Actual password goes in secrets.textproto
      sender_address: "noreply@yourdomain.com"
      sender_name: "Your App"
    }
    ```
  </Step>

  <Step title="Review authentication settings">
    Adjust token TTLs in `config.textproto`:

    ```protobuf theme={null}
    auth: {
      # Auth token expires after 1 hour (in seconds)
      auth_token_ttl_sec: 3600
      
      # Refresh token expires after 30 days
      refresh_token_ttl_sec: 2592000
    }
    ```
  </Step>

  <Step title="Set up SSL/TLS">
    Use a reverse proxy (nginx, Caddy, Traefik) for SSL/TLS termination. Never expose TrailBase directly to the internet without HTTPS.
  </Step>

  <Step title="Configure backups">
    Implement automated backups of the data directory (see Backup Strategies below).
  </Step>

  <Step title="Set up monitoring">
    Implement health checks and monitoring (see Monitoring section below).
  </Step>
</Steps>

<Warning>
  Never disable or weaken security features for convenience. Always use HTTPS, strong passwords, and proper CORS settings in production.
</Warning>

## Security Best Practices

### SSL/TLS Configuration

Always run TrailBase behind a reverse proxy with SSL/TLS:

<CodeGroup>
  ```nginx nginx theme={null}
  server {
      listen 443 ssl http2;
      server_name yourdomain.com;

      ssl_certificate /etc/ssl/certs/yourdomain.crt;
      ssl_certificate_key /etc/ssl/private/yourdomain.key;
      ssl_protocols TLSv1.2 TLSv1.3;
      ssl_ciphers HIGH:!aNULL:!MD5;

      location / {
          proxy_pass http://localhost:4000;
          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;
          
          # WebSocket support
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
      }
  }
  ```

  ```caddyfile Caddyfile theme={null}
  yourdomain.com {
      reverse_proxy localhost:4000
  }
  ```
</CodeGroup>

### File Permissions

Secure the data directory with proper permissions:

```bash theme={null}
# Set ownership to the TrailBase user
chown -R trailbase:trailbase /var/lib/trailbase

# Restrict access to owner only
chmod 700 /var/lib/trailbase

# Protect sensitive files
chmod 600 /var/lib/trailbase/secrets.textproto
chmod 600 /var/lib/trailbase/*.db
```

### Secrets Management

TrailBase separates configuration into two files:

* `config.textproto` - Non-sensitive configuration
* `secrets.textproto` - Sensitive values (OAuth secrets, SMTP passwords)

Secrets marked with `[(secret) = true]` in the protobuf schema are automatically redacted to `<REDACTED>` in `config.textproto` and stored in `secrets.textproto`.

<Tip>
  You can also override any configuration value using environment variables prefixed with `TRAIL_`, for example: `TRAIL_EMAIL_SMTP_PASSWORD`.
</Tip>

### Admin Access

For production, consider separating admin UI access:

```bash theme={null}
trail run \
  --address 0.0.0.0:4000 \
  --admin-address 127.0.0.1:4001
```

This binds:

* Public API to `0.0.0.0:4000` (accessible externally)
* Admin UI to `127.0.0.1:4001` (localhost only)

Access the admin UI through an SSH tunnel:

```bash theme={null}
ssh -L 4001:localhost:4001 user@yourserver
# Then browse to http://localhost:4001/_/admin
```

### Rate Limiting

Implement rate limiting at the reverse proxy level:

```nginx theme={null}
http {
    limit_req_zone $binary_remote_addr zone=trailbase:10m rate=10r/s;
    
    server {
        location / {
            limit_req zone=trailbase burst=20 nodelay;
            proxy_pass http://localhost:4000;
        }
    }
}
```

### Firewall Configuration

```bash theme={null}
# Only allow HTTP/HTTPS and SSH
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw default deny incoming
sudo ufw enable
```

## Backup Strategies

Regular backups are essential for production deployments.

### Full Data Directory Backup

The simplest approach is backing up the entire data directory:

```bash theme={null}
#!/bin/bash
# backup-trailbase.sh

DATA_DIR="/var/lib/trailbase/traildepot"
BACKUP_DIR="/backups/trailbase"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Create tarball of data directory
tar -czf "$BACKUP_DIR/trailbase_$TIMESTAMP.tar.gz" -C "$(dirname $DATA_DIR)" "$(basename $DATA_DIR)"

# Keep only last 7 days of backups
find "$BACKUP_DIR" -name "trailbase_*.tar.gz" -mtime +7 -delete

echo "Backup completed: trailbase_$TIMESTAMP.tar.gz"
```

Schedule with cron:

```cron theme={null}
# Run backup daily at 2 AM
0 2 * * * /usr/local/bin/backup-trailbase.sh
```

### SQLite Backup

For online backups without stopping the server, use SQLite's backup API:

```bash theme={null}
#!/bin/bash
# sqlite-backup.sh

DATA_DIR="/var/lib/trailbase/traildepot"
BACKUP_DIR="/backups/trailbase/sqlite"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR/$TIMESTAMP"

# Backup main database
sqlite3 "$DATA_DIR/main.db" ".backup '$BACKUP_DIR/$TIMESTAMP/main.db'"

# Backup logs database
sqlite3 "$DATA_DIR/logs.db" ".backup '$BACKUP_DIR/$TIMESTAMP/logs.db'"

# Copy configuration files
cp "$DATA_DIR/config.textproto" "$BACKUP_DIR/$TIMESTAMP/"
cp "$DATA_DIR/secrets.textproto" "$BACKUP_DIR/$TIMESTAMP/"

echo "SQLite backup completed: $TIMESTAMP"
```

### Cloud Backup

Sync backups to cloud storage:

<CodeGroup>
  ```bash AWS S3 theme={null}
  #!/bin/bash
  aws s3 sync /backups/trailbase s3://your-bucket/trailbase/ \
    --storage-class STANDARD_IA \
    --exclude "*" \
    --include "*.tar.gz"
  ```

  ```bash Backblaze B2 theme={null}
  #!/bin/bash
  b2 sync --replaceNewer /backups/trailbase b2://your-bucket/trailbase/
  ```
</CodeGroup>

### Restore from Backup

To restore from a backup:

```bash theme={null}
# Stop TrailBase
sudo systemctl stop trailbase

# Extract backup
tar -xzf trailbase_20240115_020000.tar.gz -C /var/lib/trailbase/

# Restore permissions
chown -R trailbase:trailbase /var/lib/trailbase/traildepot
chmod 700 /var/lib/trailbase/traildepot

# Start TrailBase
sudo systemctl start trailbase
```

<Warning>
  Always test your backup and restore procedures before you need them. Perform regular restore drills to ensure backups are valid.
</Warning>

## Monitoring

### Health Check Endpoint

TrailBase provides a health check endpoint:

```bash theme={null}
curl http://localhost:4000/api/healthcheck
```

Returns `200 OK` if the server is healthy.

### Uptime Monitoring

Use external monitoring services:

* **UptimeRobot**: Simple HTTP monitoring
* **Pingdom**: Advanced monitoring with alerting
* **Better Uptime**: Modern uptime monitoring
* **StatusCake**: HTTP and performance monitoring

Example configuration:

* Monitor URL: `https://yourdomain.com/api/healthcheck`
* Check interval: 60 seconds
* Alert after: 2 consecutive failures

### Log Monitoring

TrailBase stores access and error logs in the `logs.db` SQLite database:

```sql theme={null}
-- Query recent errors
SELECT * FROM _logs 
WHERE level = 'ERROR' 
ORDER BY timestamp DESC 
LIMIT 100;

-- Query access patterns
SELECT 
  COUNT(*) as requests,
  path,
  method
FROM _logs
WHERE timestamp > datetime('now', '-1 hour')
GROUP BY path, method
ORDER BY requests DESC;
```

For stdout logging (e.g., in Docker):

```bash theme={null}
trail run --stderr-logging
```

### Log Retention

Configure log retention in `config.textproto`:

```protobuf theme={null}
server: {
  # Keep logs for 7 days (in seconds)
  logs_retention_sec: 604800
}
```

### Resource Monitoring

Monitor system resources:

```bash theme={null}
# CPU and memory usage
top -b -n 1 | grep trail

# Database size
du -sh /var/lib/trailbase/traildepot/*.db

# Disk usage
df -h /var/lib/trailbase
```

For automated monitoring, use:

* **Prometheus** + **Grafana**: Metrics and dashboards
* **Netdata**: Real-time performance monitoring
* **Datadog**: Full-stack monitoring

### Performance Metrics

Key metrics to monitor:

* **Request latency**: P50, P95, P99 response times
* **Request rate**: Requests per second
* **Error rate**: 4xx and 5xx responses
* **Database size**: Growth rate
* **CPU usage**: Average and peak
* **Memory usage**: RSS and growth
* **Disk I/O**: Read/write operations

## Scaling

### Vertical Scaling

For most workloads, vertical scaling is the simplest approach:

* **Small**: 1 CPU, 512 MB RAM - Up to 100 req/s
* **Medium**: 2 CPU, 2 GB RAM - Up to 500 req/s
* **Large**: 4 CPU, 4 GB RAM - Up to 2000 req/s
* **X-Large**: 8 CPU, 8 GB RAM - Up to 5000+ req/s

<Info>
  TrailBase is extremely efficient. SQLite's sub-millisecond latencies mean most applications won't need horizontal scaling.
</Info>

### Horizontal Scaling (Read Replicas)

For read-heavy workloads:

<Steps>
  <Step title="Primary instance">
    Run a single write instance:

    ```bash theme={null}
    trail --data-dir /var/lib/trailbase/primary run
    ```
  </Step>

  <Step title="Create read replicas">
    Periodically copy the database to read-only instances:

    ```bash theme={null}
    # On primary
    sqlite3 /var/lib/trailbase/primary/main.db ".backup '/tmp/main.db'"

    # Transfer to replica
    scp /tmp/main.db replica:/var/lib/trailbase/replica/main.db
    ```
  </Step>

  <Step title="Route traffic">
    Use a load balancer to route:

    * **Writes** → Primary instance
    * **Reads** → Read replicas (round-robin)
  </Step>
</Steps>

<Warning>
  SQLite does not have built-in replication. For true high-availability and write scaling, consider commercial solutions like [Turso](https://turso.tech/) or [LiteFS](https://fly.io/docs/litefs/).
</Warning>

### CDN for Static Assets

If serving static files:

```bash theme={null}
trail run --public-dir /var/www/static
```

Place a CDN (CloudFlare, Fastly, CloudFront) in front to:

* Cache static assets globally
* Reduce load on TrailBase
* Improve latency for users worldwide

### Database Optimization

Optimize SQLite performance:

```sql theme={null}
-- Analyze query patterns
ANALYZE;

-- Rebuild indexes
REINDEX;

-- Vacuum to reclaim space
VACUUM;
```

Run maintenance periodically:

```bash theme={null}
#!/bin/bash
sqlite3 /var/lib/trailbase/traildepot/main.db "ANALYZE; VACUUM;"
```

## Systemd Service

Run TrailBase as a systemd service:

```ini /etc/systemd/system/trailbase.service theme={null}
[Unit]
Description=TrailBase Server
After=network.target

[Service]
Type=simple
User=trailbase
Group=trailbase
WorkingDirectory=/var/lib/trailbase
Environment="DATA_DIR=/var/lib/trailbase/traildepot"
Environment="PUBLIC_URL=https://yourdomain.com"
ExecStart=/usr/local/bin/trail run --address 0.0.0.0:4000
Restart=always
RestartSec=10

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/trailbase

[Install]
WantedBy=multi-user.target
```

Enable and start:

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl enable trailbase
sudo systemctl start trailbase
sudo systemctl status trailbase
```

## Troubleshooting

### High CPU Usage

Check for:

* Expensive queries (add indexes)
* Too many realtime subscriptions
* Insufficient `runtime-threads` for WASM workloads

### Database Locked

SQLite allows one writer at a time:

* Enable WAL mode (enabled by default in TrailBase)
* Reduce write transaction duration
* Consider read replicas for read-heavy loads

### Memory Leaks

Monitor memory over time:

```bash theme={null}
watch -n 60 'ps aux | grep trail'
```

If memory grows unbounded, file a bug report with:

* TrailBase version
* Memory growth rate
* Request patterns
* Configuration

## Next Steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/deployment/configuration">
    Detailed configuration options and environment variables
  </Card>

  <Card title="Self-Hosting" icon="server" href="/deployment/self-hosting">
    Learn about different deployment strategies
  </Card>
</CardGroup>
