A terminal-based hacking game server built in Go, featuring a virtual filesystem, network exploration, and tool-based gameplay. Available via both SSH and WebSocket (browser) interfaces.
For development, simply run:
make devThis will build all binaries and start the combined server (SSH on port 2222, Web on port 8080).
See the Building and Running sections below for more details.
- GAMEPLAY.md - Complete gameplay guide with commands, strategies, and tips
- README.md (this file) - Technical documentation for building, running, and deploying
The game features a procedural generation system that automatically creates missions and servers when static content is exhausted, ensuring players always have new content to explore. See GAMEPLAY.md for details.
The project supports three deployment options:
- Combined Server (
cmd/all) - Runs both SSH and WebSocket servers together (recommended for single-machine deployments) - SSH Server (
cmd/ssh) - Traditional SSH terminal interface only - Web Server (
cmd/web) - HTTP/WebSocket server for browser access only
All servers share the same core game logic and can use the same database. The combined server is the easiest way to get started, while separate servers allow for independent scaling and deployment.
Binaries are built to the bin/ directory (which is gitignored). The project includes a Makefile for convenient build and run commands.
For development, use the dev command to build and start the combined server:
make devThis will:
- Build all binaries (SSH, Web, and Combined)
- Start the combined server (SSH on port 2222, Web on port 8080)
The project includes a Makefile with convenient commands:
# Build all binaries
make build # or: make build-all
# Build specific binaries
make build-ssh # SSH server only
make build-web # Web server only
# Build and run
make dev # Build all + start combined server (recommended for dev)
make run # Build all + start combined server (alias for run-all)
make run-ssh # Build and run SSH server only
make run-web # Build and run Web server only
# Clean built binaries
make clean
# Show all available commands
make helpIf you prefer to build manually:
Build SSH Server:
mkdir -p bin
go build -o bin/terminal.sh-ssh ./cmd/sshBuild Web Server:
go build -o bin/terminal.sh-web ./cmd/webBuild Combined Server:
go build -o bin/terminal.sh ./cmd/allBuild All:
mkdir -p bin
go build -o bin/terminal.sh-ssh ./cmd/ssh
go build -o bin/terminal.sh-web ./cmd/web
go build -o bin/terminal.sh ./cmd/allFor development, use the dev command to build and start everything:
make devThis will:
- Build all binaries
- Start the combined server (SSH + Web)
The server will start:
- SSH server on
0.0.0.0:2222(default) - Web server on
0.0.0.0:8080(default)
If you've already built the binaries, you can run directly:
./bin/terminal.shOr using Makefile:
make run # Builds and runs combined serverThis will start:
- SSH server on
0.0.0.0:2222(default) - Web server on
0.0.0.0:8080(default)
./bin/terminal.sh-sshOr using Makefile:
make run-ssh # Builds and runs SSH server onlyThe SSH server will listen on 0.0.0.0:2222 by default.
./bin/terminal.sh-webOr using Makefile:
make run-web # Builds and runs Web server onlyThe web server will listen on 0.0.0.0:8080 by default.
You can also run both servers in separate terminals:
# Terminal 1
make run-ssh # or: ./bin/terminal.sh-ssh
# Terminal 2
make run-web # or: ./bin/terminal.sh-webConfiguration can be set via:
- Environment variables (production/Docker - recommended)
.envfile (local development - optional, gitignored)
Environment variables take precedence over .env file values. For local development, create a .env file from .env.example:
cp .env.example .env
# Edit .env with your settingsHOST- Host to bind to (default:0.0.0.0)PORT- Port to listen on (default:2222)HOSTKEY_PATH- Path to SSH host key file (optional)- If not provided, defaults to
.ssh/ssh_host_key - The Wish framework will automatically generate a new host key if the file doesn't exist
- Important: The host key identifies your SSH server to clients. Keep it consistent across restarts to avoid "host key changed" warnings
- SSH keys are gitignored (see
.gitignore)
- If not provided, defaults to
DATABASE_PATH- Path to SQLite database file (default:data/terminal.db)JWT_SECRET- Secret key for JWT tokens (default:change-this-secret-key-in-production)
WEB_HOST- Host to bind to (default: same asHOSTor0.0.0.0)WEB_PORT- Port to listen on (default:8080)DATABASE_PATH- Path to SQLite database file (default:data/terminal.db, used whenDATABASE_URLis not set)DATABASE_URL- PostgreSQL connection URL (optional, if set, uses PostgreSQL instead of SQLite)JWT_SECRET- Secret key for JWT tokens (default:change-this-secret-key-in-production)
Both servers use the same database by default. For separate deployments, you can:
- Use the same
DATABASE_PATHfor SQLite (file must be accessible to both) - Use
DATABASE_URLfor PostgreSQL (recommended for separate containers)
The server supports both SQLite (default) and PostgreSQL. Switching is automatic based on configuration:
By default, the server uses SQLite. The database file is created at data/terminal.db. The data/ directory will be created automatically if it doesn't exist.
Configuration:
DATABASE_PATH- Path to SQLite database file (default:data/terminal.db)DATABASE_URL- Leave unset or empty
Examples:
# Using default (data/terminal.db)
./bin/terminal.sh
# Custom SQLite location
DATABASE_PATH=/var/lib/terminal.sh/terminal.db ./bin/terminal.sh
# In-memory SQLite (testing only)
DATABASE_PATH=:memory: ./bin/terminal.shTo use PostgreSQL, set the DATABASE_URL environment variable. When DATABASE_URL is set, DATABASE_PATH is ignored.
Configuration:
DATABASE_URL- PostgreSQL connection URL (required)- Format:
postgres://user:password@host:port/dbnameorpostgresql://user:password@host:port/dbname
Examples:
# Local PostgreSQL
DATABASE_URL=postgres://user:password@localhost:5432/terminal_sh ./bin/terminal.sh
# Remote PostgreSQL
DATABASE_URL=postgres://user:password@db.example.com:5432/terminal_sh ./bin/terminal.sh
# PostgreSQL with SSL
DATABASE_URL=postgres://user:password@db.example.com:5432/terminal_sh?sslmode=require ./bin/terminal.shNote: The data/ directory and all .db files are gitignored, so your SQLite database won't be committed to the repository.
terminal.sh/
├── cmd/
│ ├── all/
│ │ └── main.go # Combined server entry point (SSH + Web)
│ ├── ssh/
│ │ └── main.go # SSH server entry point
│ └── web/
│ └── main.go # WebSocket server entry point
├── terminal/
│ ├── ssh/ # SSH-specific terminal code
│ │ └── server.go
│ ├── websocket/ # WebSocket-specific terminal code
│ │ ├── server.go
│ │ ├── bridge.go
│ │ ├── messages.go
│ │ └── http.go
│ ├── login.go # Shared login model
│ ├── shell.go # Shared shell model
│ ├── chat.go # Chat UI model
│ └── ...
├── cmd/ # Command handlers
│ ├── chat_commands.go # Chat command handlers
│ └── ...
├── services/ # Business logic
│ ├── chat.go # Chat service
│ └── ...
├── models/ # Data models
│ ├── chat.go # Chat data models
│ └── ...
├── database/ # Database layer
├── config/ # Configuration
├── filesystem/ # Virtual filesystem
├── web/ # Frontend files (HTML, JS, CSS)
│ ├── index.html
│ ├── terminal.js
│ └── style.css
└── Dockerfile # Docker build file
Combined Server (Default):
docker build -t terminal.sh .SSH Server Only:
docker build -t terminal.sh-ssh --target ssh .Web Server Only:
docker build -t terminal.sh-web --target web .Combined Server (Recommended):
docker run -p 2222:2222 -p 8080:8080 \
-e PORT=2222 \
-e WEB_PORT=8080 \
-e DATABASE_PATH=/data/terminal.db \
-v $(pwd)/data:/data \
terminal.shCombined Server - with .env file:
docker run -p 2222:2222 -p 8080:8080 \
--env-file .env \
-v $(pwd)/data:/data \
terminal.shSSH Server Only:
docker run -p 2222:2222 \
-e PORT=2222 \
-v $(pwd)/data:/data \
terminal.sh-sshSSH Server Only - with .env file:
docker run -p 2222:2222 \
--env-file .env \
-v $(pwd)/data:/data \
terminal.sh-sshWeb Server Only:
docker run -p 8080:8080 \
-e WEB_PORT=8080 \
-v $(pwd)/data:/data \
terminal.sh-webWeb Server Only - with .env file:
docker run -p 8080:8080 \
--env-file .env \
-v $(pwd)/data:/data \
terminal.sh-webNote: The default DATABASE_PATH is data/terminal.db, which will be created in the container at /data/terminal.db when you mount $(pwd)/data:/data.
For deploying both servers with a shared SQLite database:
version: "3.8"
services:
ssh-server:
build:
context: .
target: ssh
env_file:
- .env # Optional: load from .env file
environment:
- PORT=2222
- DATABASE_PATH=/data/terminal.db
volumes:
- ./data:/data
ports:
- "2222:2222"
web-server:
build:
context: .
target: web
env_file:
- .env # Optional: load from .env file
environment:
- WEB_PORT=8080
- DATABASE_PATH=/data/terminal.db
volumes:
- ./data:/data
ports:
- "8080:8080"For deploying both servers with PostgreSQL:
version: "3.8"
services:
postgres:
image: postgres:15
environment:
- POSTGRES_USER=terminal_sh
- POSTGRES_PASSWORD=changeme
- POSTGRES_DB=terminal_sh
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
ssh-server:
build:
context: .
target: ssh
env_file:
- .env # Optional: load from .env file
environment:
- PORT=2222
- DATABASE_URL=postgres://terminal_sh:changeme@postgres:5432/terminal_sh
depends_on:
- postgres
ports:
- "2222:2222"
web-server:
build:
context: .
target: web
env_file:
- .env # Optional: load from .env file
environment:
- WEB_PORT=8080
- DATABASE_URL=postgres://terminal_sh:changeme@postgres:5432/terminal_sh
depends_on:
- postgres
ports:
- "8080:8080"
volumes:
postgres_data:Note:
- SQLite: The
data/directory will be created automatically on first run. Both servers share the same database file. - PostgreSQL: Both servers connect to the same PostgreSQL database. Recommended for production and multi-container deployments.
- Go 1.25.5 or later
- SQLite (for default database)
Option 1: Combined (Recommended)
go run ./cmd/allThis starts both servers. Connect via:
- SSH:
ssh -p 2222 username@localhost - Web: Open
http://localhost:8080in your browser
Option 2: Separate
-
Start SSH server:
go run ./cmd/ssh
-
Start Web server (in another terminal):
go run ./cmd/web
-
Connect:
- SSH:
ssh -p 2222 username@localhost - Web: Open
http://localhost:8080in your browser
- SSH:
Both servers provide identical functionality. For gameplay testing, see GAMEPLAY.md.
ISC