Skip to main content

Overview

This guide covers deploying Tesslate Studio to production with:
  • Custom domain configuration
  • Automatic SSL/TLS certificates
  • Security hardening
  • Performance optimization
  • Backup strategies
This guide assumes you’ve already set up Tesslate Studio locally. If not, see the Self-Hosting Quickstart first.

Prerequisites

Server

  • Cloud VM or dedicated server
  • 16GB RAM recommended
  • 50GB+ disk space
  • Ubuntu 22.04 LTS (or similar)

Domain

  • Custom domain (e.g., studio.yourcompany.com)
  • DNS access to create records
  • Wildcard DNS support (*.studio.yourcompany.com)

SSL Certificate

  • Automatic via Let’s Encrypt (recommended)
  • Or bring your own certificate

Email

  • Admin email for Let’s Encrypt notifications

Server Setup

1. Provision Server

Choose a cloud provider:
  • DigitalOcean
  • AWS EC2
  • Hetzner
# Create Droplet
# - Image: Ubuntu 22.04 LTS
# - Size: 4 vCPUs, 16GB RAM
# - Region: Closest to your users
# - Add SSH key
Estimated cost: $80/month

2. Initial Server Configuration

1

Connect to Server

ssh root@your-server-ip
2

Update System

apt update && apt upgrade -y
3

Install Docker

curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
Verify:
docker --version
docker compose version
4

Create Non-Root User

adduser tesslate
usermod -aG docker tesslate
usermod -aG sudo tesslate
Switch to new user:
su - tesslate
5

Set up Firewall

sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS
sudo ufw enable

DNS Configuration

1. Create DNS Records

Add these records to your DNS provider:
Type: A
Name: studio
Value: your-server-ip
TTL: 300

2. Verify DNS Propagation

Wait 5-10 minutes, then test:
# Should return your server IP
dig studio.yourcompany.com
dig test.studio.yourcompany.com

Application Deployment

1. Clone Repository

cd /home/tesslate
git clone https://github.com/TesslateAI/Studio.git
cd Studio

2. Configure Environment

cp .env.example .env
nano .env
Update these values:
# Domain Configuration
APP_DOMAIN=studio.yourcompany.com
APP_PROTOCOL=https
FRONTEND_URL=https://studio.yourcompany.com

# Generate strong keys
SECRET_KEY=<generate-with-python>
LITELLM_MASTER_KEY=sk-<generate-with-python>

# AI Provider (at least one)
OPENAI_API_KEY=sk-your-production-key
ANTHROPIC_API_KEY=sk-your-production-key

# Database
DATABASE_URL=postgresql+asyncpg://tesslate:CHANGE_THIS_PASSWORD@postgres:5432/tesslate_db
POSTGRES_PASSWORD=CHANGE_THIS_PASSWORD

# Production Settings
LOG_LEVEL=INFO
AUTO_SEED_DATABASE=false  # Set to false after first run
Generate secure keys:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
python3 -c "import secrets; print('sk-' + secrets.token_urlsafe(32))"

3. Configure SSL with Let’s Encrypt

Update docker-compose.yml for production:
services:
  traefik:
    image: traefik:v3.1
    command:
      - "--api.dashboard=false"  # Disable dashboard in production
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # Redirect HTTP to HTTPS
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      # Let's Encrypt configuration
      - "--certificatesresolvers.letsencrypt.acme.email=admin@yourcompany.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - tesslate-network

  app:
    labels:
      - "traefik.http.routers.app.rule=Host(`studio.yourcompany.com`)"
      - "traefik.http.routers.app.tls=true"
      - "traefik.http.routers.app.tls.certresolver=letsencrypt"

  orchestrator:
    labels:
      - "traefik.http.routers.orchestrator.rule=Host(`studio.yourcompany.com`) && PathPrefix(`/api`)"
      - "traefik.http.routers.orchestrator.tls=true"
      - "traefik.http.routers.orchestrator.tls.certresolver=letsencrypt"

4. Deploy

# Create letsencrypt directory
mkdir -p letsencrypt
chmod 600 letsencrypt

# Start services
docker compose up -d

# Monitor logs
docker compose logs -f

5. Verify Deployment

1

Check Services

docker compose ps
All services should be “Up”.
2

Test HTTPS

Open browser to:
https://studio.yourcompany.com
Should show:
  • Valid SSL certificate
  • Green padlock in browser
  • No certificate warnings
3

Test API

curl https://studio.yourcompany.com/api/health
Should return:
{"status": "healthy"}
4

Create First User

Sign up at https://studio.yourcompany.comFirst user is automatically admin.

Database Backup

1. Automated Backup Script

Create /home/tesslate/backup.sh:
#!/bin/bash
BACKUP_DIR="/home/tesslate/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/tesslate_$DATE.sql.gz"

# Create backup directory
mkdir -p $BACKUP_DIR

# Dump database
docker compose exec -T postgres pg_dump -U tesslate tesslate_db | gzip > $BACKUP_FILE

# Keep only last 7 days
find $BACKUP_DIR -type f -mtime +7 -delete

echo "Backup completed: $BACKUP_FILE"
Make executable:
chmod +x /home/tesslate/backup.sh

2. Schedule Backups

Add to crontab:
crontab -e
Add this line (daily at 2 AM):
0 2 * * * /home/tesslate/backup.sh

3. Test Restore

# Stop services
cd /home/tesslate/Studio
docker compose down

# Restore database
gunzip < /home/tesslate/backups/tesslate_YYYYMMDD_HHMMSS.sql.gz | \
  docker compose exec -T postgres psql -U tesslate tesslate_db

# Restart services
docker compose up -d

Monitoring

1. Docker Health Checks

Check container health:
docker compose ps
docker stats

2. Log Management

View logs:
# All services
docker compose logs -f

# Specific service
docker compose logs -f orchestrator

# Last 100 lines
docker compose logs --tail=100 orchestrator
Rotate logs in docker-compose.yml:
services:
  orchestrator:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

3. Disk Space Monitoring

Create /home/tesslate/monitor.sh:
#!/bin/bash
USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')

if [ $USAGE -gt 80 ]; then
    echo "WARNING: Disk usage is at ${USAGE}%"
    # Clean Docker
    docker system prune -f
fi
Add to crontab (hourly):
0 * * * * /home/tesslate/monitor.sh

Security Hardening

1

Disable Root SSH

Edit /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
Restart SSH:
sudo systemctl restart ssh
2

Configure Fail2Ban

sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
3

Enable Unattended Upgrades

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
4

Secure PostgreSQL

Change default password in .env:
POSTGRES_PASSWORD=very-strong-password-here
Update DATABASE_URL accordingly.
5

Rate Limiting

Add to Traefik configuration:
- "--entrypoints.websecure.http.middlewares=rate-limit"
- "--http.middlewares.rate-limit.rateLimit.average=100"
- "--http.middlewares.rate-limit.rateLimit.burst=50"

Performance Optimization

1. Enable HTTP/2

Already enabled with Traefik HTTPS.

2. Database Optimization

Add to docker-compose.yml:
services:
  postgres:
    command:
      - "postgres"
      - "-c"
      - "shared_buffers=256MB"
      - "-c"
      - "effective_cache_size=1GB"
      - "-c"
      - "maintenance_work_mem=128MB"
      - "-c"
      - "checkpoint_completion_target=0.9"
      - "-c"
      - "wal_buffers=16MB"
      - "-c"
      - "default_statistics_target=100"

3. Docker Resource Limits

Add to docker-compose.yml:
services:
  orchestrator:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 4G
        reservations:
          cpus: '1.0'
          memory: 2G

  app:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 2G

Maintenance

Daily Tasks

# Check logs for errors
docker compose logs --tail=100 | grep -i error

# Check disk space
df -h

# Check Docker stats
docker stats --no-stream

Weekly Tasks

# Update system packages
sudo apt update && sudo apt upgrade -y

# Clean Docker resources
docker system prune -f

# Review backups
ls -lh /home/tesslate/backups/

Monthly Tasks

# Pull latest updates
cd /home/tesslate/Studio
git pull origin main

# Rebuild images
docker compose build --no-cache

# Restart services
docker compose down && docker compose up -d

# Test application
curl https://studio.yourcompany.com/api/health

Troubleshooting

Check Let’s Encrypt logs:
docker compose logs traefik | grep -i acme
Common issues:
  • DNS not propagated (wait 10-15 minutes)
  • Port 80 not accessible (check firewall)
  • Invalid email in acme configuration
  • Rate limit hit (5 certs per week per domain)
Force renewal:
rm -rf letsencrypt/acme.json
docker compose restart traefik
Check what’s using memory:
docker stats
Solutions:
  1. Add swap space
  2. Increase server RAM
  3. Add resource limits in docker-compose.yml
  4. Clean up old containers:
docker system prune -a
Check PostgreSQL is running:
docker compose ps postgres
Check logs:
docker compose logs postgres
Restart database:
docker compose restart postgres

Next Steps