TermForge: SSH, файлы и Docker в одном рабочем пространстве

Я начал делать TermForge для себя, чтобы собрать эти операции в одном локальном приложении. Пару слов про приложение - это консоль открывающаяся в бразуере, основый стек это .NET и React.

Что входит в TermForge В приложении есть несколько основных рабочих областей:
Терминал;
Файловый браузер между вашей машиной и сервером;
Редактор файлов на сервер;
Docker;
Диагностика;
Журнал операций;
Если с ssh терминалом все понятно как и с файловым браузером, то вот редактор файлов на сервере для меня был одной из важных фич, так как когда приходится что то редактировать на сервере через nano или vim, то это всегда боль. А сейчас, можно так сказать не отходя от кассы редактировать файлы на сервере, так еще предусмотрен сценарий, что если кто то еще его редактирует, то перед сохранением, система отобразит конфликты в стиле git и их можно будет решить.
По докеру, это просто доп вкладка, которая позволяет видеть какие контейнеры запущены, глянуть их логи, залезть внутрь и все без отдельных комманд.

Как устроено приложение
TermForge работает как локальное веб-приложение. ASP.NET Core запускается на компьютере пользователя, обслуживает HTTP API и WebSocket-соединения и выполняет операции с удалёнными серверами. UI написан на React и TypeScript, а Vite собирает его в статические файлы, которые обслуживает бэкенд.
По умолчанию сервер слушает 127.0.0.1:5023 и открывает браузер со ссылкой одноразового запуска. Эта ссылка создаёт браузерную сессию.
Архитектурно приложение можно разделить на четыре части:
Веб-интерфейс (src/Web). React-компоненты, терминал на xterm.js, редактор Monaco и клиентская работа с API.
Точка входа (src/Api/Entrypoint). ASP.NET Core, жизненный цикл приложения, HTTP- и WebSocket-endpoints, проверка локального доступа.
Логика функций (src/Api/Core). Прикладные сценарии: терминалы, файловые операции, Docker, диагностика, журнал и рабочее пространство.
Инфраструктура (src/Infrastructure). SSH-транспорт и проверка ключей хостов, SQLite через Entity Framework Core, системные хранилища учётных данных и зашифрованный vault.

Почему я выбрал локальное веб-приложение
Такой вариант позволяет использовать привычный веб-стек для интерфейса и оставить системные операции в .NET.
Приложение становится проще поддерживать для Windows, macOS и Linux;
Для меня нативно и удобно работать через браузер с такими вещами;
Безопасность
При этом «локальное» не означает «безопасное» автоматически. Веб-страницы могут обращаться к loopback-адресам, поэтому бэкенд проверяет, кто и откуда к нему обращается. По умолчанию приложение отказывается запускаться с адресом прослушивания, доступным из локальной сети. Сетевой режим можно включить отдельно, с настройками аутентификации и HTTPS.
Безопасность вокруг локального API
У TermForge есть доступ к SSH-сессиям и удалённым файлам, поэтому компрометация локального API может дать доступ к серверам с правами пользователя. Защита касается не только SSH, но и канала между браузером и приложением.
Браузерная сессия и запросы
При запуске приложение создаёт одноразовый токен для открытия браузерной сессии. После обмена токена браузер получает сессионную cookie с HttpOnly и SameSite=Strict. Из JavaScript прочитать её нельзя.
Для изменяющих состояние API-запросов нужен CSRF-токен и корректный Origin. WebSocket-подключения также проходят проверку Origin. Отдельная проверка Host помогает защититься от DNS rebinding.
Проверка SSH host key
При подключении TermForge проверяет ключ SSH-сервера. Неизвестный ключ не принимается молча: приложение показывает fingerprint и ждёт решения пользователя. Если известный ключ изменился, соединение блокируется до отдельного подтверждения.
Системный ~/.ssh/known_hosts читается, но не изменяется. Ключи, которым пользователь доверяет через TermForge, сохраняются отдельно в SQLite. Это позволяет приложению не менять файл, которым пользуются OpenSSH и другие инструменты.
Учётные данные
Пароли хранятся в Windows Credential Manager, macOS Keychain или Linux Secret Service, если соответствующее хранилище доступно. В противном случае TermForge использует зашифрованный vault: PBKDF2-HMAC-SHA256 для выработки ключа и AES-256-GCM для шифрования данных. После запуска такой vault нужно разблокировать мастер-паролем.
Подтверждения и режим только для чтения
Для потенциально опасных операций, например удаления файла с сервера, перезапуска контейнера, отката или перезаписи файла, предусмотрены подтверждения. Режим read-only блокирует определённые операции в бэкенде: загрузки, удаления, переименования, сохранения и действия с Docker.
У этого режима есть важная граница: терминал остаётся обычной SSH-оболочкой с правами подключённого пользователя. Баннер read-only не ограничивает команды оболочки. Это не замена системным правам доступа или изоляции на самом сервере.
Кейс: найти причину сбоя
Предположим, приложение на сервере перестало отвечать. В TermForge я могу:
Открыть SSH-терминал и проверить состояние сервера;
Перейти к Docker и посмотреть статус контейнера и его логи;
Открыть конфигурационный файл в удалённом редакторе;
Сохранить изменение и вернуться в терминал, чтобы проверить результат;
Отправить AI агента сделать это самостоятельно;
Редактор перед сохранением сверяет версию файла с той, которую он открыл. Если файл изменился на сервере, TermForge сообщает о конфликте, а не перезаписывает изменения без предупреждения. При сохранении приложение создаёт резервную копию и использует временный файл с последующей заменой, когда это поддерживает сервер.
Что ещё хочется улучшить
Проект развивается, и интерфейс пока можно сделать удобнее. Сейчас мне особенно полезна обратная связь от людей, которые администрируют несколько VPS или домашний сервер.
Какие операции вы чаще всего выполняете подряд? Какие переключения между терминалом, файловым менеджером и Docker раздражают больше всего? И каких сценариев не хватает в таком общем рабочем пространстве?
Исходный код, инструкции по запуску и технические заметки доступны в репозитории: github.com/DanilChizhikov/termforge.
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.