@hahahhh/sshx 0.0.2-rc.1 → 0.0.3-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> Transparent SSH enhancement — add remote-to-local commands, auto port forwarding, and local domains to your SSH workflow. Zero side effects when you don't need them.
|
|
4
4
|
|
|
5
|
-
**sshx** is a drop-in wrapper around OpenSSH. Wrap it as `alias ssh=sshx` and your existing SSH workflow works exactly as before — every flag, config, and connection passes through verbatim. But when you connect to a host with sshx-aware features enabled, you unlock a persistent, shared remote server that gives you:
|
|
5
|
+
**sshx** is a drop-in wrapper around OpenSSH. Wrap it as `alias ssh=sshx` and your existing SSH workflow works exactly as before — every flag, config, and connection passes through verbatim. But when you connect to a host (or Docker container) with sshx-aware features enabled, you unlock a persistent, shared remote server that gives you:
|
|
6
6
|
|
|
7
7
|
- 🔄 **Reverse command bridge** — run `sshx local <cmd>` *on the remote* to execute commands on your local machine, with stdout, stderr, exit code, and stdin all propagated.
|
|
8
8
|
- 🔌 **Automatic port forwarding** — remote loopback listeners (e.g., a dev server on `localhost:8080`) are automatically detected and forwarded to your local machine.
|
|
9
9
|
- 🌐 **Local domain binding** — access forwarded ports as `<host>.<your-user>.sshx:<port>` in your local browser, no manual `-L` flags needed.
|
|
10
|
+
- 🐳 **Docker container support** — target running containers by name or ID: `sshx my-container`. Command bridge support works inside containers via `docker exec`.
|
|
10
11
|
|
|
11
12
|
## Why sshx?
|
|
12
13
|
|
|
@@ -31,6 +32,16 @@ sshx is designed to be **safe to alias**. Hosts without sshx configuration are u
|
|
|
31
32
|
- `~/.ssh/config` resolution is handled by OpenSSH — no reimplementation.
|
|
32
33
|
- Bypass with `sshx --no-wrap` or `SSHX_DISABLE=1` at any time.
|
|
33
34
|
|
|
35
|
+
### 🐳 Docker Container Target
|
|
36
|
+
|
|
37
|
+
When the target doesn't match any SSH host, sshx falls back to resolving it as a running Docker container:
|
|
38
|
+
|
|
39
|
+
- `sshx <container-name>` — opens a shell in the container via `docker exec`.
|
|
40
|
+
- `sshx <container-id-prefix>` — matches by container ID prefix.
|
|
41
|
+
- Explicit SSH targets (`user@host`, IP addresses, hostnames with dots/colons) are never treated as Docker containers.
|
|
42
|
+
- Command bridge support works inside containers.
|
|
43
|
+
- Requires `docker` CLI available on the local machine — gracefully falls back to SSH if Docker isn't found or the container isn't running.
|
|
44
|
+
|
|
34
45
|
### 🔄 Remote-to-Local Command Bridge
|
|
35
46
|
|
|
36
47
|
Run commands on your **local machine** from inside an SSH session:
|
|
@@ -51,15 +62,15 @@ sshx local pbcopy < /tmp/some-data
|
|
|
51
62
|
When a process on the remote starts listening on `127.0.0.1` (e.g., `npm run dev` on port 3000), sshx detects it and:
|
|
52
63
|
|
|
53
64
|
1. Broadcasts the port to the local daemon.
|
|
54
|
-
2.
|
|
55
|
-
3.
|
|
65
|
+
2. Assigns the SSH target its own loopback IP.
|
|
66
|
+
3. Exposes a TCP proxy at the target domain, e.g. `debian.<your-user>.sshx:3000`.
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
The URL port is the remote port. sshx does not bind `127.0.0.1:<port>`; it binds the target's private loopback IP instead, so `debian.<your-user>.sshx:8080` and `ubuntu.<your-user>.sshx:8080` can point at different hosts at the same time. Run `sshx forward` to see the active mappings.
|
|
58
69
|
|
|
59
70
|
### 🌐 Local Domains (macOS, Linux)
|
|
60
71
|
|
|
61
|
-
- A local DNS responder on `127.0.0.1:53` resolves
|
|
62
|
-
-
|
|
72
|
+
- A local DNS responder on `127.0.0.1:53` resolves active target names dynamically.
|
|
73
|
+
- Each target domain resolves to a private loopback IP; the URL port selects the remote listener.
|
|
63
74
|
- On macOS, `/etc/resolver/<suffix>` is configured once (with `sudo` when needed).
|
|
64
75
|
- All terminals on the same host share one DNS resolver and forwarding daemon.
|
|
65
76
|
|
|
@@ -128,6 +139,21 @@ sshx -p 2222 user@my-server hostname
|
|
|
128
139
|
|
|
129
140
|
All existing SSH options work — `-F`, `-o`, `-J`, `ProxyJump`, etc. are handled by OpenSSH.
|
|
130
141
|
|
|
142
|
+
### 1a. Connect to a Docker container
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
# By container name
|
|
146
|
+
sshx my-dev-container
|
|
147
|
+
|
|
148
|
+
# By container ID prefix
|
|
149
|
+
sshx 4fa8bc
|
|
150
|
+
|
|
151
|
+
# Run a command directly
|
|
152
|
+
sshx my-container cat /etc/os-release
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
sshx detects that the target isn't an SSH host and automatically uses `docker exec`. The command bridge and other features work exactly the same inside containers.
|
|
156
|
+
|
|
131
157
|
### 2. Try the command bridge
|
|
132
158
|
|
|
133
159
|
Inside your SSH session on the remote:
|
|
@@ -151,13 +177,12 @@ On your **local** machine, open:
|
|
|
151
177
|
http://my-server.<your-user>.sshx:8080
|
|
152
178
|
```
|
|
153
179
|
|
|
154
|
-
No `-L` flags, no manual forwarding.
|
|
155
|
-
|
|
156
|
-
If local port `8080` is already occupied, sshx will try `8081`, then `8082`, and so on. Check the chosen port with:
|
|
180
|
+
No `-L` flags, no manual forwarding. Since each target gets its own loopback IP, another target can expose its own `8080` at the same time:
|
|
157
181
|
|
|
158
182
|
```sh
|
|
159
183
|
sshx forward
|
|
160
|
-
# 8080 -> my-server:8080
|
|
184
|
+
# http://my-server.<your-user>.sshx:8080 -> my-server:8080
|
|
185
|
+
# http://other-server.<your-user>.sshx:8080 -> other-server:8080
|
|
161
186
|
```
|
|
162
187
|
|
|
163
188
|
---
|
|
@@ -175,17 +200,9 @@ features:
|
|
|
175
200
|
# Remote-to-local command bridge (`sshx local <cmd>` on the remote)
|
|
176
201
|
commandBridge: true
|
|
177
202
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# Future: also detect 0.0.0.0 listeners.
|
|
182
|
-
# bindAll: false
|
|
183
|
-
|
|
184
|
-
domains:
|
|
185
|
-
# Enable local domain binding (<host>.<user>.sshx:<port>).
|
|
186
|
-
enabled: true
|
|
187
|
-
# Custom domain suffix. Default: <local-user>.sshx
|
|
188
|
-
suffix: user.sshx
|
|
203
|
+
# Auto-detect remote loopback TCP listeners and expose them via
|
|
204
|
+
# <host>.<user>.sshx:<remote-port>.
|
|
205
|
+
autoForward: true
|
|
189
206
|
|
|
190
207
|
commands:
|
|
191
208
|
# Commands blocked from bridge execution.
|
|
@@ -216,7 +233,7 @@ commands:
|
|
|
216
233
|
4. **Forwarding**: Detected ports are forwarded through a single shared local daemon using `ssh -W`.
|
|
217
234
|
5. **Domains**: The local DNS responder maps `<target>.<suffix>` → localhost. The browser's URL port selects the local forwarded port.
|
|
218
235
|
|
|
219
|
-
When `sshx` is invoked for a **non-matching host** (no sshx config, or host not in scope), it `exec`s the real `ssh` directly — no daemon, no installation, no overhead.
|
|
236
|
+
When `sshx` is invoked for a **non-matching host** (no sshx config, or host not in scope), it first checks if the target resolves to a running Docker container. If neither SSH nor Docker matches, it `exec`s the real `ssh` directly — no daemon, no installation, no overhead.
|
|
220
237
|
|
|
221
238
|
---
|
|
222
239
|
|
|
@@ -225,20 +242,22 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
|
|
|
225
242
|
- `sshx --no-wrap ...` — skip all sshx behavior and call raw `ssh`.
|
|
226
243
|
- `SSHX_DISABLE=1 sshx ...` — same as `--no-wrap`, useful in scripts.
|
|
227
244
|
- `sshx local ...` on a **client** (not inside a remote session) — errors immediately with a clear message. `local` is globally reserved.
|
|
245
|
+
- Docker containers that aren't running or can't be reached are pure passthrough — sshx falls back to raw `ssh` with no side effects.
|
|
228
246
|
- Unmatched hosts are pure passthrough — no files created, no processes started.
|
|
229
247
|
|
|
230
248
|
---
|
|
231
249
|
|
|
232
250
|
## Platform Support
|
|
233
251
|
|
|
234
|
-
| Platform | Client | Server |
|
|
235
|
-
|
|
236
|
-
| macOS | ✅ | — |
|
|
237
|
-
| Linux | ✅ | ✅ |
|
|
238
|
-
| Windows | 🔜 | — |
|
|
252
|
+
| Platform | Client | Server | Docker Client |
|
|
253
|
+
|---|---|---|---|
|
|
254
|
+
| macOS | ✅ | — | ✅ |
|
|
255
|
+
| Linux | ✅ | ✅ | ✅ |
|
|
256
|
+
| Windows | 🔜 | — | 🔜 |
|
|
239
257
|
|
|
240
258
|
- **Client**: macOS and Linux are fully supported.
|
|
241
259
|
- **Server**: Linux is required for the remote sshx server (uses `/proc/net/tcp*` for port detection).
|
|
260
|
+
- **Docker Client**: macOS and Linux — targets any running Docker container via `docker exec`.
|
|
242
261
|
|
|
243
262
|
---
|
|
244
263
|
|
|
@@ -248,7 +267,7 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
|
|
|
248
267
|
sshx/
|
|
249
268
|
├── cmd/sshx/ # Main entry point
|
|
250
269
|
├── internal/
|
|
251
|
-
│ ├── cli/ # CLI parsing, host detection
|
|
270
|
+
│ ├── cli/ # CLI parsing, host detection, Docker container resolution
|
|
252
271
|
│ ├── sshcompat/ # SSH argument compatibility
|
|
253
272
|
│ ├── config/ # YAML configuration
|
|
254
273
|
│ ├── protocol/ # Client-server wire protocol
|