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:
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
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:
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:
Check what’s using the port:
Use a different port:
Stop the conflicting process:
Can't find instance in list
Issue: Started instance but it doesn’t appear in openportal listDebug:
Check if process is running:
Clean stale entries:
Check registry file:
cat ~/.config/openportal/registry.json
High memory usage with multiple instances
Symptoms: Server becomes slow with many instancesSolutions:
Check resource usage:
Limit number of concurrent instances
Increase server RAM
Use resource limits (systemd or Docker)
Stop unused instances:
openportal stop --name "unused-instance"
Instances mixing up sessions
Issue: Sessions appearing in wrong instanceExplanation: All instances share the same OpenCode sessions directory.Workarounds:
Use clear session naming: [project-name] feature description
Run instances as different users
Use Docker with separate volumes
Delete sessions from the correct instance context
Next Steps