Skip to content

Commit 14819a8

Browse files
author
Jordan Munch O'Hare
committed
docs: improvement and split deployment
1 parent 095b89a commit 14819a8

File tree

2 files changed

+253
-290
lines changed

2 files changed

+253
-290
lines changed

DEPLOYMENT.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Deployment Guide
2+
3+
## Prerequisites
4+
5+
- Linux server with SSH access enabled
6+
- SSH key pair for passwordless authentication
7+
8+
## Docker (Recommended)
9+
10+
### HTTP Mode
11+
12+
Run as a network-accessible service on your server:
13+
14+
```bash
15+
docker run -d \
16+
-p 3000:3000 \
17+
-e SSH_HOST=server.local \
18+
-e SSH_PORT=22 \
19+
-e SSH_USERNAME=mcp-readonly \
20+
-e SSH_KEY_PATH=/keys/id_ed25519 \
21+
-e OAUTH_SERVER_URL=https://mcp.example.com \
22+
-v ~/.ssh/id_ed25519_mcp:/keys/id_ed25519:ro \
23+
ghcr.io/ohare93/mcp-ssh-sre:latest
24+
```
25+
26+
Or with Docker Compose (`docker-compose.http.yml`):
27+
28+
```yaml
29+
services:
30+
mcp-ssh-sre:
31+
image: ghcr.io/ohare93/mcp-ssh-sre:latest
32+
ports:
33+
- "3000:3000"
34+
environment:
35+
- SSH_HOST=server.local
36+
- SSH_PORT=22
37+
- SSH_USERNAME=mcp-readonly
38+
- SSH_KEY_PATH=/keys/id_ed25519
39+
- OAUTH_SERVER_URL=https://mcp.example.com
40+
volumes:
41+
- ~/.ssh/id_ed25519_mcp:/keys/id_ed25519:ro
42+
```
43+
44+
#### Environment Variables
45+
46+
| Variable | Required | Default | Description |
47+
|----------|----------|---------|-------------|
48+
| `SSH_HOST` | Yes | - | Server hostname or IP |
49+
| `SSH_PORT` | No | 22 | SSH port |
50+
| `SSH_USERNAME` | Yes | - | SSH username |
51+
| `SSH_KEY_PATH` | Yes | - | Path to SSH private key (inside container) |
52+
| `HTTP_PORT` | No | 3000 | HTTP server port |
53+
| `CORS_ORIGIN` | No | * | CORS origin |
54+
| `OAUTH_SERVER_URL` | Prod | - | Public URL for OAuth discovery |
55+
| `REQUIRE_AUTH` | No | true | Require OAuth authentication |
56+
57+
#### MCP Client Configuration
58+
59+
```json
60+
{
61+
"mcpServers": {
62+
"ssh-sre": {
63+
"url": "http://your-server:3000/mcp"
64+
}
65+
}
66+
}
67+
```
68+
69+
### Stdio Mode
70+
71+
For local MCP clients (like Claude Desktop running on the same machine):
72+
73+
```bash
74+
docker build -t mcp-ssh-sre .
75+
docker run -d --env-file .env mcp-ssh-sre
76+
```
77+
78+
## Running Locally
79+
80+
### Installation
81+
82+
```bash
83+
git clone https://github.com/ohare93/mcp-ssh-sre.git
84+
cd mcp-ssh-sre
85+
npm install
86+
npm run build
87+
```
88+
89+
### Configuration
90+
91+
Create a `.env` file:
92+
93+
```bash
94+
SSH_HOST=server.local
95+
SSH_PORT=22
96+
SSH_USERNAME=mcp-readonly
97+
SSH_KEY_PATH=~/.ssh/id_rsa_mcp
98+
```
99+
100+
### Running
101+
102+
```bash
103+
# Stdio mode (for local MCP clients)
104+
node dist/index.js
105+
106+
# HTTP mode
107+
node dist/http-server.js
108+
109+
# Development mode with auto-reload
110+
npm run dev
111+
```
112+
113+
### MCP Client Configuration (Stdio)
114+
115+
```json
116+
{
117+
"mcpServers": {
118+
"ssh-sre": {
119+
"command": "node",
120+
"args": ["/absolute/path/to/mcp-ssh-sre/dist/index.js"]
121+
}
122+
}
123+
}
124+
```
125+
126+
## Security Setup
127+
128+
### Create a Read-Only User
129+
130+
```bash
131+
# On server as root
132+
useradd -m -s /bin/bash mcp-readonly
133+
passwd mcp-readonly
134+
usermod -aG docker mcp-readonly
135+
```
136+
137+
### Generate and Deploy SSH Key
138+
139+
```bash
140+
# On your local machine
141+
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_mcp -C "mcp-ssh-sre"
142+
ssh-copy-id -i ~/.ssh/id_ed25519_mcp.pub mcp-readonly@server.local
143+
```
144+
145+
## Authentication
146+
147+
OAuth authentication is **required by default** (v2.0.0+).
148+
149+
| `REQUIRE_AUTH` | Use Case |
150+
|----------------|----------|
151+
| `true` (default) | Production - require OAuth token |
152+
| `false` | Local dev only - allows unauthenticated |
153+
| `development` | Local dev - logs warnings |
154+
155+
### OAuth Flow
156+
157+
1. Register client:
158+
```bash
159+
curl -X POST http://localhost:3000/register \
160+
-H "Content-Type: application/json" \
161+
-d '{"client_name": "My Client"}'
162+
```
163+
164+
2. Get authorization code (visit in browser):
165+
```
166+
http://localhost:3000/authorize?client_id=YOUR_ID&redirect_uri=YOUR_REDIRECT&state=xyz&response_type=code
167+
```
168+
169+
3. Exchange for token:
170+
```bash
171+
curl -X POST http://localhost:3000/token \
172+
-d grant_type=authorization_code \
173+
-d code=YOUR_CODE \
174+
-d client_id=YOUR_ID \
175+
-d client_secret=YOUR_SECRET
176+
```
177+
178+
## Network Security
179+
180+
- **Don't** expose directly to the internet
181+
- **Do** use VPN/Tailscale or reverse proxy with TLS
182+
- Set `OAUTH_SERVER_URL` when behind a reverse proxy
183+
184+
### Security Checklist
185+
186+
- [ ] `REQUIRE_AUTH=true` in production
187+
- [ ] Server behind firewall/VPN or reverse proxy
188+
- [ ] OAuth credentials stored securely
189+
- [ ] Logs monitored for unauthorized attempts

0 commit comments

Comments
 (0)