Мгновенный обратный SSH — self-hosted аналог tmate / ngrok / scp для машины за NAT
ssh.swag.best • Releases • Установка • Как работает • Сборка
swagSSH позволяет подключиться к любому компьютеру за NAT, файрволом или CG-NAT одной командой. Никакого проброса портов, VPN, Tailscale или WireGuard. Только исходящее SSH-соединение к вашему серверу.
- Пользователь выполняет одну команду и получает ID сессии
- Оператор вводит этот ID и получает полноценный интерактивный терминал, может передавать файлы и запускать команды
- Сервер релеит трафик между ними, не храня ничего на диске
Windows:
iwr -useb https://ssh.swag.best/install.ps1 | iexLinux / macOS:
curl -fsSL https://ssh.swag.best/install.sh | bashПосле выполнения появится ID сессии вида swag-a8f2d1.
Скачайте бинарник под вашу платформу из Releases или соберите из исходников:
swagssh connect swag-a8f2d1swagssh share [options] поделиться терминалом этой машины
--id <name> свой ID сессии (например, my-laptop)
--ttl <duration> время жизни сессии: 1m..24h (по умолчанию 1h)
--no-reconnect не переподключаться при обрыве сети
--retries <n> попыток подключения (по умолчанию 5)
swagssh connect <id> интерактивный терминал
swagssh send <id> <path> [-o name] отправить файл или директорию (аналог scp)
swagssh recv <id> <path> [-o name] забрать файл или директорию (аналог scp)
swagssh exec <id> <command...> выполнить команду, вывести результат и код выхода
swagssh version версия
Глобальный флаг --server host:port меняет релей (по умолчанию ssh.swag.best:2222).
# расшарить машину на 30 минут с запоминающимся ID
swagssh share --id my-laptop --ttl 30m
# подключиться к терминалу
swagssh connect my-laptop
# передать файл (как scp)
swagssh send my-laptop ./report.pdf
swagssh send my-laptop ./project/ # директория уедет рекурсивно (tar)
# забрать файл / директорию
swagssh recv my-laptop /var/log/app.log
swagssh recv my-laptop /etc/nginx/ -o nginx-config
# выполнить команду без интерактива
swagssh exec my-laptop "uname -a"
swagssh exec my-laptop "df -h /" ; echo "exit: $?"Пользователь ──(исходящее SSH)──▶ РЕЛЕ-СЕРВЕР ◀──(исходящее SSH)── Оператор
│ swagSSH │
│ ssh.swag.best:2222 │
▼ ▼
[PTY] shell терминал, файлы,
powershell / bash команды (exec)
- Пользователь запускает
swagssh share— клиент создаёт локальный PTY, запускает shell и устанавливает исходящее SSH-соединение с сервером - Сервер генерирует короткий ID сессии (
swag-xxxxxx) или принимает пользовательский (--id), сохраняет канал в памяти и выводит ID пользователю - Оператор подключается:
connectдаёт терминал,send/recvпередают файлы и директории,execвыполняет команду — сервер открывает отдельные SSH-каналы к машине пользователя и прозрачно релеит байты
Файлы идут по тем же SSH-каналам (шифрование, flow control), директории упаковываются в tar на лету. Ничего не пишется на диск сервера.
| Одна команда | Без установщиков, конфигураций и регистраций |
| Обход NAT | Работает через CG-NAT, файрволы и любые ограничения |
| Self-hosted | Весь трафик через ваш сервер, полный контроль |
| Кроссплатформенность | Windows, Linux, macOS (amd64 / arm64 / 386) — один бинарник |
| Файлы как в scp | send / recv для файлов и директорий, с прогрессом и проверкой доставки |
| exec | Однократный запуск команды без открытия терминала |
| Свои ID и TTL | --id my-laptop --ttl 30m — сессия на заданное время |
| Живучесть | Авто-реконнект с сохранением ID и shell, keepalive, ретраи с backoff |
| TOFU-защита | Host key сервера запоминается при первом соединении, смена = предупреждение о MITM |
| End-to-End шифрование | SSH + Ed25519, эфемерные сессии |
| Интерактивный терминал | PTY, resize, vim, htop, tmux, PowerShell |
├── cmd/
│ ├── server/main.go # SSH Relay Server (systemd-сервис)
│ └── client/ # CLI клиент
│ ├── main.go # команды share/connect/send/recv/exec
│ ├── share.go # шеринг: PTY, реконнект, keepalive
│ ├── shareaux.go # приём файлов/exec на стороне пользователя
│ ├── transfer.go # send/recv на стороне оператора
│ ├── exec.go # exec на стороне оператора
│ ├── knownhosts.go # TOFU known_hosts
│ ├── connect_unix.go # терминал оператора (Unix)
│ ├── connect_windows.go# терминал оператора (Windows)
│ ├── pty_unix.go # Unix PTY
│ └── pty_windows.go # Windows pipe-PTY
├── internal/proto/ # общий wire-протокол (каналы, init, статусы)
├── web/
│ ├── index.html # Лендинг
│ ├── install.sh # Установщик Linux/macOS
│ └── install.ps1 # Установщик Windows
└── dist/ # Скомпилированные бинарники
| Слой | Технология |
|---|---|
| Язык | Go 1.22+ |
| SSH | golang.org/x/crypto/ssh |
| PTY (Unix) | github.com/creack/pty |
| PTY (Windows) | Pipe-эмуляция с CR/LF-конверсией |
| Архивы (директории) | archive/tar (потоково, без диска) |
| Веб-сервер | Nginx + Let's Encrypt (автопродление certbot) |
| Управление сессиями | sync.Map in-memory + TTL cleanup |
| Сервис | systemd |
# Сервер
go build -ldflags="-s -w" -o swagssh-server ./cmd/server/
# Клиент (все платформы)
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o dist/swagssh-linux-amd64 ./cmd/client/
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o dist/swagssh-linux-arm64 ./cmd/client/
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o dist/swagssh-darwin-amd64 ./cmd/client/
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o dist/swagssh-darwin-arm64 ./cmd/client/
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o dist/swagssh-windows-amd64.exe ./cmd/client/
GOOS=windows GOARCH=386 go build -ldflags="-s -w" -o dist/swagssh-windows-386.exe ./cmd/client/# systemd сервис
systemctl enable --now swagssh
# Флаги сервера
# -port 2222 порт релея
# -host-key <path> Ed25519 host key (генерируется при первом запуске)
# -max-sessions 256 максимум одновременных сессий
# -max-conns-per-ip 16 максимум одновременных соединений с одного IP
# -admin 127.0.0.1:8022 админ-панель (пусто = выключена)
# -admin-password-file <path> пароль админки из файла
# -ban-file /etc/swagssh/bans.json персистентные баны IP (переживают рестарт)
# Nginx конфигурация
# /etc/nginx/sites-available/swagssh
# server_name ssh.swag.best;
# Проксирует: web/ → лендинг, /releases/ → dist/, /install.* → скриптыswagssh-server -admin 127.0.0.1:8022 -admin-password-file /etc/swagssh/admin.pass -ban-file /etc/swagssh/bans.jsonПанель слушает только localhost — наружу публикуется через nginx (location /admin/ { proxy_pass http://127.0.0.1:8022/; }). Вход по паролю (cookie-сессия, HttpOnly + SameSite=Strict, Secure за HTTPS), 5 неверных попыток = бан IP на час.
Что видно и чем можно управлять:
- Сессии — live-просмотр: ID, IP пользователя, TTL, подключённый оператор, трафик; разрыв сессии одной кнопкой
- История — завершённые сессии: кто делился, кто подключался оператором и когда, сколько трафика прошло
- IP-адреса — коннекты, сессии, фейлы хендшейка, перебор ID; блокировка на 1ч / 24ч / 7д / 30д / навсегда (персистентно)
- События — полный журнал: создания/закрытия сессий, подключения операторов, передачи, баны, отклонённые коннекты
Защита от перебора ID сессий: 10 несуществующих ID за 10 минут с одного IP → автобан (24ч → 7д → навсегда при рецидивах). Все баны пишутся в JSON-файл и переживают рестарт сервера.
- Ed25519 host-ключи (генерируются автоматически при первом запуске)
- TOFU: клиент запоминает host key сервера (
known_hosts) и прерывает соединение при его смене — защита от MITM (--insecure-host-keyдля обхода) - Эфемерные сессии — ничего не хранится на диске сервера
- TTL сессии: от 1 минуты до 24 часов (по умолчанию 1 час), не продлевается при реконнекте, автоматическая очистка
- Криптографически безопасная генерация ID сессий (
crypto/rand) - Лимиты: максимум сессий и соединений с одного IP, таймаут хендшейка
- При приёме файлов имена санитизируются (без
..и абсолютных путей), tar-архивы распаковываются только внутри целевой директории - Все данные только в памяти
* swagSSH®