Professional open-source server management console — clone, run
setup.sh, done.
| Feature | Description |
|---|---|
| Docker Management | Full container lifecycle via /var/run/docker.sock using dockerode |
| Container Factory | Create and duplicate containers with image/env/cmd/ports/volumes/networks |
| Container Port Forwarding | Portainer-style managed TCP forwards per container (host port -> container port) |
| Granular RBAC | Per-container, per-path, per-feature permissions — mapped to individual users |
| File Explorer | Touch-optimized explorer via host mount or remote SFTP backend |
| Diff Viewer | Compare unsaved changes for stack/config files directly in the browser before saving |
| Drag & Drop Uploads | Upload files and whole folders into the file explorer via folder picker or drag & drop |
| Multi-session Terminal | xterm.js with local PTY or remote SSH shell backend |
| SSH Key Backend | Remote Terminal + Files support encrypted SSH private keys instead of password-only auth |
| User Management | Admin UI to create users and assign surgical permissions |
| Audit Log | Every action is recorded with user, IP, resource, and outcome |
| Dark Mode | Enterprise-grade UI built with Tailwind CSS + Shadcn/UI |
- Docker Engine ≥ 24
- Docker Compose v2
- Linux host (the app mounts
/var/run/docker.sockand/)
git clone https://github.com/your-org/ServerCommander.git
cd ServerCommander
bash setup.shIf you want to wipe all local runtime data and start clean:
./reset.shreset.sh removes for this project:
- Compose containers/networks
- Compose volumes (including SQLite data)
- Locally built images
.envand backup env files- Build/cache artifacts (
node_modules,.next,dist, logs, local db files)
User
└── UserPermission (1-to-1)
├── Docker Global Flags
│ dockerAccess, dockerViewAll, dockerImages,
│ dockerVolumes, dockerNetworks, dockerCreate, dockerDelete
│
├── ContainerPermission[] (whitelist entries)
│ containerId, containerName
│ canView, canStart, canStop, canRestart,
│ canDelete, canLogs, canExec, canInspect
│
├── FsPathPermission[] (path-based grants)
│ path (e.g. /var/www), readOnly, canCreate, canDelete
│
└── Terminal
terminalAccess, terminalReadOnly, terminalMaxSessions
Container whitelist logic:
- When
dockerViewAll = true→ user sees all containers - When
dockerViewAll = false→ only containers explicitly whitelisted appear; all Docker API calls are intercepted and filtered server-side before the response is sent to the browser
servercommander-os/
├── setup.sh # Interactive installer
├── docker-compose.yml # App + volumes + mounts
├── Dockerfile # Multi-stage Next.js build
├── docker-entrypoint.sh # Migrations + seed + start
├── server.mjs # Custom HTTP + Socket.IO server
├── prisma/
│ ├── schema.prisma # Full RBAC schema (SQLite)
│ └── seed.ts # Admin user seeder
└── src/
├── middleware.ts # JWT auth guard (all routes)
├── lib/
│ ├── auth.ts # JWT sessions, cookie helpers
│ ├── rbac.ts # All permission check functions
│ ├── docker.ts # Dockerode wrapper
│ ├── db.ts # Prisma singleton
│ └── audit.ts # Audit log writer
├── app/
│ ├── api/
│ │ ├── auth/ # login, logout, me
│ │ ├── docker/ # containers, images
│ │ ├── users/ # CRUD + container-perms + fs-perms
│ │ ├── files/ # Host filesystem API
│ │ └── audit/ # Audit log endpoint
│ └── (dashboard)/
│ ├── dashboard/ # Overview + stats
│ ├── containers/ # Container list + controls
│ ├── files/ # File explorer
│ ├── terminal/ # xterm.js multi-session
│ ├── users/ # User management (admin)
│ └── users/[id]/ # Permission editor UI
└── components/
├── layout/ # Sidebar, TopBar
├── dashboard/ # StatusCard
├── docker/ # ContainerTable
├── files/ # FileExplorer
├── terminal/ # TerminalManager
└── users/ # UsersTable, UserPermissionsEditor
All configuration lives in .env (generated by setup.sh):
| Variable | Description |
|---|---|
SESSION_SECRET |
64-char secret for session signing |
JWT_SECRET |
64-char secret for JWT tokens |
ADMIN_USERNAME |
Initial admin username |
ADMIN_PASSWORD |
Initial admin password |
SESSION_MAX_AGE |
Session duration in seconds (default 8h) |
DOCKER_SOCKET |
Docker socket path (default /var/run/docker.sock) |
HOST_FS_MOUNT |
Host filesystem mount point inside container |
SSH_ENABLED |
Enable remote SSH/SFTP backend for Terminal + Files (true/false) |
SSH_HOST |
Remote SSH host/IP |
SSH_PORT |
Remote SSH port |
SSH_USERNAME |
Remote SSH username |
SSH_PASSWORD_ENC |
Encrypted remote SSH password, optional when using keys |
SSH_PRIVATE_KEY_ENC |
Encrypted OpenSSH private key for Terminal + Files backend |
SSH_KEY_PASSPHRASE_ENC |
Encrypted passphrase for the SSH private key, optional |
SSH_SFTP_ROOT |
Root directory used for SFTP operations |
ServerCommander now supports SSH key authentication for the remote Terminal and SFTP-backed File Explorer. The recommended path is:
- Generate a dedicated key pair on the machine where you run setup:
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/servercommander_ed25519 -C "servercommander"- Install the public key on the target host:
ssh-copy-id -i ~/.ssh/servercommander_ed25519.pub user@your-serverIf ssh-copy-id is not available, append the .pub file manually to ~/.ssh/authorized_keys on the target server.
-
Run
bash setup.sh, enable SSH/SFTP, choose key-based authentication, and point the installer to your private key file. -
If your private key has a passphrase, enter it when the installer asks for it. The private key and passphrase are encrypted into
.envusingENCRYPTION_KEY.
An SSH key is not downloaded from a vendor. You generate it yourself.
- For Linux and macOS,
ssh-keygenis usually already installed through OpenSSH. - On Windows, use PowerShell or Git Bash and run the same
ssh-keygencommand. - If you already have a key like
~/.ssh/id_ed25519, you can reuse it, but a dedicated key for ServerCommander is cleaner and easier to revoke.
Recommended commands:
# Create a new dedicated Ed25519 key pair
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/servercommander_ed25519 -C "servercommander"
# Show the public key you need to install on the remote host
cat ~/.ssh/servercommander_ed25519.pub
# Test the connection before running setup
ssh -i ~/.ssh/servercommander_ed25519 user@your-serverWhat each file means:
~/.ssh/servercommander_ed25519: your private key, keep it secret~/.ssh/servercommander_ed25519.pub: your public key, this goes on the server
Security notes for keys:
- Prefer Ed25519 keys over RSA for new setups.
- Use a passphrase when possible.
- Do not commit private keys into Git.
- If a key is compromised, remove its public key from
authorized_keyson the server and generate a new pair.
- The Docker socket is mounted read-only in Docker Compose; write operations are proxied through the app which enforces RBAC before every API call
- Host filesystem is mounted with
rslavepropagation; all path operations are sandboxed via prefix-matching and directory traversal prevention - Session tokens are HTTP-only, SameSite=Lax cookies — never accessible from JavaScript
- Passwords are hashed with
bcrypt(cost factor 12) - SSH private keys and registry credentials are stored encrypted in
.envusingENCRYPTION_KEY - All privileged actions are written to the
AuditLogtable no-new-privileges:truesecurity opt is set on the container
MIT — Use freely, contribute back.