126 lines
5.4 KiB
Markdown
126 lines
5.4 KiB
Markdown
# xboctploy
|
||
|
||
Легковесная CLI-утилита на Rust для централизованного деплоя хобби-проектов
|
||
(Node.js, Rust) с локального ПК на слабую VPS по SSH.
|
||
|
||
- сборка, тесты и линтеры выполняются **локально** — CPU VPS не тратится
|
||
- артефакты передаются по **SFTP** (без rsync, работает на Windows/Linux/macOS)
|
||
- сервисные команды (`pm2 restart`, `systemctl restart`) запускаются **по SSH**
|
||
- fail-fast: упавший шаг немедленно останавливает деплой (ADR-005)
|
||
|
||
## Установка
|
||
|
||
```sh
|
||
cargo install --path .
|
||
```
|
||
|
||
Требуется Rust 1.88+. Кроссплатформенно: Windows (MSVC), Linux, macOS.
|
||
|
||
## Быстрый старт
|
||
|
||
```sh
|
||
xboctploy --list # показать проекты из конфига
|
||
xboctploy --list-servers # показать серверы из конфига
|
||
xboctploy --pick # интерактивно выбрать проект (нечёткий поиск)
|
||
xboctploy --dry-run demo # напечатать план деплоя без выполнения
|
||
xboctploy demo # задеплоить проект demo
|
||
```
|
||
|
||
Вывод:
|
||
|
||
```txt
|
||
deploying 'demo'
|
||
[Local] running: npm run build... Success! (1.2s)
|
||
[SFTP] transferring dist to /var/www/pages... Done! (14 file(s), 231.5 KiB) (829ms)
|
||
[Remote] running: pm2 restart pages... Success! (102ms)
|
||
Deploy successful! (total 2.3s)
|
||
```
|
||
|
||
## Конфигурация
|
||
|
||
Файл ищется по цепочке:
|
||
|
||
1. `--config PATH`, если указан явно;
|
||
2. `./deploy.toml` в текущей папке — удобно держать рядом с проектом и в тестах;
|
||
3. глобальный `~/.config/xboctploy/deploy.toml` — запуск «из любой папки».
|
||
|
||
Схема:
|
||
|
||
```toml
|
||
[servers.my-vps] # профиль сервера: описывается один раз
|
||
host = "195.0.2.10" # алиас из ~/.ssh/config или IP
|
||
port = 2222
|
||
user = "deploy"
|
||
key_path = "~/.ssh/id_ed25519"
|
||
base_dir = "/var/www/pages" # корень для относительных sync target
|
||
|
||
[projects.my-node-app]
|
||
server = "my-vps" # ссылка на профиль
|
||
workdir = "~/code/my-node-app" # где выполнять локальные команды (~ разворачивается)
|
||
|
||
[projects.my-node-app.env] # переменные для локальных команд сборки
|
||
PUBLIC_BASE_PATH = "/my-node-app"
|
||
|
||
[projects.my-node-app.local] # шаги сборки на вашей машине
|
||
commands = ["npm ci", "npm run build"]
|
||
|
||
[[projects.my-node-app.sync]] # что заливать на сервер
|
||
source = "dist" # файл или папка (относительно workdir)
|
||
target = "my-node-app" # относительный -> base_dir сервера;
|
||
# абсолютный "/path" используется как есть
|
||
|
||
[projects.my-node-app.remote] # команды управления на сервере
|
||
commands = ["pm2 restart pages"]
|
||
```
|
||
|
||
Проект может задать параметры подключения и напрямую (`host`, `user`, `port`,
|
||
`key_path` вместо `server`) — тогда они имеют приоритет над профилем.
|
||
|
||
Приоритет параметров SSH: проект → `[servers.<name>]` → `~/.ssh/config` → дефолт.
|
||
|
||
### Windows-нюанс TOML
|
||
|
||
В basic-строках `"..."` бэкслеши — escape-символы, путь `C:\Users` сломает парсинг.
|
||
Для путей Windows используйте литеральные строки `'...'`:
|
||
|
||
```toml
|
||
workdir = 'C:\code\my-node-app'
|
||
```
|
||
|
||
или прямые слэши `C:/code/my-node-app`.
|
||
|
||
## Аутентификация
|
||
|
||
Цепочка (первый успешный способ используется):
|
||
|
||
1. **ssh-agent**: OpenSSH-агент (named pipe на Windows / `SSH_AUTH_SOCK` на Unix),
|
||
затем Pageant; перебираются все ключи агента;
|
||
2. **файловый ключ** `key_path` → `identity_file` → `~/.ssh/id_rsa`
|
||
(ключи с passphrase пока не поддерживаются);
|
||
3. иначе — понятная ошибка.
|
||
|
||
Проверка host key — TOFU поверх вашего `~/.ssh/known_hosts`: неизвестный хост
|
||
доверяется и запоминается, смена ключа сервера — громкая ошибка (MITM-защита).
|
||
|
||
## Переменные окружения (.env)
|
||
|
||
Если рядом с workdir проекта есть `.env`, его переменные (KEY=VALUE, `#`
|
||
комментарии, кавычки, префикс `export`) доступны всем локальным командам.
|
||
`.env` не копируется на сервер, если не указан явно в `sync`.
|
||
|
||
Приоритет источников: `[env]` из deploy.toml → `.env` → окружение ОС.
|
||
|
||
```env
|
||
# .env
|
||
NODE_ENV=production
|
||
API_TOKEN="secret"
|
||
export DB_URL=postgres://localhost/app
|
||
```
|
||
|
||
## Разработка
|
||
|
||
```sh
|
||
just test # fmt + clippy -D warnings + cargo test
|
||
just run # деплой из test/deploy.toml (в git не входит)
|
||
```
|