Google Nexus 5: Nura (postmarketOS) без графики — домашний сервер с Docker и экранной оболочкой
Что получится
Nexus 5 2013 года превращается в маленький сервер: Linux без графического интерфейса, Docker, вход по SSH-ключу, Wi-Fi. Вместо пустой строки login: на экране — табло состояния, htop, консоль и меню, которыми можно управлять кнопками громкости и касаниями. Телефон можно отдать человеку без ПК: в меню есть подключение к новой сети Wi-Fi.
Nura — новое название postmarketOS. Команды и инструменты (pmbootstrap, pmaports) остались прежними.

| Параметр | Значение |
| Модель | LG Google Nexus 5 (D820/D821), кодовое имя hammerhead |
| SoC | Qualcomm Snapdragon 800 (msm8974), 4 ядра Krait, armv7 (32 бита) |
| Память | 2 ГБ (около 1,88 ГБ доступно системе) |
| Накопитель | eMMC 16/32 ГБ |
| Wi-Fi | Broadcom BCM4339 по SDIO (драйвер brcmfmac) |
| Порт Nura | lg-hammerhead, категория testing, ядро linux-postmarketos-qcom-msm8974 (общее с OnePlus One) |
Ядро на момент установки (ноябрь 2026): 6.16.12. Без графики система занимает около 300 МБ памяти, образ — 1,5 ГБ.
Похожая статья про OnePlus One (тот же процессор msm8974, первая версия экранной оболочки): OnePlus One: Ubuntu Touch → Nura.
Что нужно
- Nexus 5 с разблокированным загрузчиком (
fastboot oem unlock, стирает данные). Желательно TWRP в разделе recovery: он пригодится, если что-то пойдёт не так. - ПК с Linux, кабель micro-USB. У старых Nexus 5 часто разболтано гнездо: если телефон не определяется, переподключите кабель.
pmbootstrap3.11 или новее. В Debian пакет устарел (3.1.0), поэтому берём из git:
☯
Terminal:
⌕
≡
✕
git clone https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git ~/src/pmbootstrap alias pmbootstrap="python3 ~/src/pmbootstrap/pmbootstrap.py" pmbootstrap --version # 3.12.1 на момент написания pmbootstrap pull # обновить pmaports
Если на ПК уже есть настройки pmbootstrap для другого телефона, сохраните копию ~/.config/pmbootstrap_v3.cfg.
Если на телефоне уже стоял postmarketOS: частые проблемы
Мой Nexus 5 уже работал на postmarketOS, но не видел Wi-Fi. Причины пригодятся всем, кто обновляет старую установку.
Нет Wi-Fi после обновления. Интерфейса wlan0 нет, хотя чип виден в dmesg (mmc1: new ultra high speed SDR104 SDIO card). uname -r показывает одно ядро, а в /lib/modules лежат модули другого, поэтому modprobe brcmfmac не находит модуль. Причина: после apk upgrade новый /boot/boot.img не записался в раздел boot. В порте lg-hammerhead нет настройки flash_kernel_on_update, так что без lk2nd ядро само не обновляется. Исправление вручную (с резервной копией):
☯
Terminal:
⌕
≡
✕
sudo dd if=/dev/disk/by-partlabel/boot of=~/boot-backup.img bs=1M conv=fsync sudo dd if=/boot/boot.img of=/dev/disk/by-partlabel/boot bs=1M conv=fsync sudo reboot
Как сделать, чтобы это происходило автоматически, — в разделе «Ядро при обновлениях».
lk2nd на этом экземпляре не заработал. pmbootstrap предлагает поставить вторичный загрузчик lk2nd. У меня lk2nd 20.0 уходил в режим зарядки (загрузчик LG передаёт androidboot.mode=charger), а при следующей перезагрузке зависал на заставке. Откатился через TWRP: adb push резервной копии раздела boot и dd обратно. Поэтому дальше ядро пишется прямо в раздел boot, загрузкой управляет штатный загрузчик LG.
Сохранить файлы старой системы через TWRP. Если система не грузится, но TWRP работает, rootfs postmarketOS можно смонтировать прямо в TWRP: он лежит во втором разделе внутри userdata. Так я забрал профиль Wi-Fi, чтобы не вводить пароль заново:
☯
Terminal:
⌕
≡
✕
adb shell 'fdisk -l /dev/block/mmcblk0p28' # userdata: внутри p1 (boot) и p2 (rootfs), смотрим начальный сектор p2 adb shell 'mkdir -p /tmp/oldroot; L=$(losetup -f); losetup -o $((651264*512)) -r $L /dev/block/mmcblk0p28 && mount -t ext4 -o ro $L /tmp/oldroot' adb shell 'ls /tmp/oldroot/etc/NetworkManager/system-connections/' adb pull "/tmp/oldroot/etc/NetworkManager/system-connections/<сеть>.nmconnection" backup/ adb shell 'umount /tmp/oldroot; losetup -d /dev/block/loop0'
Число 651264 — начальный сектор p2 из вывода fdisk, у вас может отличаться. В файлах .nmconnection пароль Wi-Fi хранится открытым текстом: держите их с правами 600.
pmbootstrap init
☯
Terminal:
⌕
≡
✕
pmbootstrap init
Ответы:
- Vendor / device:
lg/hammerhead. - Username: ваш пользователь.
- UI: console («Console environment, with no graphical/touch UI»).
- Service manager: по умолчанию systemd.
- Extra packages:
docker,docker-cli-compose,nano,htop. - Locale
ru_RU, hostname, например,nexus5. - Copy SSH keys to device: да — тогда сразу будет вход по ключу.
Init может подставить часовой пояс ПК или виртуальной машины. Проверьте и при необходимости поправьте:
☯
Terminal:
⌕
≡
✕
pmbootstrap config timezone Europe/Moscow
Сборка образа
☯
Terminal:
⌕
≡
✕
pmbootstrap install --password <PIN>
Пароль должен быть цифровым: он же PIN. После первого входа его можно сменить командой passwd. Все пакеты для armv7 готовые, компиляции нет, сборка заняла около 11 минут.
Результат — ~/.local/var/pmbootstrap/chroot_native/home/pmos/rootfs/lg-hammerhead.img, 1,5 ГБ. С console UI образ почти вдвое меньше, чем с Phosh.
В конце pmbootstrap предложит flash_lk2nd. Его я пропустил (см. выше).
Прошивка
Переведите телефон в fastboot: с выключенного — кнопки VOL− и POWER, из TWRP — adb reboot bootloader. Проверка:
☯
Terminal:
⌕
≡
✕
fastboot getvar product # hammerhead fastboot oem device-info # Device unlocked: true
Сначала очистите userdata. Это главный совет статьи, ниже объясню почему:
☯
Terminal:
⌕
≡
✕
fastboot erase userdata
Затем rootfs и ядро:
☯
Terminal:
⌕
≡
✕
pmbootstrap flasher flash_rootfs --partition userdata pmbootstrap flasher flash_kernel fastboot reboot
Запись rootfs идёт около 4 минут. Предупреждение config-postmarketos-qcom-msm8974.armv7 isn't configured properly (category:hardening) при flash_kernel некритично.
Первая загрузка: «root partition not found»
Я сначала прошил без fastboot erase userdata и получил: USB-сеть есть (ping 172.16.42.1 отвечает), а SSH закрыт. Зато открыт telnet (порт 23) — это отладочная оболочка initramfs. На экране и в /pmOS_init.log:
☯
Terminal:
⌕
≡
✕
Mount subpartitions of /dev/mmcblk0p28 Primary GPT is invalid, using alternate GPT. ERROR: failed to mount subpartitions! / root partition not found!
Лог можно прочитать с ПК без интерактивного telnet:
☯
Terminal:
⌕
≡
✕
{ sleep 1; echo 'tail -30 /pmOS_init.log'; sleep 3; } | nc 172.16.42.1 23Причина. Старая система лежала в userdata с таблицей разделов GPT. Резервная копия GPT хранится в последних секторах раздела. Новый образ (1,5 ГБ, таблица msdos) намного короче раздела (12,8 ГБ), поэтому хвост с резервной GPT остался. Ядро видит «испорченный основной GPT», берёт резервную, старую таблицу, и разделы оказываются не там, где их записал pmbootstrap.
Проверка: в последнем секторе раздела сигнатура EFI PART:
☯
Terminal:
⌕
≡
✕
N=$(cat /sys/class/block/mmcblk0p28/size) dd if=/dev/mmcblk0p28 bs=512 skip=$((N-1)) count=1 | head -c 8
Исправление прямо в отладочной оболочке — затереть хвост раздела:
☯
Terminal:
⌕
≡
✕
N=$(cat /sys/class/block/mmcblk0p28/size)
dd if=/dev/zero of=/dev/mmcblk0p28 bs=512 seek=$((N-64)) count=64 conv=fsync
L=$(losetup --show -Pf /dev/mmcblk0p28); blkid ${L}p1 ${L}p2; losetup -d $L
# p1: LABEL="pmOS_boot" p2: LABEL="pmOS_root" — теперь правильно
reboot -fЧтобы не попасть в эту ловушку, перед flash_rootfs на устройство, где раньше был postmarketOS, Ubuntu Touch или любая система с GPT внутри userdata, выполняйте fastboot erase userdata.
Первая настройка
Через минуту после загрузки поднимается SSH по USB-сети:
☯
Terminal:
⌕
≡
✕
ssh <пользователь>@172.16.42.1
Если на этом же адресе раньше был другой телефон, ssh предупредит о смене ключа хоста. Чтобы не удалять старый ключ, дайте новому телефону отдельное имя: ssh -o HostKeyAlias=nexus5 <пользователь>@172.16.42.1. Если ssh-copy-id падает с Too many authentication failures, добавьте -o PubkeyAuthentication=no. Вход под root по SSH запрещён.
Корневой раздел. Initramfs растягивает раздел до конца userdata, но файловая система у меня осталась прежнего размера (957 МБ, занято 87%). Проверьте df -h / и при необходимости:
☯
Terminal:
⌕
≡
✕
sudo resize2fs /dev/loop0p2 df -h / # 11.9G, занято 7%
Wi-Fi. Либо сохранённый профиль:
☯
Terminal:
⌕
≡
✕
sudo install -m 600 -o root -g root <сеть>.nmconnection /etc/NetworkManager/system-connections/ sudo nmcli con reload && sudo nmcli -w 40 con up "<сеть>"
либо новая сеть: sudo nmcli device wifi connect "<сеть>" password "<пароль>". Работает только 2,4 ГГц: в прошивке нет файла brcmfmac4339-sdio.clm_blob, драйвер предупреждает об ограниченном наборе каналов.
Время. Часов реального времени у телефона нет, после загрузки дата может быть неверной:
☯
Terminal:
⌕
≡
✕
sudo timedatectl set-ntp true
Docker:
☯
Terminal:
⌕
≡
✕
sudo systemctl enable --now docker sudo addgroup <пользователь> docker docker run --rm hello-world
Docker 29, драйвер хранения overlayfs, cgroup v2 — всё работает из коробки.
Репозиторий пакетов. Если apk update пишет про репозиторий Nura 1 unavailable, провайдер обрывает загрузку с mirror.nura.eco. Пакеты Alpine при этом ставятся нормально. Обход — стороннее зеркало, как в статье про OnePlus One.
Ядро при обновлениях
Чтобы новое ядро после apk upgrade само попадало в раздел boot (без lk2nd), включите flash_kernel_on_update локально. boot-deploy читает /etc/deviceinfo после настроек пакета устройства, поэтому пакет трогать не нужно:
☯
Terminal:
⌕
≡
✕
sudo tee /etc/deviceinfo <<'X' # Локальные настройки поверх /usr/share/deviceinfo/deviceinfo deviceinfo_flash_kernel_on_update="true" X sudo mkinitfs # то же, что при обновлении ядра # ==> Flashing boot image # Flashing boot.img to 'boot'
Перед этим сохраните копию раздела boot (dd выше). Проверка, что записалось:
☯
Terminal:
⌕
≡
✕
S=$(stat -c %s /boot/boot.img); head -c $S /dev/disk/by-partlabel/boot | md5sum; md5sum /boot/boot.img
Перезагрузка по SSH: sudo systemd-run --on-active=3 systemctl reboot. Вариант (sleep 2; reboot) & не работает — фоновый процесс умирает вместе с сессией.
Экранная оболочка nura-server-shell
Без графики на экране висит только nexus5 login:. Я написал для таких телефонов небольшую оболочку и выложил её на GitHub: nura-server-shell, лицензия GPL-3.0-or-later. Она работает на Nexus 5 и OnePlus One.
Установка одной командой (ключ --headless дополнительно отключает графический вход, если он был):
☯
Terminal:
⌕
≡
✕
wget -qO- https://raw.githubusercontent.com/ramanzes/nura-server-shell/main/install.sh | sudo sh -s -- --headless
Повторный запуск той же команды — обновление. Удаление: sudo ./uninstall.sh из клона репозитория, --restore-gui вернёт графику.
Что появляется на экране:
- Табло на tty1: время, аптайм, Wi-Fi и уровень сигнала, IP, доступность шлюза и интернета, USB-сеть, контейнеры Docker, батарея, температура и загрузка CPU, память. Экран гаснет через минуту.
- Светодиод показывает состояние: зелёная вспышка раз в 5 секунд — всё в порядке.
- htop, консоль с экранной клавиатурой и меню.

| Действие | Что делает |
| VOL+ / VOL− | яркость (в htop — прокрутка, в меню — выбор пункта) |
| VOL+ и VOL− вместе | табло ⇄ htop |
| VOL− дважды в htop | показать / спрятать экранную клавиатуру |
| VOL− дважды | консоль ⇄ табло |
| VOL+ дважды | меню ⇄ табло (и отмена ввода пароля Wi-Fi) |
| касание пункта меню | выполнить |
| POWER коротко | включить погасший экран |
| POWER 5 секунд | перезагрузка |
В меню: подключить к Wi-Fi, перезапустить контейнеры, переподключить Wi-Fi, перезагрузить, выключить. Опасные действия — с подтверждением.
Подключение к новой сети Wi-Fi без ПК
- VOL+ дважды → «Подключить к Wi-Fi».
- Через 5–10 секунд — список до 6 сетей по силе сигнала:
#/##/###— сигнал,*— текущая,+— сохранённая,open— без пароля. - Касание сети. Сохранённая или открытая подключается сразу. Для новой защищённой сети открывается экран ввода пароля с экранной клавиатурой. Пароль виден при вводе, чтобы было проще не ошибиться. Пустой пароль или VOL+ дважды — отмена.
- В меню выводится результат: «Подключено» с IP и сигналом или текст ошибки. Профиль с неверным паролем удаляется.


htop с клавиатурой
В htop VOL− дважды показывает экранную клавиатуру, htop ужимается по высоте. Функциональных клавиш на экранной клавиатуре нет, поэтому строка F1Help … F10Quit внизу htop нажимается касанием. Работают k (завершить процесс), / (поиск), t (дерево), P/M/T (сортировка), F7/F8 (приоритет), q (выход на табло). В портрете htop использует шрифт 12×24 (90 колонок), чтобы строка F1…F10 помещалась целиком.


Поворот экрана на msm8974 недоступен. В меню есть пункт «Ориентация htop/консоли», но ядро msm8974 собрано без CONFIG_FRAMEBUFFER_CONSOLE_ROTATION: запись в /sys/class/graphics/fbcon/rotate проходит без ошибки и ничего не меняет. На Nexus 5 и OnePlus One оболочка честно пишет «Ядро не умеет поворачивать консоль». На устройствах с другим ядром (например, sdm660) поворот работает.
Итог
| Что | Результат |
| Загрузка до SSH | около 1 минуты |
| Память без нагрузки | ~300 МБ из 1,88 ГБ |
| Свободно на диске | ~11 ГБ (из 16) |
| Wi-Fi | 2,4 ГГц |
| Docker | работает |
| Обновление ядра | автоматически, через flash_kernel_on_update |
Для 32-битного телефона 2013 года это вполне рабочий маленький сервер: Docker-контейнеры, SSH, туннель наружу. При этом встроенный аккумулятор работает как ИБП, а экран показывает состояние без подключения к ПК.
Ссылки
- nura-server-shell — экранная оболочка
- postmarketOS wiki: Google Nexus 5 (lg-hammerhead)
- pmbootstrap
- OnePlus One: Ubuntu Touch → Nura
-
Создано 14.11.2026 18:15:00
-
Роман Александрович Сахно

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.