Мінісервер, від ідеї до девайсу

Ідея створення домашнього мінісерверу стара як світ. Навіть у 2006му коли я збирав сервер що мав працювати у мережі гуртожитку я не був а ні першим а ні сотим хто до такого додумався.

Станом на сьогодні ідея домашнього серверу все щє є актуальною. Так є безліч хмарних сервісів, але вони зїдають багато коштів і надають лімітовану кількість ресурсів. Тому, здебільшого, ми використовуємо хмарні сервіси лише для проектів які вже готові вийти в світ та приносити певну користь, в той час як різні випробувальні пет-проекти простіше розгорнути на домашньому сервері. До того ж є безліч сервісів які дуже корисні в домашній мережі і не має жодного сенсу розгортати їх в хмарі, на приклад plex або jellyfin, різні варіації розумного будинку та багато інших.

В моєму випадку пет-лаб був завжди розділений на дві основні частини. Це був NAS (Network-attached storage) що використовувся за прямим призначенням та невеличкий домашній сервер, що раннив кубер.

Про збірку останньої версії домашнього сервера в мене навіть є невеличке відео на youtube:

В якості нас я використовував Synology ds716+ii, маю сказати що з 2016го року з ним не разу не виникало пробем (Якщо не враховувати відмову диску).

До недоліків девайсу можу віднести доволі слабенку аппаратну частину, що дуже контрастує з можливостями системи DSM. Враховуючи наявність більш потужного серверу це не створювало проблем. Тим паче що NAS я використовува саме як NAS, а, на приклад, plex був запущєний на великому сервері та використовував простір насу через NFS.

24го лютого В наше життя внесла коррективи війна, так, для декого вона внесла коррективи щє у 2013-14му роках а у 22гому дісталась і до нас.

Коли ви живете в арендованому житлі та напевно не знаєте скілька разів вам доведеться переїжжати, коли і куди, тримати великі сервери вже не така класна ідея, адже їх доведеться возити за собою весь час. Тому в мене з’явилась ідея побудувати достатньо потужний nas, що буде тримати певну кількість пет-проектів та сервісів а тако ж виконуватиме свою пряму функцію

Вимоги

Давайте для початку розберемось з вимогами.

  • Компактний розмір
  • Достатньо тихий
  • Адекватне споживання енергії
  • Адекватний зовнішній вигляд
  • Можливість встановлення 3х-4х дисків 3.5
  • Можливість встановлення ssd (sata та/або m2)
  • Стандартний набір функцій нас (Захист данних / реплікація / моніторинг стану дисків та ін)
  • Можливість раннити певну кількість сервісів (plex/home assistant/ docker)

Ідея створення подібного мінісерверу тако ж не нова, та коли я взявся за її реалізацію виявилось що не так багато рішень та мануалів є у вільному доступі, саме тому вирішив написати цей допис, щоб поділитись моїм досвідом.

Залізо

Отже що до хардварю. Я мав процессор Core i5 7400 та материнську плату msi b250 що була не зовсім справна. Я придбав mini-itx плату Asrock z270m-itx/ac . Переваги цієї плати в тому що вона на борту має шість розьємів sata3, m2 порт та два гігабітні lan-порти (є щє wifi але він мене не цікавить). В цю збірку я додав 16ть гігбайт пам’яті, і наче вийшла вже непогана система.

Що до дисків, я мав два диска WD red plus (WD120EFBX) що стояли в synology один диск Seagate exos 10tb (взагалі то їх було два, але один з часом зламався), один sdd диск samsung evo 850 sata3 на 2tb і щє один samsung evo 970 m2 на 250гіг. Також я маю зовнішній usb диск WD myBook на 8 терабайт, але не певен що його варто розбирати і ставити в мінісервер.

Корпус

Ось тут я перший раз зрозумів що доведеться щось вигадувати. Так, є багато непоганих корпусів які ви можете використати, на приклад JONSBO має доволі широку лінійку класних корпусів. Я б обрав V11 black якби планував систему з дискретною відеокартою.

Тим не менш я маю певні сумніви що до тих корпусів, адже диски там встановлюються у передній частині, тобто якщо поставити корпус так як вони малюють є імовірність що домашній улюбленець його звалить на бік і це для дисків буде дуже не добре. Звісно, можна одразу його покласти на бік, але тоді виникають сумніви що до продувки. Я вирішив підти іншим шляхом і задизайнити власний корпус.

Перш за все, я хотів отримати якумога компактніший розмір (і маю визнати що мій корпус меньше за jonsbo n1 хоча і не на багато). Другою вимогою була ефективна продувака знизу в гору і третя – корпус мав бути спроектований таким чином щоб бути повністю надрукованим на 3д принтері.

Почав я звісно з продувки. В якості основного і єдиного кулера я придбав Fractal Design Prisma AL 18 це доволі продуктивний кулер що може створити потік повітря без зайвого шуму. Далі я відрізав від кулера корпус таким чином щоб отримати якумога довщі лучі кріплення і почав розробляти власний.

Нижня частина корпусу, за моїм задумом, мала відповідати саме за нагнітання повітря. Я не став додавати фільтри тому що досвід з synology показав що не так вже і багато пилу система тягне всередину, а в разі потреби можно продути все сжатим повітрям.

Далі основна секція що містить в собі всі комплетуючі.

Моя версія містить три диска 3.5, але простір корпусу дозволяє встановити 4й, за материнською платою, якщо трохи змінити положення. При такому розташуванні верхній диск за материнською платою охолоджується гірше і якщо решта дисків мають температуру 39-40 градусів після кількох годин напруженої роботи то верхній має 45-47 градусів. Це доволі далеко від критичної температури в 60 градусів та як на мене, не дуже добре.

У верхній частинні корпусу я вирішив розташувати сенсорну кнопку живлення та контроллер, про нього трохи далі, а поки що ось так виглядає мій корпус на кінцевій моделі

Цікаво, чи помітив хтось відсутність блока живлення? В якості нього я вирішив взяти плату pico-psu що живиться від 20ти вольт та вмонтував в корпус порт для підєднання зарядки від ноутбуку lenovo, бо я маю запасну зарядку від мого легіону потужністю 300 ват. Звісно це більше ніж потрібно цьому мінісерверу, але для мене так кращє адже не доведеться купляти блок живлення.

В разі, якщо ви захочете використати мій корпус не для NAS-у – можете взяти блок живлення формату tfx встановивши його або замість блоку дисків зліва або справа. Я спеціально зробив вікно навколо порта живлення такого розміру щоб можна було використати роз’єм 220 вольт.

Далі друкуємо всі деталі нашого корпусу

і збираємо до купи.

Контроллер корпусу

Якщо ви звернули увагу на купу проводів та не дуже акуратні плати зверху – це моє інше ноу-хау.

Справа в тому, що я б хотів мати можливість керувати станом мінісерверу віддалено і незалежно від того увімкнено сам сервер чи ні. На додачу хочеться мати можливість незалежно моніторити температуру всередині корпусу а також argb підсвітка потребує якийсь контроллер.

Всі перераховані вимоги задовольняє одна маленька Vemos mini. Цей ESP32 контроллер підєднаний до індикаторів та кнопок материнської плати через модулі гальванічної розв’язки PC817. Тут треба врахувати що цей модуль розрахований на 5В логіку Arduino. Тобто модуль що підєднано до індикаторів працює з коробки, але той що підєднано до кнопок потребує модифікації інакше працювати не буде. Щоб змусити модуль корректно працювати з esp32 треба замінити резістор на інший, з меншим номіналом.

Далі все просто, розводимо порти як нам зручно, підєднуємо все до купи і пишемо скетч. Найпростіша схема виглядатиме приблизно так:

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

Датчик температури щє не доїхав, тому поки що без нього.

Що до Blynk-у, я не експерт у ньому але з того що я зрозумів, треба створити шаблон для вашого майбутнього девайсу і вже потім створювати сам девайс. У шаблоні ви можете описати віртуальні порти що будете використовувати на налаштувати віджети (контроли).

І далі у самому скетчі ви вже можете використовувати datastream-и за їх віртуальними портами. Ось так може виглядати ваш скетч до попередньої схеми з використанням blynk

#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "{ваш templateId з blynk}"
#define BLYNK_TEMPLATE_NAME "Pc power controll"
#define BLYNK_AUTH_TOKEN "{ваш токен з blynk}"

#include <Arduino.h>
#include <Bounce2.h>
#include <WS2812FX.h>
#include <BlynkSimpleEsp32.h>

#define WIFI_SSID "{ваш ssid}"
#define WIFI_PASSWORD "{ваш пароль wifi}"

#define LED_BUILTIN 2

#define SENSOR_BTN_PIN 19

#define CONTROL_POWER_PIN 17
#define CONTROL_RESET_PIN 4

#define LED_POWER_PIN 33
#define LED_ACTIVITY_PIN 35

#define RGB_PIN 25
#define RGB_LED_COUNT 35

WS2812FX ws2812fx = WS2812FX(RGB_LED_COUNT, RGB_PIN, NEO_GRB + NEO_KHZ800);

Bounce sensorButtonState = Bounce();

Bounce ledPowerState = Bounce();
Bounce ledActivityState = Bounce();

BlynkTimer blynk_timer;

int rgb_brightness = 90;
int standby_mode = FX_MODE_BREATH;
int rgb_transition_speed = 100;

BLYNK_WRITE(V0){
  Serial.print("V0 is:");
  Serial.println(param.asInt());

  if((1 == param.asInt() && 0 == ledPowerState.read()) || (0 == param.asInt() && 1 == ledPowerState.read())){
    digitalWrite(CONTROL_POWER_PIN, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);

    digitalWrite(CONTROL_POWER_PIN, LOW);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
    ledPowerState.update();
    void updatePowerState();
  }
}

BLYNK_WRITE(V1){
  Serial.print("V1 is:");
  Serial.println(param.asInt());
  if(1 == param.asInt()) {
    digitalWrite(CONTROL_RESET_PIN, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(CONTROL_RESET_PIN, LOW);
    digitalWrite(LED_BUILTIN, LOW);
    Blynk.virtualWrite(V1, 0);
  }
}

BLYNK_WRITE(V2){
  Serial.print("V2 is:");
  Serial.println(param.asInt());
  rgb_brightness = param.asInt();
  ws2812fx.setBrightness(rgb_brightness);
}

BLYNK_CONNECTED(){
  Blynk.syncAll();
}

void blynk_tick(){
  Blynk.virtualWrite(V6, millis() / 1000);
}

void updatePowerState(){
  int powerState = ledPowerState.read();
  Serial.print("Power state is: ");
  Serial.println(powerState);
  Blynk.virtualWrite(V3, powerState);
  Blynk.virtualWrite(V0, powerState);
  if(1 == powerState) {
    ws2812fx.setMode(FX_MODE_STATIC);
    ws2812fx.setBrightness(rgb_brightness);
  } else {
    ws2812fx.setMode(standby_mode);
    ws2812fx.setBrightness(rgb_brightness / 2);
  }
}
void updateActivityState(){
  int activityState = ledActivityState.read();
  Blynk.virtualWrite(V4, activityState);
  if(1 == activityState) {
    ws2812fx.setColor(RED);
  } else {
    ws2812fx.setColor(WHITE);
  }
}

void setup() {
  Serial.begin(115200);

  pinMode(CONTROL_POWER_PIN, 0x02);
  pinMode(CONTROL_RESET_PIN, OUTPUT);

  sensorButtonState.attach(SENSOR_BTN_PIN, INPUT_PULLDOWN);
  ledPowerState.interval(3);

  ledPowerState.attach(LED_POWER_PIN, INPUT_PULLDOWN);
  ledPowerState.interval(3);

  ledActivityState.attach(LED_ACTIVITY_PIN, INPUT_PULLDOWN);
  ledActivityState.interval(3);

  pinMode(LED_BUILTIN, OUTPUT);

  ws2812fx.init();
  ws2812fx.setBrightness(rgb_brightness);
  ws2812fx.setSpeed(rgb_transition_speed);
  ws2812fx.setMode(standby_mode);
  ws2812fx.setColor(WHITE);
  ws2812fx.start();

  Blynk.begin(BLYNK_AUTH_TOKEN, WIFI_SSID, WIFI_PASSWORD);
  blynk_timer.setInterval(1000L, blynk_tick);

  ledPowerState.update();
  updatePowerState();
  ledActivityState.update();
  updateActivityState();
}

void loop() {
  sensorButtonState.update();
  
  if(sensorButtonState.changed()) {
    int sensorValue = sensorButtonState.read();
    Serial.print("SENSOR level is:");
    Serial.println(sensorValue);
    Blynk.virtualWrite(V5, sensorValue);
    digitalWrite(CONTROL_POWER_PIN, sensorValue == 1 ? HIGH : LOW);
    digitalWrite(LED_BUILTIN, sensorValue == 1 ? HIGH : LOW);
  }

  ledPowerState.update();
  if(ledPowerState.changed()) {
    updatePowerState();
  }

  ledActivityState.update();
  if(ledActivityState.changed()) {
    updateActivityState();
  }
  
  Blynk.run();
  blynk_timer.run();
  ws2812fx.service();
}

Звісно цей скетч дуже сирий і взагалі варто щє доопрацювати контроллер. На приклад замість використання Bounce2, кращє додати pull-down резістори та і сам скетч потребує щє виправлень. Тут щє немає датчику DHT11, та провізії wifi. Станом на зараз я щє в процессі вдосконалення цієї частини тому оновлену версію, скоріш за все, додам пізніше.

Результат

Зрештою коли все було зібрано отримуємо ось такий результат:

Дружина вже навіть дала оцінку моєму дизайну, сказала що схоже на комфорку газової пічки :D. Тим не менш мінісервер вже працює і виконує свої функції. Допис вийшов доволі великим тому про операційну систему напишу окремо.

Якщо ви дочитали до цього місця, от вам невеличкий бонус: