- BrainTools - https://www.braintools.ru -
После переезда я нашёл в коробке NVIDIA Jetson Nano, который несколько лет лежал без дела. Покупать готовый NAS не хотелось, поэтому решил собрать домашнее облако из того, что уже было: Jetson, старого SSD и VPS.
В результате на четырёх гигабайтах памяти [1] заработали Nextcloud, Immich, семейный чат, мониторинг и собственный REST API. Самой сложной частью оказались не Docker и не CGNAT, а USB‑хранилище: три разных сбоя заставили переделать подключение диска, загрузочные параметры и правила работы с репозиторием.
Задача была бытовой: перестать постоянно расширять облачное хранилище Google и перенести домой фотографии, файлы и контакты. Полностью отказаться от внешних сервисов я не планировал. Хотел сократить объём личных данных, которые хранятся вне моей инфраструктуры, и при этом не превратить домашний сервер в отдельную работу.
Доступ к дому осложнял CGNAT. Пробрасывать порты на роутере было невозможно, но у меня уже был VPS с публичным адресом. Поэтому архитектура сложилась вокруг исходящего SSH‑туннеля: Jetson сам подключается к VPS, а nginx на VPS принимает запросы клиентов.
|
Компонент |
Что использовал |
Откуда взялось |
|---|---|---|
|
NVIDIA Jetson Nano Dev Kit |
4 ГБ LPDDR4, ARM64, GPU Maxwell |
Остался после занятий сына робототехникой |
|
Системный диск |
microSD 64 ГБ |
Старая карта памяти от телефона |
|
Хранилище |
SSD 250 ГБ, доступно 229 ГБ, ext4 |
Остался после замены диска в ноутбуке |
|
VPS |
Ubuntu 24.04, 2 ГБ RAM |
Уже использовался для домашних сервисов |
|
Домашний роутер |
Статический адрес Jetson в LAN |
Обычный домашний роутер |
На старте в системе не был настроен swap. Позже я включил четыре zram‑устройства общим объёмом около 2 ГБ, но это не превратило Jetson в машину с полноценными шестью гигабайтами памяти. Приходилось считать память и не держать сервисы «на всякий случай».
Второе ограничение — JetPack и старый Docker 20.10.7. Обновлять Docker отдельно от системного стека рискованно: от JetPack зависят компоненты платформы. Для ARM64 также есть не все контейнерные образы. Поэтому я отказался от тяжёлого универсального NAS‑дистрибутива и собрал систему из отдельных сервисов.
Машинное обучение [2] в Immich отключено:
IMMICH_DISABLE_MACHINE_LEARNING=true
На этом этапе важнее было обеспечить устойчивый автобэкап фотографий, чем распознавание лиц и объектов.
[Смартфон / браузер / приложение]
|
| HTTPS / HTTP
v
[VPS]
nginx
:8080 / :8443 -> Nextcloud
:2283 / :2443 -> Immich
:8090 / :9443 -> LLM Gateway
:8099 -> NAS API
|
| reverse SSH tunnel (autossh)
v
[Jetson Nano, домашняя сеть]
Nextcloud + PostgreSQL + Redis
Immich + PostgreSQL + Redis
Samba, Netdata, Uptime Kuma, Portainer
NAS API, LLM Gateway
|
| USB 3.0
v
[JMS583 SSD, ext4, /mnt/storage]
Jetson не принимает входящие подключения из интернета. Сервис autossh поднимает обратный туннель до VPS и восстанавливает его после разрыва. На VPS работает nginx, который проксирует трафик к локальным портам туннеля.
В моей конфигурации WireGuard упирался в особенности ядра Tegra 4.9, а Tailscale конфликтовал с уже используемым VPN на Android. Поэтому я оставил более простой для этого стенда вариант — autossh с автоматическим перезапуском.
Домена пока нет. Для Android‑клиентов сделал самоподписанный сертификат с IP‑адресами в SAN и отдельные HTTPS‑порты. Это рабочее, но временное решение: при появлении домена планирую перейти на обычный сертификат Let’s Encrypt.
|
Контейнер |
Назначение |
Порт |
Лимит памяти |
|---|---|---|---|
|
|
Файлы, контакты, календарь, Talk |
8080 |
512 МБ |
|
|
PostgreSQL 16 |
— |
512 МБ |
|
|
Redis |
— |
64 МБ |
|
|
Фотоархив |
2283 |
1024 МБ |
|
|
PostgreSQL для Immich |
— |
384 МБ |
|
|
Redis |
— |
64 МБ |
|
|
Фоновые задачи Immich |
— |
512 МБ |
|
|
Шлюз AI‑сервисов |
8090 |
256 МБ |
|
|
Собственный FastAPI |
8099 |
128 МБ |
|
|
Файловый доступ только из LAN |
445 |
— |
|
|
Текущие метрики |
19 999 |
256 МБ |
|
|
Проверка доступности |
3001 |
128 МБ |
|
|
Ручное управление Docker |
9000 |
128 МБ |
Для контейнеров заданы mem_limit, healthcheck и политика перезапуска. На четырёх гигабайтах это не оптимизация «на будущее», а защита: один неограниченный процесс способен вытеснить остальные сервисы.
До этого момента проект был обычной сборкой сервисов. Инженерная работа началась, когда несколько дней подряд отваливался SSD.
Первый USB‑энклоужер несколько дней работал нормально, а затем в dmesg появились отключения и ошибки [3] ввода‑вывода:
usb 2-1.3: USB disconnect, device number X
sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR...
Проблема проявлялась после простоя. Отключение autosuspend помогло частично, но при записи через UAS скорость постепенно падала примерно до 40 МБ/с, затем появлялись stream errors. В итоге я заменил энклоужер на JMS583.
После замены энклоужера симптомы повторились. Причина оказалась проще: четвёртый USB‑порт на конкретной плате был нестабилен. После переноса SSD во второй порт ошибки исчезли. Номер рабочего порта я зафиксировал в конфигурации watchdog и в документации проекта.
Часть systemd‑юнитов и скриптов я готовил на Windows. После переноса на Jetson они не запускались:
Failed to execute /usr/bin/env bash
: No such file or directory
Причина — окончания строк CRLF. Для репозитория добавил правило:
* text=auto eol=lf
После этого Git приводит скрипты к LF при checkout в Linux.
# /boot/extlinux/extlinux.conf, параметр APPEND
usb-storage.quirks=152d:a583:u usbcore.autosuspend=-1
Флаг u переключает JMS583 из UAS в BOT. На этом стенде после настройки получились 250 МБ/с на запись и 172 МБ/с на чтение без новых USB‑ошибок в dmesg. Дополнительно настроены увеличенный SCSI timeout, автоматическое монтирование и восстановление контейнеров после переподключения диска.
Мне было важно понимать не только текущее состояние, но и что происходило ночью или перед сбоем. Для этого использовал три уровня контроля:
ежедневный отчёт в Telegram;
исторические графики Beszel Hub;
инфраструктурные тесты goss после изменений.
В отчёте видны uptime, использование памяти и диска, температуры, перезапуски контейнеров, локальные HTTP‑проверки и доступность через VPS.
После существенных изменений запускаю goss:
goss validate --gossfile tests/goss/goss.yaml
Count: 40, Failed: 0, Skipped: 0
Тесты проверяют порты, systemd‑сервисы, файлы и HTTP‑эндпоинты. Это не заменяет ручную проверку, но быстро показывает, что именно сломалось после очередной правки.
Большинство семейных телефонов — Xiaomi с MIUI или HyperOS. Без настройки автозапуска и исключения приложений из энергосбережения Immich переставал загружать фотографии в фоне. Поэтому для каждого пользователя сделал короткую инструкцию без серверных терминов.
На историческом снимке было загружено 6697 из 6719 объектов. При отдельной проверке 16 июля 2026 года в базе находились 6622 изображения и 357 видео — 6979 активных объектов. Контакты синхронизировались через DAVx⁵; в адресной книге было 2151 запись.
Для семейного чата использовал Nextcloud Talk. Группа состоит из пяти человек, история хранится на домашнем SSD.
Portainer удобен, когда я сам открываю браузер и вручную проверяю контейнеры. Для автоматизации этого оказалось недостаточно. Нужна была одна точка, через которую скрипт или бот может получить состояние системы, статистику Immich и выполнить только заранее разрешённое действие.
Так появился FastAPI‑сервис с 20 HTTP‑операциями. Основные группы:
|
Группа |
Что возвращает или выполняет |
|---|---|
|
System |
Память, процессор, температура, uptime, состояние диска |
|
Containers |
Список контейнеров и число перезапусков |
|
Talk |
Комнаты, участники, отправка уведомлений |
|
Photos |
Статистика изображений и видео в Immich |
|
Actions |
Перезапуск контейнера из whitelist и запуск резервного копирования |
Ответы описаны Pydantic‑моделями, поэтому формат не меняется от запроса к запросу. Опасные операции ограничены списком разрешённых действий.
Swagger UI собственного NAS API
AI‑агент был инструментом разработки, а не источником технических решений. Я задавал цель, показывал текущее состояние системы, проверял команды и принимал итоговое решение.
Лучше всего агент помогал в трёх типах задач:
создание однотипных Docker Compose, nginx и systemd‑файлов;
подготовка тестов, документации и rollback‑инструкций;
сравнение вариантов, когда ограничения уже были известны.
Ключевым файлом стал AGENTS.md. В нём записаны ограничения конкретного стенда: не трогать работающие VPN‑контейнеры на VPS, не использовать нестабильный USB‑порт, сохранять bash‑скрипты только с LF, проверять монтирование SSD перед резервным копированием.
Без человека агент не определил бы физически неисправный порт и не знал бы, какие сервисы на VPS нельзя останавливать. Конфигурации firewall, fstab, секреты и команды с риском потери данных я проверял сам.
Один из рабочих запросов выглядел так:
Подними Nextcloud и Immich на Jetson Nano.
PostgreSQL для обоих. Данные храни в /mnt/storage.
Учти ограничения: 4 ГБ RAM, старый Docker, ARM64.
Перед изменениями покажи команды проверки и способ отката.
Внешние сервисы доступны только через VPS и обратный туннель. На самом Jetson входящие порты из интернета не открыты. Samba разрешена только в домашней сети. NAS API требует авторизацию, а команды управления контейнерами проходят через whitelist.
При этом проект нельзя считать законченным с точки зрения [4] отказоустойчивости:
Docker 20.10.7 устарел, а его обновление ограничено зависимостями JetPack;
самоподписанный TLS усложняет подключение новых устройств;
off‑site‑копия пока не настроена, поэтому один SSD остаётся единой точкой отказа;
машинное обучение Immich отключено из‑за ограничений памяти.
|
Показатель |
Зафиксированный результат |
|---|---|
|
Docker |
13 контейнеров запущены; для 12 настроен healthcheck |
|
Фотоархив |
6622 изображения и 357 видео по проверке от 16.07.2026 |
|
Контакты |
2151 запись через CardDAV/DAVx⁵ |
|
Семейный чат |
5 участников |
|
Инфраструктурные тесты |
40 из 40 в историческом прогоне |
|
SSD |
250 МБ/с запись, 172 МБ/с чтение после настройки JMS583 |
Сразу выбрал бы проверенный USB‑энклоужер. Два аппаратных инцидента заняли больше времени, чем развёртывание основных сервисов.
Добавил бы .gitattributes в первый коммит. Тогда CRLF не попал бы на Jetson.
Создал бы AGENTS.md до первой сессии. Контекст оборудования и запреты пришлось несколько раз объяснять заново.
Сразу завёл бы домен. Самоподписанный сертификат работает, но усложняет подключение родственников.
Раньше занялся бы второй копией данных. Домашнее облако без независимого бэкапа остаётся экспериментом, даже если работает стабильно.
Старый Jetson Nano оказался достаточен для домашнего облака, которым семья действительно пользуется. Ограничения четырёх гигабайт памяти заставили аккуратно выбирать сервисы, но не помешали запустить Nextcloud, Immich, мониторинг и собственный API.
Главный вывод для меня — надёжность такого проекта определяется не количеством контейнеров. Гораздо важнее питание, USB‑мост, файловая система, автоматическое восстановление и резервная копия. Именно эти вещи заняли больше всего времени.
Исходный код, Docker Compose, systemd‑юниты, тесты и журнал решений опубликованы в репозитории на Гитхабе [5].
Автор: Alexey_git
Источник [6]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/33530
URLs in this post:
[1] памяти: http://www.braintools.ru/article/4140
[2] обучение: http://www.braintools.ru/article/5125
[3] ошибки: http://www.braintools.ru/article/4192
[4] зрения: http://www.braintools.ru/article/6238
[5] опубликованы в репозитории на Гитхабе: https://github.com/AlexeyBorovskoy/NAS_Jetson_Nano
[6] Источник: https://habr.com/ru/articles/1062914/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1062914
Нажмите здесь для печати.