Що я готую заздалегідь
Це треба зробити до того, як друг почне встановлення — інакше він застрягне на кроці 6.
SSH-ключ через GitHub
Найзручніший спосіб передати публічний ключ: залити його в GitHub. В інсталяторі Ubuntu є поле «Import SSH identity → from GitHub» — друг вводить мій нік, ключ підтягується сам. Нічого не диктувати по телефону.
ssh-keygen -t ed25519 -C "home-server" -f $env:USERPROFILE\.ssh\home_server_ed25519Далі GitHub → Settings → SSH and GPG keys → New SSH key. Перевірити, що ключ віддається публічно: відкрити https://github.com/МІЙ_НІК.keys
Ключ Tailscale
- Зареєструватись на tailscale.com
- Admin console → Settings → Keys → Generate auth key. Reusable: ні. Термін: 90 днів.
- Скопіювати
tskey-auth-…— його вставляє друг у кроці 7
Після того, як сервер підключиться — зайти в Machines → сервер → «…» → Disable key expiry.
Без цього через 180 днів ключ вузла протухне, і доступ зникне саме тоді, коли цього найменше чекаєш.
Що надіслати другу
- Посилання на цю сторінку (у режимі «Тільки для друга»)
- Мій нік на GitHub
- Ключ
tskey-auth-… - Домовитись про пароль локального користувача
Частина A · виконує друг, фізично біля машини
На місці
Орієнтовно 2–4 години активної роботи. Тести пам'яті й дисків можна лишити на ніч. Далі все роблю я віддалено.
Зібрати дані про залізо
Від цього залежить, чи потягне машина Immich і скільки треба докупити. Найпростіше — завантажитись з флешки Ubuntu (крок 4) в режимі shell і виконати:
lscpu
free -h
lsblk -o NAME,SIZE,MODEL,ROTA
sudo dmidecode -t baseboard -t memoryПотрібно знати: модель материнки й процесора, скільки RAM і скільки слотів вільних, які диски стоять (SSD чи HDD), модель блока живлення з наліпки збоку.
Фізична ревізія
Машина стоятиме 24/7 і в ній лежатимуть фотографії. Треба переконатись, що вона не помре через місяць.
- Повністю продути від пилу: кулер CPU, блок живлення, корпусні вентилятори
- Перевірити блок живлення — зняти кришку, оглянути конденсатори. Здуті або потекли зверху = БЖ під заміну
- Замінити термопасту на процесорі, якщо їй понад 5 років
- Замінити батарейку CR2032 на материнці
- Прибрати все зайве: старі PCI-карти, дисковод, непотрібні диски
- Після збірки перевірити, що всі вентилятори реально крутяться
Здутий конденсатор у блоці живлення — найчастіша причина смерті старих компів і цілком реальний ризик пожежі. Це той пункт, на якому не варто економити.
Тест пам'яті та дисків
Пам'ять
Записати memtest86+ (memtest.org) на флешку і прогнати мінімум два повні проходи, краще всю ніч. Будь-яка помилка = битий модуль: витягти по одному й знайти який.
Диски
sudo apt update && sudo apt install -y smartmontools
lsblk
sudo smartctl -a /dev/sda # і так для кожного диска| Атрибут | Що означає |
|---|---|
| Reallocated_Sector_Ct (5) | > 0 — диск сиплеться |
| Current_Pending_Sector (197) | > 0 — не використовувати |
| Offline_Uncorrectable (198) | > 0 — не використовувати |
| UDMA_CRC_Error_Count (199) | > 0 — швидше за все поганий SATA-кабель, замінити |
| Power_On_Hours (9) | понад 40 000 год ≈ 4,5 роки безперервної роботи |
Довгий тест (кілька годин, можна паралельно з іншим):
sudo smartctl -t long /dev/sda
# через кілька годин:
sudo smartctl -l selftest /dev/sda- memtest86+: два проходи без помилок
- SMART усіх дисків чистий, вивід надіслано мені
Флешка з Ubuntu Server 24.04 LTS
Завантажити образ (~2,5 ГБ) з releases.ubuntu.com/24.04 або ubuntu.com/download/server.
Потрібен файл виду ubuntu-24.04.x-live-server-amd64.iso — саме server, не desktop, і amd64.
| Система | Чим записати |
|---|---|
| Windows | Rufus (rufus.ie) — налаштування за замовчуванням підходять |
| Будь-яка | Ventoy (ventoy.net) — зручніше, кілька ISO на одній флешці |
| Linux / macOS | balenaEtcher |
Налаштування BIOS
Зайти в BIOS (Del / F2 / F10 при старті). Це найважливіші п'ять хвилин усієї роботи.
Restore on AC Power Loss → Power On
У різних BIOS називається по-різному: AC Back Function, After Power Failure, Power On After Power Fail, State After Power Loss. Значення: Power On або Last State.
Без цього після першого ж зникнення світла сервер просто не увімкнеться — і треба буде їхати або просити когось натиснути кнопку.
- Restore on AC Power Loss → Power On
- Halt On → No Errors (щоб стартувало без клавіатури)
- Boot order: спочатку USB, потім системний диск
- Fast Boot → вимкнено
- Вимкнути зайве: серійні порти, аудіо, вбудований Wi-Fi
- Wake-on-LAN → Enabled, якщо є
- Виставлені правильні дата й час
- Пароль на BIOS не ставити (або поставити й надіслати мені)
Встановлення Ubuntu Server
Комп під'єднаний до роутера кабелем (не Wi-Fi), флешка вставлена, вантажимось з неї.
| Крок інсталятора | Що обрати |
|---|---|
| Language | English — щоб помилки легше гуглити |
| Type of install | Ubuntu Server (не minimized) |
| Network | Лишити DHCP. Записати IP, який видало |
| Proxy | пусто |
| Mirror | за замовчуванням |
| Storage | Use an entire disk → обрати SSD. Галочку «Set up this disk as an LVM group» лишити |
| Profile | Server name: home-server, username: maksym |
| Ubuntu Pro | Skip for now |
| SSH Setup | ✅ Install OpenSSH server + Import SSH identity → from GitHub |
| Featured snaps | нічого не обирати |
Шифрування диска (LUKS) — не вмикати.
Воно вимагає ввести пароль з фізичної клавіатури при кожному завантаженні. На машині за 3000 км це означає, що після кожного відключення світла сервер стоятиме й чекатиме людину.
Після «Reboot Now» витягти флешку, дочекатись завантаження, увійти в консоль і виконати:
ip -4 addr show
sudo apt update && sudo apt upgrade -yНадіслати мені IP-адресу.
Tailscale — щоб я міг зайти ззовні
Це замість прокидання портів. Роутер чіпати не треба взагалі — три команди, і все.
Я надішлю довгий ключ виду tskey-auth-…. Вставити його в другий рядок:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh --authkey ВСТАВИТИ_КЛЮЧ_СЮДИ
tailscale ip -4Остання команда покаже адресу виду 100.x.x.x — надіслати її мені. Після цього фізична частина завершена.
Розміщення й дрібниці
- Поставити так, щоб було провітрювання — не в шафу й не впритул до стіни
- Під'єднати до ДБЖ, а не до звичайного подовжувача
- Монітор і клавіатуру можна відключити
- Флешку з Ubuntu не форматувати — покласти поруч з компом на випадок відновлення
- Написати мені, до якого роутера й порту він підключений
Частина B · виконую я, віддалено по SSH
Віддалено
З цього моменту фізична присутність більше не потрібна. Головне правило нижче — прочитати перш ніж торкатись чогось.
Перший вхід
Ставлю Tailscale собі на Windows, далі в ~/.ssh/config:
Host homeserver
HostName 100.x.x.x
User maksym
IdentityFile ~/.ssh/home_server_ed25519
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6ssh homeserverГоловне правило віддаленої роботи
Ніколи не закривати робочу SSH-сесію, поки зміни не перевірені другою сесією. Змінив sshd, файрвол чи мережу → відкрив нове вікно → переконався, що заходить → тільки тоді закрив старе.
Для особливо ризикованих кроків — страховка з автоматичним відкатом:
# якщо через 10 хвилин я не скасую — конфіг відкотиться сам
sudo bash -c 'sleep 600 && cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config && systemctl restart ssh' &
# коли переконався, що все працює:
sudo kill %1Три незалежні канали доступу
- OpenSSH з ключем через Tailscale IP
- Tailscale SSH (
--ssh) — працює, навіть якщо я зламаю/etc/ssh/sshd_config - Друг з монітором і клавіатурою
Опційно, якщо проєкт надовго: розумна розетка Shelly Plug S (~€20) для примусового перезапуску живлення без друга, або апаратний KVM-over-IP — JetKVM чи PiKVM ($70–150) — який дає BIOS і вибір завантаження віддалено.
База системи
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y curl git htop vim tmux ncdu smartmontools \
unattended-upgrades needrestart
sudo timedatectl set-timezone Europe/Kyiv
sudo hostnamectl set-hostname home-serverДожати LVM
Інсталятор Ubuntu віддає логічному тому лише частину диска — класична пастка, на якій потім раптово закінчується місце.
df -h /
sudo vgdisplay | grep Free
# якщо є вільне місце:
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lvЗаборонити сон
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.targetЯкщо це ноутбук — ще й реакція на кришку:
sudo mkdir -p /etc/systemd/logind.conf.d
sudo tee /etc/systemd/logind.conf.d/99-server.conf >/dev/null <<'EOF'
[Login]
HandleLidSwitch=ignore
HandleLidSwitchDocked=ignore
HandleLidSwitchExternalPower=ignore
EOF
sudo systemctl restart systemd-logindОбмежити логи
sudo sed -i 's/^#SystemMaxUse=.*/SystemMaxUse=300M/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journaldzram, якщо RAM мало
sudo apt install -y systemd-zram-generator
sudo tee /etc/systemd/zram-generator.conf >/dev/null <<'EOF'
[zram0]
zram-size = ram / 2
compression-algorithm = zstd
EOF
sudo systemctl daemon-reload
sudo systemctl start systemd-zram-setup@zram0.serviceБезпека
SSH тільки по ключу
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf >/dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers maksym
EOF
sudo sshd -t && sudo systemctl restart sshssh.socket). Якщо колись знадобиться змінити порт — правити треба /etc/systemd/system/ssh.socket.d/, а не тільки sshd_config. При Tailscale міняти порт сенсу немає.Файрвол
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow in on tailscale0
sudo ufw allow from 192.168.0.0/16 to any port 22 proto tcp
sudo ufw enable
sudo ufw status verboseDocker публікує порти в обхід ufw — він пише напряму в iptables, і правила ufw його не стосуються.
Тому в compose-файлах прив'язувати порти явно до локального інтерфейсу: 127.0.0.1:2283:2283, а назовні віддавати через reverse proxy.
Оновлення
sudo dpkg-reconfigure -plow unattended-upgradesАвтоперезавантаження не вмикати: якщо машина не підніметься, це поїздка на 3000 км. Замість цього — безкоштовний Ubuntu Pro (до 5 машин) з Livepatch, який закриває ядерні вразливості без ребута:
sudo pro attach <token>
sudo pro enable livepatchfail2ban потрібен тільки якщо щось таки стирчить у публічний інтернет. При чистому Tailscale — не обов'язковий.
Диск під дані
lsblk -f
sudo mkfs.ext4 -L data /dev/sdb1
sudo blkid /dev/sdb1
sudo mkdir -p /srv/dataРядок у /etc/fstab:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /srv/data ext4 defaults,nofail,x-systemd.device-timeout=10 0 2nofail — не забути. Без нього збійний диск підвішує завантаження на emergency shell, і сервер не підніметься взагалі. З ним машина просто стартує без цього диска, а я побачу проблему в моніторингу.
sudo mount -a && df -h /srv/data
sudo systemctl enable --now smartdDocker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# перелогінитись
docker compose versionОбмежити логи контейнерів — інакше з часом з'їдають диск:
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
EOF
sudo systemctl restart dockerРозкладка файлів
| Шлях | Що там |
|---|---|
| /srv/docker/ | compose-файли, .env, конфіги — на SSD, і в приватному git-репо |
| /srv/data/ | великі дані: фото, документи — на HDD |
Сервіси
Фото — Immich
Найближче до Google Photos: мобільні застосунки з автобекапом, розпізнавання облич, таймлайн, пошук. Compose і .env брати з офіційної інструкції.
UPLOAD_LOCATION=/srv/data/immich- Базу Postgres тримати на SSD — на HDD воно повзатиме
- Якщо RAM менше 6 ГБ — прибрати контейнер
immich-machine-learning - Версії в compose пінити явно: Immich активно розвивається, ламаючі зміни трапляються
Документи
| Сервіс | Для чого |
|---|---|
| Paperless-ngx | Сканування, OCR, теги, повнотекстовий пошук. Для архіву документів — найкраще |
| Seafile | Швидка синхронізація файлів, легший за Nextcloud |
| Nextcloud AIO | Якщо потрібні ще календар, контакти й офіс. Важчий і повільніший |
| Filebrowser | Просто веб-файловий менеджер, ~30 МБ |
Обслуговування
| Сервіс | Для чого |
|---|---|
| Dockge / Portainer | Веб-інтерфейс для compose-стеків |
| Beszel | Легкий моніторинг: CPU, RAM, диск, температури, алерти |
| Uptime Kuma | Пінгує сервіси й пише в Telegram, коли щось лягло |
| Caddy | Reverse proxy з автоматичним TLS, конфіг у п'ять рядків |
HTTPS і доступ
Для старту: тільки всередині Tailscale
Увімкнути MagicDNS і HTTPS в admin console, далі:
sudo tailscale cert home-server.<мій-тейлнет>.ts.netОтримую справжній сертифікат Let's Encrypt на ім'я в .ts.net — без жодного відкритого порту. Caddy роздає сервіси по піддоменах, заходжу з будь-якого свого пристрою з Tailscale.
Якщо треба ділитись посиланням назовні
Cloudflare Tunnel — теж без прокидання портів, плюс Cloudflare Access зверху, щоб не світити сервіс голим.
Класичний проброс 80/443 має сенс тільки якщо в друга білий IP і я готовий чіпати його роутер. Без потреби — не варто.
Бекапи
Сервер — це не бекап. Один диск, одна квартира, одна пожежа або крадіжка.
sudo apt install -y resticКуди: Backblaze B2 (~$6 за ТБ на місяць) або Hetzner Storage Box (1 ТБ ≈ €4/міс, підтримує rsync і Borg).
Що бекапити:
/srv/data/— фото й документи/srv/docker/— compose, конфіги,.env- Дампи баз: для Immich —
pg_dump, а не копія файлів тому
Раз на квартал — перевірити відновлення на кількох файлах. Неперевірений бекап не існує.
Фінальний чекліст
- memtest86+ — два проходи без помилок
- SMART усіх дисків чистий
- BIOS: авто-увімкнення після зникнення живлення
- Ubuntu Server 24.04 LTS, OpenSSH, ключ імпортовано
- Tailscale підключено, key expiry вимкнено
- Вхід по ключу працює, паролі вимкнено
- ufw налаштовано, вхід через tailscale0 є
- LVM розширено на весь диск
- Диск даних змонтовано з
nofail - Docker + ліміти логів
- Сон замасковано
- Immich / Paperless піднято
- Uptime Kuma шле алерти в Telegram
- restic ллє на офсайт, відновлення перевірено
- Тест: вимкнути з розетки й переконатись, що сервер піднявся сам
Коли все зламалось
Завести приватний репозиторій або нотатку і тримати там усе, що через рік уже не пам'ятатимеш:
- IP у Tailscale, hostname, ім'я користувача, де лежить ключ
- Логін і пароль локального користувача
- Контакт друга й що саме можна його попросити зробити
- Що виставлено в BIOS, які диски за що відповідають
- Список стеків і портів
- Куди йдуть бекапи і як з них відновлюватись
Порядок відновлення доступу: Tailscale SSH → локальна мережа друга → друг з монітором → завантаження з тієї самої флешки.