Домашнее облако на старом Jetson Nano: Nextcloud, Immich, CGNAT и три сбоя USB
После переезда мне на глаза попалась пылившаяся в коробке плата NVIDIA Jetson Nano. Покупать готовый сетевой накопитель не хотелось, поэтому я решил развернуть персональное облако из подручных средств: самого Jetson, подержанного твердотельного накопителя и арендованного VPS.
В итоге на скромных четырех гигабайтах оперативной памяти успешно запедали Nextcloud, Immich, семейный мессенджер, система мониторинга и кастомный REST API. Самым капризным компонентом оказались вовсе не Docker или ограничения CGNAT, а USB-накопитель: три последовательных сбоя заставили перетряхнуть схему подключения, конфигурацию загрузки и правила обработки репозитория.

Чего хотелось добиться
Цель носила сугубо практический характер: перестать бесконечно докупать гигабайты в Google Диске и перевезти под крышу личные фото, документы и адресные книги. Полностью рвать связи с коммерческими облаками я не собирался, но стремился минимизировать объем персональной информации, утекающей на чужие сервера, при этом не превращая администрирование домашней фермы в рутинную вторую работу.
Серьезным препятствием стал CGNAT провайдера, из-за которого прямой проброс портов на роутере оказался невозможен. У меня уже имелся VPS с белым IP-адресом, поэтому архитектура построена вокруг исходящего SSH-туннеля: мини-компьютер самостоятельно устанавливает соединение с облачным сервером, а nginx на стороне VPS принимает входящий пользовательский трафик.
Использованное «железо»
|
Компонент |
Что использовалось |
Происхождение |
|---|---|---|
|
NVIDIA Jetson Nano Dev Kit |
4 ГБ LPDDR4, архитектура ARM64, графический чип Maxwell |
Остался после увлечения робототехникой |
|
Системный накопитель |
microSD на 64 ГБ |
Извлечен из старого смартфона |
|
Основное хранилище |
SSD на 250 ГБ (доступно 229 ГБ), файловая система ext4 |
Демонтирован при апгрейде ноутбука |
|
VPS (удаленный сервер) |
Ubuntu 24.04, 2 ГБ RAM |
Арендован ранее для сопутствующих задач |
|
Домашний маршрутизатор |
Выделение статичного IP для Jetson в локальной сети |
Обычный бытовой роутер |
Архитектурные ограничения
На старте в системе отсутствовал файл подкачки (swap). Позже я активировал четыре zram-устройства суммарным объемом около 2 ГБ, однако это не превратило Jetson в условный сервер с шестью гигабайтами на борту. Приходилось жестко контролировать потребление ресурсов и избегать запуска фоновых служб «на всякий случай».
Вторым сдерживающим фактором стали особенности JetPack и устаревшая версия Docker 20.10.7. Обновлять Docker отдельно от базового системного ПО чревато сбоями, поскольку к JetPack привязаны драйверы платформы, а экосистема ARM64 располагает далеко не всеми готовыми образами. В результате я осознанно отказался от громоздких универсальных NAS-дистрибутивов в пользу модульной сборки из отдельных контейнеров.
Функции машинного обучения в Immich были отключены:
IMMICH_DISABLE_MACHINE_LEARNING=true
На начальном этапе стабильный фоновый бэкап медиаархива был куда важнее автоматического распознавания лиц и классификации объектов.
Сетевая архитектура и обход CGNAT
[Смартфон / браузер / приложение]
|
| 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]
Плата не принимает входящие соединения напрямую из глобальной сети. Демон autossh держит открытым обратный туннель до VPS, автоматически поднимая его в случае обрыва. На самом VPS настроен nginx, перенаправляющий входящий трафик на соответствующие локальные порты туннеля.
Использовать WireGuard в моем случае мешали нюансы ядра Tegra 4.9, а Tailscale конфликтовал с уже развернутым VPN-клиентом на смартфонах. Поэтому я остановился на проверенном и неприхотливом решении — autossh с принудительным перезапуском.
Полноценный домен пока не приобретен. Для мобильных клиентов под Android я сгенерировал самоподписанный сертификат с прописанными в SAN IP-адресами и выделил индивидуальные HTTPS-порты. Это временная мера: как только появится доменное имя, я перейду на стандартные сертификаты Let’s Encrypt.
Перечень запущенных Docker-контейнеров
|
Контейнер |
Назначение |
Порт |
Лимит RAM |
|---|---|---|---|
|
|
Облачное хранилище, контакты, календарь, Talk |
8080 |
512 МБ |
|
|
СУБД PostgreSQL 16 |
— |
512 МБ |
|
|
Кэширование Redis |
— |
64 МБ |
|
|
Сервер фотогалереи |
2283 |
1024 МБ |
|
|
PostgreSQL для Immich |
— |
384 МБ |
|
|
Кэш Immich |
— |
64 МБ |
|
|
Фоновые процессы фотохостинга |
— |
512 МБ |
|
|
Шлюз для нейросетевых API |
8090 |
256 МБ |
|
|
Кастомный FastAPI-сервис управления |
8099 |
128 МБ |
|
|
Файловый доступ строго из LAN |
445 |
— |
|
|
Мониторинг производительности в реальном времени |
19999 |
256 МБ |
|
|
Контроль доступности эндпоинтов |
3001 |
128 МБ |
|
|
Веб-интерфейс Docker |
9000 |
128 МБ |
Для каждого контейнера явно заданы директивы mem_limit, healthcheck и правила перезапуска. В условиях четырех гигабайт памяти это не избыточная предосторожность, а жизненная необходимость: один бесконтрольный процесс способен мгновенно положить всю систему.
Хронические проблемы с USB
До определенного момента проект выглядел как заурядный конструктор из готовых образов. Настоящий хардкор начался, когда внешний SSD стал регулярно отваливаться.
1. RTL9210B-CG, функция autosuspend и ошибка -71
Первый бокс для диска вел себя прилично пару дней, после чего в системном логе dmesg посыпались фатальные сбои ввода-вывода:
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 МБ/с, после чего интерфейс зависал. Контейнер пришлось сменить, купив бокс на чипсете JMS583.
2. Физический износ USB-порта
После установки нового корпуса проблема возобновилась. Источник оказался до смешного банальным: четвертый порт USB на самой плате Jetson имел плохой контакт. Стоило переставить SSD во второй порт, как ошибки исчезли. Номер исправного разъема я задокументировал и прописал в параметрах сторожевого таймера.
Часть служебных сценариев и юнитов systemd я правил в Windows. При попытке запуска на Jetson они выдавали ошибку:
Failed to execute /usr/bin/env bash
: No such file or directory
Виной всему оказались невидимые символы перевода строки в стиле Windows (CRLF). Проблема решилась добавлением в репозиторий правила:
* text=auto eol=lf
Теперь Git принудительно приводит все скрипты к стандарту Linux (LF) при клонировании.
Финальная конфигурация диска
# /boot/extlinux/extlinux.conf, параметр APPEND
usb-storage.quirks=152d:a583:u usbcore.autosuspend=-1
Флаг u принудительно переключает контроллер JMS583 с быстрого, но капризного UAS на надежный протокол BOT. В результате удалось выжать 250 МБ/с на запись и 172 МБ/с на чтение без единой ошибки в логах ядра. Дополнительно были увеличены тайм-ауты SCSI-подсистемы и настроено автоматическое восстановление контейнеров при переподключении накопителя.
Многоуровневый мониторинг
Мне было принципиально важно не просто фиксировать текущий статус сервисов, но и понимать, что происходило накануне в случае сбоя. Для этого я внедрил тришешелонную систему контроля:
-
Ежедневные сводки в Telegram;
-
Графики долговременной статистики в Beszel Hub;
-
Автоматические интеграционные тесты с помощью утилиты goss.
Ежедневный Telegram‑отчёт: система, температуры, контейнеры и доступность сервисов

Отчет содержит данные об аптайме, степени заполнения дисков, температурах чипов, рестартах контейнеров и результатах пинга локальных и внешних эндпоинтов.


После любых серьезных правок я запускаю проверку:
goss validate --gossfile tests/goss/goss.yaml
Count: 40, Failed: 0, Skipped: 0
Тесты опрашивают сетевые порты, проверяют состояние служб systemd, наличие файлов и доступность HTTP-адресов. Это не заменяет полноценного тестирования, но мгновенно подсвечивает, какой именно узел отвалился после очередного вмешательства.
Клиентский опыт: Immich, DAVx⁵ и Nextcloud Talk
Большинство домашних телефонов — это аппараты от Xiaomi под управлением MIUI или HyperOS. Без предварительного отключения агрессивного энергосбережения и фиксации приложений в памяти фоновая выгрузка фото в Immich постоянно засыпала. Поэтому для домочадцев я составил простые пошаговые инструкции без избыточной технической терминологии.

На архивном скриншоте зафиксирована успешная заливка 6697 объектов из 6719. При контрольной проверке 16 июля 2026 года в базе числилось 6622 изображения и 357 видеороликов — суммарно 6979 медиафайлов. Синхронизация контактов организована через DAVx⁵, адресная книга насчитывает 2151 запись.
Для обмена сообщениями используется Nextcloud Talk. В семейном чате состоят пять человек, вся переписка и вложения хранятся локально на SSD.


Собственный REST API поверх инфраструктуры
Portainer прекрасен, когда нужно зайти глазами в консоль и вручную проверить состояние контейнеров. Однако для автоматизации этого мало. Требовалась единая точка входа, через которую внешний скрипт или бот мог бы запрашивать телеметрию, статистику фотохостинга и выполнять строго регламентированные команды.
Так родился сервис на FastAPI, реализующий два десятка эндпоинтов. Основные категории запросов:
|
Категория |
Возвращаемые данные или выполняемое действие |
|---|---|
|
System |
Нагрузка на CPU/RAM, температура кристаллов, аптайм, статус дисков |
|
Containers |
Состояние контейнеров и счетчик перезапусков |
|
Talk |
Активные чаты, список участников, отправка пушей |
|
Photos |
Счетчики фото и видеоматериалов в Immich |
|
Actions |
Перезапуск контейнеров из белого списка и запуск бэкапов |
Все ответы строго типизированы с помощью Pydantic-моделей, поэтому формат выдачи неизменен. Потенциально деструктивные операции защищены списками разрешенных команд.
Интерфейс Swagger UI для кастомного NAS API

Роль ИИ-ассистента в разработке
Нейросетевой помощник выступал инструментом реализации, но не автором архитектурных концепций. Я ставил задачу, описывал текущее положение дел, валидировал предложенный код и утверждал итоговые изменения.
Максимальную пользу ассистент принес в трех сценариях:
-
Генерация однотипных конфигураций Docker Compose, nginx и служебных файлов systemd;
-
Написание тестовых сценариев, сопутствующей документации и инструкций на случай отката изменений;
-
Анализ альтернативных решений при уже известных аппаратных ограничениях.
Ключевым файлом проекта стал AGENTS.md. В нем зафиксированы жесткие лимиты стенда: не трогать рабочие VPN-туннели на VPS, обходить стороной неисправный порт USB, сохранять скрипты исключительно в формате LF и проверять примонтированность SSD перед стартом резервного копирования.
Без участия человека ИИ не смог бы диагностировать физический дефект разъема или узнать, какие критические службы на VPS нельзя перезагружать. Манипуляции с файрволом, таблицей разделов fstab, секретными ключами и потенциально опасные команды я всегда выполнял самостоятельно.
Типичный запрос к ассистенту выглядел следующим образом:
Разверни Nextcloud и Immich на плате Jetson Nano.
СУБД для обоих — общая PostgreSQL. Файлы хранить в каталоге /mnt/storage.
Учитывай ограничения: 4 ГБ RAM, старый Docker, архитектура ARM64.
Перед выдачей команд покажи алгоритм проверки работоспособности и способ отката.
Безопасность и слабые места
Все внешние службы доступны исключительно через VPS и защищенный обратный туннель. Прямые входящие соединения на сам Jetson из интернета заблокированы. Доступ по протоколу Samba разрешен только внутри домашней сети. NAS API защищен авторизацией, а управляющие команды фильтруются по белому списку.
Тем не менее, проект пока нельзя назвать эталоном отказоустойчивости:
-
Версия Docker 20.10.7 безнадежно устарела, а ее апдейт завязан на зависимости JetPack;
-
Самоподписанные TLS-сертификаты создают лишнюю головную боль при подключении новых гаджетов;
-
Внеплощадочное резервное копирование отсутствует, поэтому единственный SSD остается единой точкой отказа;
-
Модули машинного обучения Immich отключены из-за дефицита памяти.
Итоговые показатели
|
Метрика |
Фактический результат |
|---|---|
|
Docker-окружение |
Запущено 13 контейнеров, для 12 из них настроены healthcheck-проверки |
|
Медиатека |
6622 фотографии и 357 видео по состоянию на 16.07.2026 |
|
Контакты |
2151 запись, синхронизируемая через CardDAV/DAVx⁵ |
|
Семейный чат |
Активны 5 пользователей |
|
Тестирование |
40 из 40 интеграционных тестов проходят успешно |
|
Дисковая подсистема |
250 МБ/с на запись и 172 МБ/с на чтение после настройки чипа JMS583 |

Работа над ошибками: как я поступил бы сейчас
-
Сразу купил проверенный USB-бокс. Борьба с аппаратными сбоями диска отняла больше времени, чем вся остальная конфигурация софта.
-
Добавил бы файл
.gitattributesв самый первый коммит. Это уберегло бы меня от проблем с символами CRLF на плате Jetson. -
Оформил бы файл
AGENTS.mdдо начала работ. Контекст железа и ограничения пришлось растолковывать нейросети заново несколько раз. -
Обзавелся бы доменом на старте. Самоподписанные сертификаты работают, но излишне усложняют жизнь при подключении устройств родственников.
-
Раньше озаботился резервной копией. Домашнее облако без независимого бэкапа — это всего лишь занимательная игрушка, какой бы стабильной ни казалась система.
Заключение
Устаревший Jetson Nano отлично справился с ролью персонального облачного сервера, которым действительно пользуется вся семья. Жесткие рамки в четыре гигабайта оперативки заставили подойти к выбору софта с хирургической точностью, но не помешали поднять Nextcloud, Immich, систему мониторинга и кастомный API.
Главный урок, который я вынес: надежность подобных самодельных систем определяется вовсе не количеством запущенных контейнеров. Куда критичнее стабильное питание, качественный USB-мост, здоровье файловой системы, механизмы самовосстановления и актуальные бэкапы. Именно на борьбу с этими нюансами ушла львиная доля времени.
Исходные конфигурации Docker Compose, юниты systemd, тесты и журнал принятых решений опубликованы в профильном репозитории на GitHub.
Meta* выходит из RE100 спустя 10 лет: газовая энергетика для ИИ победила возобновляемую
Китай заявил о прорыве в нейроинтерфейсах: ученые впервые синхронно собрали ЭЭГ у тысяч людей
Мощный мини-ПК Acemagic F9A: 16-ядерный Ryzen AI Max+ 395, до 128 ГБ ОЗУ, RGB и кнопка Copilot
Илон Маск готовится поймать огромный корабль Starship прямо в воздухе уже в августе
Samsung ужесточила защиту One UI 9.0: экран блокировки сотрется после 13 неудачных попыток ввода
Представлена мощная 100-ваттная зарядка Ugreen X876 на нитриде галлия всего за 28 долларов
В Китае разработали флеш-память, работающую всего на одном электроне
Стоит ли покупать Nintendo Switch 2 год спустя: обзор самой доступной консоли поколения