Skip to main content
Rexec gives you instantly-available, network-isolated Linux terminals in the cloud. Perfect for development, testing, and secure remote access.

Installation Methods

1

Choose Your Deployment Method

Select the installation method that best fits your needs:
# Clone the repository
git clone https://github.com/brimblehq/rexec.git
cd rexec/docker

# Start the stack
docker compose up --build
Docker Compose is the fastest way to get started. It includes PostgreSQL, Redis, and all dependencies configured automatically.
2

Access the Dashboard

Once your deployment is running, open your browser:
http://localhost:8080
Default Credentials:
  • Username: admin
  • Password: admin
Change the default password immediately in production! Go to Settings > Profile after logging in.
3

Create Your First Container

From the dashboard, click “New Container” and configure:
  • Image: Choose from ubuntu:24.04, alpine:latest, node:20, python:3.12, or use a custom image
  • Name: Give it a memorable name (auto-generated if left blank)
  • Role: Select pre-configured environments:
    • barebone - Minimal setup (fastest)
    • webdev - Node.js, npm, yarn
    • python - Python 3, pip, venv
    • devops - kubectl, helm, terraform
    • database - PostgreSQL client, Redis CLI
Click Create and your terminal will be ready in seconds!
Container names are auto-generated using fun combinations like swift-tiger-42 if you don’t specify one.
4

Connect and Use Your Terminal

Your terminal opens automatically with a full-featured shell:
# Try some commands
echo "Hello from Rexec!"

# Install packages (Ubuntu example)
apt update && apt install -y curl

# Create files (persistent across restarts)
echo "data" > /workspace/myfile.txt

# Check resources
free -h
df -h
All data in /workspace is persistent across container stops/starts. Other directories are ephemeral.

Docker Compose Configuration

The complete docker-compose.yml sets up Rexec with all dependencies:
docker-compose.yml
version: "3.8"

services:
  # Rexec API (connects to remote Docker daemon)
  rexec:
    build:
      context: ../
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
      - "22:22" # SSH Gateway (optional, enable with SSH_GATEWAY_ENABLED=true)
    environment:
      - PORT=8080
      - JWT_SECRET=${JWT_SECRET:-rexec-dev-secret-change-me}
      - DATABASE_URL=postgres://rexec:${POSTGRES_PASSWORD:-rexec_dev_password}@postgres:5432/rexec?sslmode=disable
      - REDIS_URL=redis://redis:6379
      # Remote Docker daemon configuration
      - DOCKER_HOST=${DOCKER_HOST}
      - DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-1}
      - DOCKER_CA_CERT=${DOCKER_CA_CERT}
      - DOCKER_CLIENT_CERT=${DOCKER_CLIENT_CERT}
      - DOCKER_CLIENT_KEY=${DOCKER_CLIENT_KEY}
      # SSH Gateway configuration
      - SSH_GATEWAY_ENABLED=${SSH_GATEWAY_ENABLED:-false}
      - SSH_GATEWAY_HOST_KEY=/app/.ssh/host_key
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      - recordings-data:/app/recordings
      - ssh-keys:/app/.ssh # SSH host keys (persistent)
    restart: unless-stopped
    networks:
      - rexec-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

  # Redis for session management
  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: unless-stopped
    networks:
      - rexec-network

  # PostgreSQL for user data
  postgres:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=rexec
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-rexec_dev_password}
      - POSTGRES_DB=rexec
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U rexec -d rexec"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - rexec-network

volumes:
  redis-data:
  postgres-data:
  recordings-data:
  ssh-keys:

networks:
  rexec-network:
    driver: bridge

Using the API

Rexec provides a REST API for programmatic container management.

Authentication

First, obtain an API token:
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "admin"
  }'
Response:
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "user-123",
    "email": "[email protected]"
  }
}

Create a Container

curl -X POST http://localhost:8080/api/containers \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "ubuntu:24.04",
    "name": "api-sandbox",
    "role": "webdev",
    "shell": {
      "enhanced": true,
      "theme": "dracula",
      "use_tmux": false
    },
    "memory_mb": 2048,
    "cpu_shares": 1024,
    "disk_mb": 8192
  }'
Response:
{
  "id": "abc123def456",
  "name": "api-sandbox",
  "image": "ubuntu:24.04",
  "status": "creating",
  "async": true,
  "message": "Container is being created. This may take a moment if the image needs to be pulled.",
  "resources": {
    "memory_mb": 2048,
    "cpu_shares": 1024,
    "disk_mb": 8192
  }
}

List Containers

curl -X GET http://localhost:8080/api/containers \
  -H "Authorization: Bearer YOUR_TOKEN"

Execute Commands

Connect to the WebSocket terminal endpoint:
ws://localhost:8080/ws/terminal/{containerId}?token=YOUR_TOKEN

Manage Container Lifecycle

curl -X POST http://localhost:8080/api/containers/{id}/start \
  -H "Authorization: Bearer YOUR_TOKEN"

Using the SDKs

Rexec provides official SDKs for multiple languages.

Go SDK

Install:
go get github.com/brimblehq/rexec-go
Example:
package main

import (
    "context"
    "fmt"
    "log"

    rexec "github.com/brimblehq/rexec-go"
)

func main() {
    // Create client
    client := rexec.NewClient("https://your-rexec-instance.com", "your-api-token")

    ctx := context.Background()

    // Create a container
    container, err := client.Containers.Create(ctx, &rexec.CreateContainerRequest{
        Image: "ubuntu:24.04",
        Name:  "my-sandbox",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Created container: %s\n", container.ID)

    // Connect to terminal
    term, err := client.Terminal.Connect(ctx, container.ID)
    if err != nil {
        log.Fatal(err)
    }
    defer term.Close()

    // Send a command
    term.Write([]byte("echo 'Hello from Rexec!'\n"))

    // Read output
    output, _ := term.Read()
    fmt.Printf("Output: %s\n", output)

    // Clean up
    client.Containers.Delete(ctx, container.ID)
}

JavaScript/TypeScript SDK

Install:
npm install @pipeopshq/rexec
Example:
import { RexecClient } from '@pipeopshq/rexec';

const client = new RexecClient({
  baseURL: 'https://your-rexec-instance.com',
  token: 'your-api-token'
});

// Create a container
const container = await client.containers.create({
  image: 'ubuntu:24.04',
  name: 'my-sandbox'
});

console.log(`Created container: ${container.id}`);

// Connect to terminal
const terminal = await client.terminal.connect(container.id);

terminal.onData((data) => {
  console.log('Output:', data);
});

terminal.write('echo "Hello from Rexec!"\n');

// Clean up
await client.containers.delete(container.id);

Integration with xterm.js

For web applications, integrate with xterm.js:
import { Terminal } from 'xterm';
import { RexecClient } from '@pipeopshq/rexec';

const xterm = new Terminal();
xterm.open(document.getElementById('terminal'));

const client = new RexecClient({
  baseURL: 'https://your-rexec-instance.com',
  token: 'your-api-token'
});

const container = await client.containers.create({ image: 'ubuntu:24.04' });
const rexecTerminal = await client.terminal.connect(container.id, {
  cols: xterm.cols,
  rows: xterm.rows
});

// Connect xterm to rexec terminal
rexecTerminal.onData((data) => {
  xterm.write(data);
});

xterm.onData((data) => {
  rexecTerminal.write(data);
});

xterm.onResize(({ cols, rows }) => {
  rexecTerminal.resize(cols, rows);
});

Configuration

Rexec is configured via environment variables:
VariableDescriptionDefault
PORTAPI listen port8080
DATABASE_URLPostgreSQL connection stringpostgres://...
JWT_SECRETRequired. Secret for signing auth tokens(Random if unset)
REDIS_URLRedis connection stringredis://localhost:6379
GIN_MODEWeb framework mode (debug or release)debug
DOCKER_HOSTRemote Docker daemon address(Uses local Docker socket)
SSH_GATEWAY_ENABLEDEnable SSH gateway on port 22false
S3_BUCKETS3 bucket for storing session recordings(Optional)
S3_REGIONS3 regionus-east-1
Create a .env file in the project root to set these variables. See .env.example for a complete list.

Next Steps

Connect Your Machines

Install the Rexec Agent on your infrastructure for secure remote access

Session Recording

Record and replay terminal sessions for documentation

API Reference

Explore the complete API documentation

Security

Learn about MFA, audit logging, and security features

Troubleshooting

This usually means Docker couldn’t pull the image. Check:
  • Docker daemon is running: docker ps
  • Internet connectivity: docker pull ubuntu:24.04
  • Docker Hub rate limits (use authenticated pulls)
  • Custom image names are valid: registry.example.com/image:tag
Verify:
  • Container status is running: Check dashboard or API
  • WebSocket proxy configuration (if behind nginx/traefik)
  • JWT token is valid and not expired
  • Firewall allows WebSocket connections on port 8080
Ensure PostgreSQL is healthy:
docker compose logs postgres
docker compose exec postgres pg_isready -U rexec
Check DATABASE_URL format:
postgres://user:password@host:5432/database?sslmode=disable
Containers have resource limits based on your tier:
  • Free: 2GB RAM, 2 vCPU
  • Pro: 4GB RAM, 4 vCPU
  • Enterprise: Custom limits
Upgrade your plan or adjust limits in container settings.

Community & Support

Need help? Join the community:

Build docs developers (and LLMs) love