Skip to main content

Overview

OpenCode Portal supports running multiple instances simultaneously, allowing you to work on different projects without conflicts. Each instance can have its own:
  • Dedicated ports (Web UI and OpenCode server)
  • Separate sessions and chat history
  • Independent working directory
  • Custom instance name

Why Multiple Instances?

Project Isolation

Keep different codebases completely separate with their own AI context and sessions.

Client Work

Maintain distinct instances for different clients, preventing context mixing.

Environment Separation

Run separate instances for development, staging, and production environments.

Team Collaboration

Share different instances with different team members based on project access.

Basic Multi-Instance Usage

Starting Multiple Instances

The simplest way to run multiple instances is to use different directories:
# Terminal 1: Start first project
cd ~/projects/website
openportal
# Web UI: http://localhost:3000
# OpenCode: http://localhost:4000

# Terminal 2: Start second project
cd ~/projects/api
openportal
# Ports auto-increment if defaults are busy:
# Web UI: http://localhost:3001
# OpenCode: http://localhost:4001
OpenCode Portal automatically finds available ports if the defaults (3000 and 4000) are already in use.

Using Custom Names

Give each instance a memorable name:
# Project 1: Frontend
cd ~/projects/website
openportal --name "website-frontend"

# Project 2: Backend API
cd ~/projects/api
openportal --name "api-backend"

# Project 3: Mobile App
cd ~/projects/mobile
openportal --name "mobile-app"
Names help you identify instances when listing them:
openportal list
Output:
Running OpenCode Portal instances:

┌───────────────────┬──────────────────────┬─────────┬───────────────┬─────────┐
│ Name              │ Directory            │ Web UI  │ OpenCode Port │ PID     │
├───────────────────┼──────────────────────┼─────────┼───────────────┼─────────┤
│ website-frontend  │ /home/user/projects/ │ 3000    │ 4000          │ 12345   │
│                   │ website              │         │               │         │
├───────────────────┼──────────────────────┼─────────┼───────────────┼─────────┤
│ api-backend       │ /home/user/projects/ │ 3001    │ 4001          │ 12346   │
│                   │ api                  │         │               │         │
├───────────────────┼──────────────────────┼─────────┼───────────────┼─────────┤
│ mobile-app        │ /home/user/projects/ │ 3002    │ 4002          │ 12347   │
│                   │ mobile              │         │               │         │
└───────────────────┴──────────────────────┴─────────┴───────────────┴─────────┘

Advanced Configuration

Specifying Exact Ports

For consistent access (especially useful for bookmarks and remote access), specify exact ports:
# Frontend on specific ports
openportal \
  --name "frontend" \
  --port 3000 \
  --opencode-port 4000 \
  --directory ~/projects/website

# Backend on different ports
openportal \
  --name "backend" \
  --port 3100 \
  --opencode-port 4100 \
  --directory ~/projects/api

# Mobile on yet different ports
openportal \
  --name "mobile" \
  --port 3200 \
  --opencode-port 4200 \
  --directory ~/projects/mobile
If you specify a port that’s already in use, Portal will fail to start. Use openportal list to see which ports are currently occupied.

Port Organization Strategy

Organize ports systematically for easier management:
Project Type       | Web UI Port | OpenCode Port
-------------------|-------------|---------------
Frontend projects  | 3000-3099   | 4000-4099
Backend projects   | 3100-3199   | 4100-4199
Mobile projects    | 3200-3299   | 4200-4299
DevOps/Infra       | 3300-3399   | 4300-4399

Running from Different Directories

You can start Portal from anywhere and specify the project directory:
# Run from home directory but target specific project
openportal \
  --name "client-a" \
  --directory ~/projects/client-a/frontend \
  --port 3000

openportal \
  --name "client-b" \
  --directory ~/projects/client-b/app \
  --port 3100

Managing Instances

List All Running Instances

openportal list
Shows all active instances with their configuration.

Stop Specific Instance

Stop instances by name or port:
# Stop by name
openportal stop --name "website-frontend"

# Stop by port
openportal stop --port 3000

# Stop all instances
openportal stop --all
The stop command gracefully shuts down both the Web UI and OpenCode server for the specified instance.

Clean Up Stale Entries

If processes were killed ungracefully, clean up stale registry entries:
openportal clean
This removes entries for processes that are no longer running.

Remote Access for Multiple Instances

Via Tailscale VPN

When accessing multiple instances remotely via Tailscale:
# On server, start multiple instances on different ports
openportal --name "proj-a" --port 3000 --hostname 0.0.0.0
openportal --name "proj-b" --port 3001 --hostname 0.0.0.0
openportal --name "proj-c" --port 3002 --hostname 0.0.0.0

# Access from mobile:
# http://server-name:3000  (Project A)
# http://server-name:3001  (Project B)
# http://server-name:3002  (Project C)
Create mobile bookmarks for each instance with descriptive names:

Using Nginx Reverse Proxy

For cleaner URLs, set up Nginx to route by subdomain or path:

Subdomain-based routing

# /etc/nginx/sites-available/openportal

# Frontend instance
server {
    listen 80;
    server_name frontend.myserver.ts.net;
    
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

# Backend instance
server {
    listen 80;
    server_name backend.myserver.ts.net;
    
    location / {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Path-based routing

server {
    listen 80;
    server_name myserver.ts.net;
    
    location /frontend/ {
        proxy_pass http://localhost:3000/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    
    location /backend/ {
        proxy_pass http://localhost:3001/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Enable and reload:
sudo ln -s /etc/nginx/sites-available/openportal /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Persistent Multi-Instance Setup

Using systemd Services

Create separate systemd services for each project:
# Create service for Project A
sudo nano /etc/systemd/system/openportal-frontend.service
[Unit]
Description=OpenCode Portal - Frontend
After=network.target

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/projects/website
ExecStart=/home/your-username/.bun/bin/openportal --name "frontend" --port 3000 --hostname 0.0.0.0
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
# Create service for Project B
sudo nano /etc/systemd/system/openportal-backend.service
[Unit]
Description=OpenCode Portal - Backend
After=network.target

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/projects/api
ExecStart=/home/your-username/.bun/bin/openportal --name "backend" --port 3001 --hostname 0.0.0.0
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
Enable and start all services:
sudo systemctl enable openportal-frontend openportal-backend
sudo systemctl start openportal-frontend openportal-backend

# Check status
sudo systemctl status openportal-frontend
sudo systemctl status openportal-backend

Using tmux for Multiple Sessions

Organize multiple instances in tmux windows:
# Start tmux session
tmux new -s portals

# Window 0: Frontend
cd ~/projects/website
openportal --name "frontend"

# Create new window (Ctrl+B, C)
cd ~/projects/api
openportal --name "backend"

# Create another window
cd ~/projects/mobile
openportal --name "mobile"

# Navigate between windows: Ctrl+B, 0/1/2
# Detach: Ctrl+B, D
# Reattach: tmux attach -t portals

Using PM2 Process Manager

PM2 provides excellent process management with monitoring:
# Install PM2
npm install -g pm2

# Start instances with PM2
pm2 start openportal --name "frontend" -- --port 3000 --directory ~/projects/website
pm2 start openportal --name "backend" -- --port 3001 --directory ~/projects/api
pm2 start openportal --name "mobile" -- --port 3002 --directory ~/projects/mobile

# View all processes
pm2 list

# View logs
pm2 logs frontend
pm2 logs backend

# Auto-start on system boot
pm2 startup
pm2 save

# Stop specific instance
pm2 stop frontend

# Restart instance
pm2 restart backend

Resource Management

Monitoring Resource Usage

# Check memory and CPU usage per instance
top -p $(pgrep -f openportal | tr '\n' ',')

# Or use htop for better visualization
htop -p $(pgrep -f openportal | tr '\n' ',')

Resource Limits

If running many instances on limited resources:
# Limit resources using systemd (in service file)
[Service]
MemoryLimit=512M
CPUQuota=50%
Or with Docker (see next section).

Docker Multi-Instance Setup

Run instances in isolated containers:
# docker-compose.yml
version: '3.8'

services:
  portal-frontend:
    image: oven/bun:latest
    working_dir: /app/website
    command: bunx openportal --hostname 0.0.0.0
    ports:
      - "3000:3000"
      - "4000:4000"
    volumes:
      - ./projects/website:/app/website
    restart: unless-stopped

  portal-backend:
    image: oven/bun:latest
    working_dir: /app/api
    command: bunx openportal --hostname 0.0.0.0
    ports:
      - "3001:3000"
      - "4001:4000"
    volumes:
      - ./projects/api:/app/api
    restart: unless-stopped

  portal-mobile:
    image: oven/bun:latest
    working_dir: /app/mobile
    command: bunx openportal --hostname 0.0.0.0
    ports:
      - "3002:3000"
      - "4002:4000"
    volumes:
      - ./projects/mobile:/app/mobile
    restart: unless-stopped
Start all instances:
docker-compose up -d

# View logs
docker-compose logs -f portal-frontend

# Stop all
docker-compose down

Best Practices

Use consistent, descriptive names:
  • Include project name: client-acme-frontend
  • Include environment: api-staging, api-production
  • Keep it short but meaningful: docs, admin-panel
  • Avoid special characters: use hyphens, not spaces or underscores
Maintain a port allocation document:
# Port Allocations

| Project          | Web UI | OpenCode | Notes          |
|------------------|--------|----------|----------------|
| website-frontend | 3000   | 4000     | Main website   |
| api-backend      | 3001   | 4001     | REST API       |
| admin-panel      | 3002   | 4002     | Admin UI       |
| docs-site        | 3003   | 4003     | Documentation  |
  • Use clear session names within each instance
  • Delete old sessions regularly to avoid clutter
  • Keep sessions focused on specific features or bugs
  • Document session purposes in the first message
OpenCode sessions are stored in:
~/.config/opencode/sessions/
Each instance shares this directory. To separate instances completely, use different user accounts or Docker containers.

Troubleshooting

Error: Port 3000 is already in useSolutions:
  1. Check what’s using the port:
    lsof -i :3000
    
  2. Use a different port:
    openportal --port 3010
    
  3. Stop the conflicting process:
    kill $(lsof -t -i:3000)
    
Issue: Started instance but it doesn’t appear in openportal listDebug:
  1. Check if process is running:
    ps aux | grep openportal
    
  2. Clean stale entries:
    openportal clean
    
  3. Check registry file:
    cat ~/.config/openportal/registry.json
    
Symptoms: Server becomes slow with many instancesSolutions:
  1. Check resource usage:
    htop
    
  2. Limit number of concurrent instances
  3. Increase server RAM
  4. Use resource limits (systemd or Docker)
  5. Stop unused instances:
    openportal stop --name "unused-instance"
    
Issue: Sessions appearing in wrong instanceExplanation: All instances share the same OpenCode sessions directory.Workarounds:
  1. Use clear session naming: [project-name] feature description
  2. Run instances as different users
  3. Use Docker with separate volumes
  4. Delete sessions from the correct instance context

Next Steps

Build docs developers (and LLMs) love