A terminal-based MMO accessible via SSH. Connect and explore a procedurally generated world with AI-generated avatars.
ssh abyss.maldoror.dev
maldoror.dev/
├── apps/
│ └── ssh-world/ # SSH server application
├── packages/
│ ├── ai/ # AI avatar generation
│ ├── db/ # Database schema (Drizzle + Postgres)
│ ├── protocol/ # Shared types
│ ├── render/ # Terminal rendering
│ ├── world/ # Procedural world generation
│ └── queue/ # Background job processing
└── deploy/ # Deployment configuration
- Node.js 20+
- pnpm 9.15+
- Docker (for PostgreSQL)
# Install dependencies
pnpm install
# Start PostgreSQL
pnpm docker:up
# Push database schema
pnpm db:push
# Generate SSH host key
cd apps/ssh-world && pnpm generate-keys && cd ../..
# Start development server
pnpm dev:sshssh -p 2222 localhostThe project includes a deploy script for Docker-based deployment to any VPS.
- A VPS with SSH access (Ubuntu recommended)
- Your SSH key added to the server
- A domain pointing to your server IP (optional)
- Create the production environment file:
cp deploy/.env.prod.example deploy/.env.prod- Edit
deploy/.env.prodwith your credentials:
POSTGRES_PASSWORD=your_secure_password
AI_PROVIDER=openai
OPENAI_API_KEY=sk-your-key-here
AI_MODEL=gpt-4.1-miniOr for Anthropic:
POSTGRES_PASSWORD=your_secure_password
AI_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-your-key-here
AI_MODEL=claude-sonnet-4-20250514- Update the server IP in
deploy/deploy.shif needed:
SERVER="root@your-server-ip"./deploy/deploy.shThis will:
- Move system SSH to port 22022 (first deploy only)
- Install Docker on the server (if needed)
- Sync project files via rsync
- Build the Docker image
- Start HAProxy, PostgreSQL, and the SSH server
- Initialize the database schema
ssh your-server-ip
# or with a domain
ssh abyss.yourdomain.comSystem SSH is moved to port 22022 to free up port 22 for the game:
ssh -p 22022 root@your-server-ipInternet (port 22) → HAProxy → ssh-world:2222 (game)
Internet (port 22022) → System SSH (admin)
HAProxy provides:
- Zero-downtime deployments: Connections are queued during restarts
- Health checking: Routes only to healthy backends
- Graceful draining: Existing sessions continue during shutdown
- Stats dashboard: Available at
http://your-server:8404/stats
The deployment uses connection draining for seamless restarts:
- New container starts and becomes healthy
- HAProxy routes new connections to new container
- Old container receives SIGTERM
- Old container stops accepting new connections
- Existing sessions continue (up to 5 min drain timeout)
- Player state saved to database on disconnect
- Reconnecting players restore their position automatically
The project also supports Railway deployment with the included Dockerfile and railway.toml.
- Link your repo to Railway
- Add a PostgreSQL database
- Set environment variables:
AI_PROVIDEROPENAI_API_KEYorANTHROPIC_API_KEYAI_MODEL
- Enable TCP Proxy in Settings → Networking on port 2222
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Required |
SSH_PORT |
Port for SSH server | 2222 |
AI_PROVIDER |
openai or anthropic |
anthropic |
OPENAI_API_KEY |
OpenAI API key | - |
ANTHROPIC_API_KEY |
Anthropic API key | - |
AI_MODEL |
Model for avatar generation | claude-sonnet-4-20250514 |
| Command | Description |
|---|---|
pnpm dev:ssh |
Start SSH server in dev mode |
pnpm build |
Build all packages |
pnpm db:push |
Push schema to database |
pnpm db:studio |
Open Drizzle Studio |
pnpm docker:up |
Start local PostgreSQL |
pnpm docker:down |
Stop local PostgreSQL |
./deploy/deploy.sh |
Deploy to production |