Установка FreeBSD на флешку для seedbox машины

Попалась на харабре интересная статья про установку FreeBSD на флешку.


На многие домашние seedbox'ы (имеется в виду маленький пограничный роутер для Интернета) довольно часто ставятся старые жесткие диски, из принципа «не жалко». Важных данных туда все равно не пишется, и когда они помирают, ничего страшного не происходит, за исключением проблем с перестановкой ОС.

Для минимизирования риска смерти ОС, можно вынести ее на отдельный физический носитель. Один из вариантов — на маленькую флешку. Речь дальше пойдет об установке и настройке FreeBSD (7.0-8.0) на флешке.

[Размер флешки]

Исходя из моих экспериментов, в 200 мегабайт (на 256 меговую флешку) легко влезает вполне рабочий роутер с dhcp/dns/vpn сервером. При этом из ядра выкидываются все ненужные драйвера, а также опции отладки и профилирования, а из мира убираются manы. Конечно, исходники (/usr/src) и порты (/usr/ports) туда не поместятся, но их можно без особых проблем монтировать и с другого носителя.

Под роутер с функциями seedbox лучше иметь флешку побольше, поскольку там потребуется и apache, и perl, и php. Для данного примера возьмем глючную флешку на 4 гигабайта :).

[Проблемы с надежностью]

Поскольку флешки очень не любят перезапись секторов, гайдбук рекомендует монтировать корень только на чтение, а все разделы, требующие доступа на запись, выносить в память. Таким образом, /var будет смонтирован как диск в оперативной памяти и каждая перезагрузка будет удалять все его содержимое.

[Подготовка разделов]

Установку удобнее всего делать из под FreeBSD (я делал с виртуалки), в которой уже собрано нужное вам ядро и мир.

Итак, вставляем флешку, смотрим как она определилась в dmesg (далее da0). Для начала флешку надо отформатировать. Создаем flash_disk.proto:
# slice type start length
# создаем два слайса
p 1 0xa5 63 1429722
p 3 0xa5 2040255 6072570
# делаем первый активным
a 1
Поскольку флешка у меня глючная (попытка чтения данных из участка между 700 и 1000 мегабайтами вызывает отваливание контроллера), то пространство у меня дробится на два слайса. С нормальной флешкой можно создавать один кусок на всю флешку.

Форматируем:
fdisk -f flash_disk.proto -i da0
Создаем загрузчик:
# создаем MBR
boot0cfg -B da0
# по-умолчанию грузимся с первого slice
boot0cfg -s 1 da0
# запрещаем загрузчику перезаписывать себя
boot0cfg -o noupdate da0
Теперь разметим наш слайс. Создаем flash_labels.proto:
# size offset fstype [fsize bsize bps/cpg]
a: 1429722 0 4.2BSD 0 0 0
c: * 0 unused 0 0 # "raw" part, don't edit
Размечаем диск и создаем файловую систему:
# Размечаем в соответствии с созданным файлом
bsdlabel -R da0s1 flash_labels.proto
# Создаем файловую систему
newfs -U da0s1a
Монтируем наш слайс
mount /dev/da0s1 /mnt/flash
[Установка системы и портов]

Чтобы каждый раз при make install не указывать путь, временно выставим DESTDIR флаг в make.conf на рабочей системе:
DESTDIR=/mnt/flash
Теперь устанавливаем на флешку ядро, мир, системные конфиги и скрипты (etc):
cd /usr/src
make installkernel
make installworld
cd /usr/src/etc
make distrib-dirs
make distribution
У меня в make.conf, помимо прочего, выключена сборка info и man (NO_INFO=YES NO_MAN=YES), поэтому, для нормальной установки портов на флешку, потребуется вручную поставить texinfo, как описано здесь.
cd /usr/src/gnu/usr.bin/texinfo
make install
После этого правим fstab на флешке:
# Device Mountpoint FStype Options Dump Pass#
/dev/da0s1a / ufs ro 1 1
md /tmp mfs rw,-s24M,noatime 0 0
md /var mfs rw,-s128M,noatime` 0 0
Поскольку /var будет смонтирован в памяти, необходимо перенести /var/db на флешку, чтобы данные об установленных портах не терялись между перезапусками. Для этого создаем ссылку:
mkdir /mnt/flash/etc/pkg
ln -s ../../etc/pkg /mnt/flash/var/db/pkg
Теперь можно настраивать систему на флешке, править конфиги и ставить порты с рабочей системы (необходимо только в resolv.conf на флешке прописать dns-сервера).
Например:
cd /usr/ports/net/isc-dhcp30-server
make
make install
Флаг DESTDIR в make.conf укажет make install что ставить порт нужно на флешку.

[Проблемы с dns-сервером named]

По-умолчанию named запускается системой в песочнице (chroot'ом) в каталоге /var/named. Вынести этот каталог на флешку нельзя, поскольку named должен иметь возможность писать в свой маленький /var. Вариант, который использовал я, заключается в добавлении в rc.local копирования конфига named каждый раз при старте системы:
# копируем конфиг named
mkdir -p /var/named/etc
cp -Rp /usr/local/etc/namedb /var/named/etc
/etc/rc.d/named start
На мой взгляд, это несколько коряво и я с удовольствием выслушал бы другие варианты решения.

[Загрузка установленной системы]

Подключаем флешку к роутеру и выставляем в биосе загрузку с нее. На некоторых материнках возможен баг, когда флешка не успевает определиться к тому моменту, когда загрузчик начинает монтировать корень. Хак для данной проблемы описан в конце этой статьи на Хабре.
После загрузки системы можно продолжить ее настройку. Для этого достаточно перемонтировать корень на запись:
mount -uw /
После внесения нужных изменений (установки портов/правки конфигов/добавления пользователей и т.д.) нужно вернуть корень в доступ только на чтение:
mount -ur /

UPDATE: Как отметили в комментариях, нет смысла вручную монтировать /var и /tmp. В случае, если при загрузке /var и /tmp доступны только на чтение, будет автоматически вызван /etc/rc.initdiskless, который, по-умолчанию, смонтирует эти разделы в оперативную память. Поэтому из fstab можно убрать строчки про /var и /tmp, а в /etc/rc.conf добавить параметры для скрипта rc.initdiskless:
tmpmfs=true
tmpsize=24M
varmfs=true
varsize=128M

Обновлено: 12.03.2015