Skip to main content

HP D2700: схема дисковых массивов и назначение хранилищ

HP D2700: схема дисковых массивов и назначение хранилищ

Версия 1.8
Дата 10.11.2026
Статус P411 с 512 MB FBWC и firmware 6.64 работает в PCIe Slot 1 как PCIe Gen2 x8. D2700 firmware 0150, все 25 дисков исправны, production RAID-массивы созданы. MAIN-DATA передан в VM 103, production Btrfs смонтирован в /srv/main-data. Созданы 8 функциональных Btrfs subvolume, Snapper, группы и POSIX ACL. Samba введена в эксплуатацию: опубликованы 8 SMB shares, проверена матрица доступа, Windows Previous Versions, Samba recycle и автоматическая очистка корзин. ACL корзин скорректированы для административного доступа через File Browser без раскрытия пользовательских корзин профильным группам. Установлен и проверен File Browser Next v3.0.0-next как отдельный systemd-сервис. Management-маршрутизация переведена на gateway 10.44.100.1 через ens19.

DNS-интеграция файлового сервера введена в эксплуатацию: настроен split DNS через systemd-resolved, для пяти OT-сегментов зарегистрированы отдельные FQDN и согласованные A/PTR, создан /usr/local/sbin/ot-ddns-register и включён ot-ddns-register.service.

На Windows-клиенте проверена штатная процедура переключения Samba-учётной записи: BAT change_share.bat отключает только SMB-сессии к SMR-SRV-OT-SHARE по всем известным IP/FQDN/коротким именам, очищает связанные сохранённые credentials и не затрагивает сетевые подключения к другим серверам.

Добавлена модель read-only доступа для производственных подразделений: shared-ro даёт RO к exchange, software и documentation; профильные группы pivoproduction-ro, rozliv-ro и utilities-ro дают RO только к соответствующему производственному share. Для RO-групп настроены обычные и default POSIX ACL с исключением .snapshots и .recycle. Учётная запись rozliv_read проверена локально: доступ только на чтение соответствует принятой матрице.

Введён в эксплуатацию конфигурационный backup файлового сервера: создан /usr/local/sbin/share-config-backup, который формирует обычный архив конфигурации и инвентаризации, отдельный зашифрованный AES-256 архив Samba/File Browser credential/state DB и файл SHA256. Первый recovery-набор сформирован и вынесен с сервера.
Проект Расширение памяти сервера

1. Назначение документа

Документ фиксирует production-архитектуру хранения HP ProLiant DL380 G7 с внешней дисковой полкой HP StorageWorks D2700, контроллером Smart Array P411, аппаратными RAID, виртуальной машиной Ubuntu Server, Btrfs, Snapper, POSIX ACL и Samba.

Здесь рассматриваются основной файловый массив MAIN-DATA, локальный массив CRITICAL-BACKUP, служебный RECOVERY, общий горячий резерв, передача MAIN-DATA в VM 103 и публикация функциональных ресурсов по SMB. TFTP/PXE/Cisco recovery для массива RECOVERY должен оформляться отдельной статьёй.

Начиная с версии 1.3 документ также фиксирует DNS-интеграцию многосетевого файлового сервера: маршрутизацию DNS-запросов по OT-интерфейсам через systemd-resolved, сегментные FQDN, RFC 2136/DDNS через nsupdate и правила коротких имён для клиентов.

2. Состав оборудования

Сервер HP ProLiant DL380 G7
Гипервизор Proxmox VE 9.1.9
Внутренний RAID HP Smart Array P410i, firmware 6.64, 512 MB cache
Внешний RAID HP Smart Array P411, PCIe Slot 1, firmware 6.64, 512 MB FBWC
Полка HP StorageWorks D2700, 25 × 2.5" SFF SAS
Firmware D2700 0150
Подключение P411 port 1E → SFF-8088 → D2700 I/O Module A, P1
Режим Single Domain

3. Физическая раскладка дисков D2700

Отсеки Диски Роль Имя
1–12 12 × 600 GB SAS 10K Основной RAID50 MAIN-DATA
13–14 2 × 146 GB SAS 15K RAID1 RECOVERY
15 1 × 600 GB SAS 10K Shared online spare GLOBAL-SPARE
16–25 10 × 500 GB SAS 7.2K Резервный RAID50 CRITICAL-BACKUP
HP D2700 — bays 01–25

01–12  600 GB  MAIN-DATA
13–14  146 GB  RECOVERY
15     600 GB  GLOBAL-SPARE
16–25  500 GB  CRITICAL-BACKUP

4. Production RAID-массивы

4.1. MAIN-DATA

RAID RAID50
Состав 12 × 600 GB SAS 10K
Parity groups 2 группы: bays 1–6 и 7–12
Strip size 256 KiB
Полезная ёмкость 5.46 TiB / 6.00 TB
Назначение рабочие данные, SMB/NFS, Clonezilla

4.2. RECOVERY

RAID1 из bays 13–14, около 136 GiB. Зарезервирован под отдельный TFTP/PXE/Cisco recovery-проект.

4.3. GLOBAL-SPARE

Bay 15, 600 GB SAS 10K. P411 отображает диск как shared spare. При отказе активного диска контроллер автоматически использует spare для rebuild. После установки замены в штатный bay контроллер может выполнить copy-back, после чего bay 15 снова становится свободным spare.

4.4. CRITICAL-BACKUP

RAID50 из 10 × 500 GB SAS 7.2K, две parity group по пять дисков, полезная ёмкость около 3.64 TiB. Используется для локальных копий выбранных критичных данных и не публикуется как обычная пользовательская шара.

CRITICAL-BACKUP не является независимым backup: MAIN-DATA и CRITICAL-BACKUP находятся в одной D2700 и зависят от одного P411, сервера и общей инфраструктуры питания.

5. Логика использования хранилищ

MAIN-DATA
├── рабочие документы
├── SMB shares
├── NFS при необходимости
└── Clonezilla
        │
        └── выбранные критичные копии
                ↓
        CRITICAL-BACKUP

RECOVERY
└── отдельный TFTP/PXE/Cisco recovery проект

6. Имена объектов

Объект Имя Статус
Основной RAID50 MAIN-DATA Создан
Служебный RAID1 RECOVERY Создан
Общий spare GLOBAL-SPARE Назначен
Резервный RAID50 CRITICAL-BACKUP Создан

7. Ввод P411 и D2700 в эксплуатацию

Первоначальный 256 MB cache-модуль P411 оказался неисправным и приводил к ошибке self-test. После установки исправного 512 MB FBWC и обновления firmware до 6.64 P411 корректно заработал с SAS-expander D2700. D2700 и оба I/O-модуля работают на firmware 0150.

7.1. Диагностика PCIe/IOCK

При размещении P411 в прежнем PCIe Slot 5 воспроизводились IOCK, reset и controller lockup. Перевод драйвера hpsa в simple mode не устранил проблему. После переноса P411 в PCIe Slot 1 контроллер согласовал PCIe Gen2 5 GT/s ×8; повторных IOCK/lockup в контрольном периоде не зафиксировано.

7.2. Контроль через ssacli

ssacli ctrl all show status
ssacli ctrl slot=1 show detail
ssacli ctrl slot=1 show config
ssacli ctrl slot=1 ld all show detail
ssacli ctrl slot=1 pd all show status

Production checkpoint P411: Controller/Cache/Capacitor Status = OK; firmware 6.64; cache ratio 25% read / 75% write.

7.3. Parity initialization

MAIN-DATA и CRITICAL-BACKUP сохраняют Parity Initialization Status: Queued, при этом logical drive имеют Status: OK. Это не блокирует эксплуатацию, но статус продолжает контролироваться.

8. Виртуальная машина файлового сервера

VM ID 103
Имя SMR-SRV-OT-SHARE
Hostname smr-srv-ot-share
ОС Ubuntu Server 24.04.4 LTS
CPU 4 vCPU, type host
RAM 8 GiB
Системный диск 100 GiB, ext4/LVM
Production data MAIN-DATA через отдельный SCSI device
DNS-зона OT ot-samara.baltika.ru
DNS-модель Multi-homed: отдельный FQDN на каждый OT-сегмент; автоматическая регистрация A/PTR через RFC 2136

9. Системный диск VM

Системный диск 100 GiB размещён на внутреннем хранилище Proxmox/P410i. Корневая файловая система Ubuntu — ext4 поверх LVM; production-данные на системном диске не хранятся.

10. Сетевые интерфейсы VM

Ubuntu Сегмент Адрес Маршрутизация
ens18 временная сеть настройки 192.168.1.229/24 без default gateway
ens19 Prod management VLAN2100 10.44.100.229/24 default gateway 10.44.100.1
ens20 Rozliv VLAN2002 172.16.68.229/23 connected route
ens21 Pivoproduction VLAN2030 целевой 172.16.66.229/23 целевой интерфейс; route 172.16.66.0/23 пока остаётся на ens23
ens22 Utilities VLAN2040 172.16.70.229/23 connected route
ens23 Legacy VLAN1 10.255.0.229/16 + переходный 172.16.66.229/23 connected: 10.255.0.0/16 и переходный 172.16.66.0/23
enp2s1 АСТУЭ VLAN2006 172.17.14.229/24 connected route

Адрес 172.16.66.229 не должен одновременно находиться на legacy-интерфейсе и VLAN2030. После миграции он переносится на целевой интерфейс VLAN2030.

Основной маршрут по умолчанию для VM: default via 10.44.100.1 dev ens19. На ens18 адрес 192.168.1.229/24 сохранён для локального сервисного доступа, но default gateway через 192.168.1.1 удалён. Это исключает два конкурирующих default route и обеспечивает обратный трафик к корпоративной сети через management VLAN2100.

Проверенная таблица маршрутизации после netplan try:

default via 10.44.100.1 dev ens19 proto static
10.44.100.0/24 dev ens19 proto kernel scope link src 10.44.100.229
10.255.0.0/16 dev ens23 proto kernel scope link src 10.255.0.229
172.16.66.0/23 dev ens23 proto kernel scope link src 172.16.66.229
172.16.68.0/23 dev ens20 proto kernel scope link src 172.16.68.229
172.16.70.0/23 dev ens22 proto kernel scope link src 172.16.70.229
172.17.14.0/24 dev enp2s1 proto kernel scope link src 172.17.14.229
192.168.1.0/24 dev ens18 proto kernel scope link src 192.168.1.229

10.1. Split DNS через systemd-resolved

Файловый сервер подключён одновременно к нескольким изолированным OT-сегментам. Для корректного обращения к локальному BIND9 каждому OT-интерфейсу назначается DNS-адрес своего сегмента. Маршрутизация запросов выполняется systemd-resolved через route-only domains с префиксом ~.

Важно: ~ot-samara.baltika.ru — это не search suffix. Он определяет, на какой DNS отправлять запрос. Расширение короткого имени выполняется на клиенте через DNS suffix search list и описано в разделе 20.14.

Интерфейс Сегмент DNS Route-only domains
ens18 временная сеть настройки 192.168.1.1 общий/внешний resolver; без OT route-only domain
ens20 Rozliv 172.16.68.53 ~ot-samara.baltika.ru, ~68.16.172.in-addr.arpa, ~69.16.172.in-addr.arpa
ens22 Utilities 172.16.70.53 ~ot-samara.baltika.ru, ~70.16.172.in-addr.arpa, ~71.16.172.in-addr.arpa
ens23 Legacy + временно Pivo 10.255.0.53, 172.16.66.53 ~ot-samara.baltika.ru, ~255.10.in-addr.arpa, ~66.16.172.in-addr.arpa, ~67.16.172.in-addr.arpa
enp2s1 АСТУЭ 172.17.14.53 ~ot-samara.baltika.ru, ~14.17.172.in-addr.arpa
ens21 Pivoproduction VLAN2030, целевой пока не назначен после миграции сюда переносятся DNS 172.16.66.53 и route-only domains ~ot-samara.baltika.ru, ~66.16.172.in-addr.arpa, ~67.16.172.in-addr.arpa

Почему для /23 указаны две reverse-зоны. Сеть 172.16.66.0/23 включает две стандартные reverse-зоны: 66.16.172.in-addr.arpa для адресов 172.16.66.x и 67.16.172.in-addr.arpa для адресов 172.16.67.x. Обе route-only зоны нужны, чтобы файловый сервер мог разрешать PTR любого узла во всей /23.

Это не означает, что собственный IP SHARE должен иметь PTR в обеих зонах. Например, 172.16.66.229 имеет PTR только в 66.16.172.in-addr.arpa. Запись с owner 229 в зоне 67.16.172.in-addr.arpa означала бы другой адрес — 172.16.67.229.

Management-интерфейс ens19 не использует management-IP DNS-ВМ как DNS: BIND9 намеренно не слушает DNS на management-сети.

Фрагменты DNS-настроек в Netplan; существующие адреса и маршруты интерфейсов при этом сохраняются:

ens18:
  nameservers:
    addresses:
      - 192.168.1.1

ens20:
  nameservers:
    addresses:
      - 172.16.68.53
    search:
      - "~ot-samara.baltika.ru"
      - "~68.16.172.in-addr.arpa"
      - "~69.16.172.in-addr.arpa"

ens22:
  nameservers:
    addresses:
      - 172.16.70.53
    search:
      - "~ot-samara.baltika.ru"
      - "~70.16.172.in-addr.arpa"
      - "~71.16.172.in-addr.arpa"

ens23:
  nameservers:
    addresses:
      - 10.255.0.53
      - 172.16.66.53
    search:
      - "~ot-samara.baltika.ru"
      - "~255.10.in-addr.arpa"
      - "~66.16.172.in-addr.arpa"
      - "~67.16.172.in-addr.arpa"

enp2s1:
  nameservers:
    addresses:
      - 172.17.14.53
    search:
      - "~ot-samara.baltika.ru"
      - "~14.17.172.in-addr.arpa"

10.2. Применение и проверка DNS-маршрутизации

sudo netplan generate
sudo netplan try --timeout 120

resolvectl status

Подтверждённая маршрутизация:

  • 172.16.68.53 PTR — через ens20;
  • 172.16.70.53 PTR — через ens22;
  • 10.255.0.53 и 172.16.66.53 PTR — через ens23;
  • 172.17.14.53 PTR — через enp2s1;
  • прямая зона ot-samara.baltika.ru может обслуживаться любым равнозначным OT-link, поскольку все локальные BIND-адреса авторитетны для одной и той же зоны;
  • обычные внешние имена при текущей переходной конфигурации разрешаются через ens18 → 192.168.1.1, а не через OT BIND.

11. Ubuntu Server

Ubuntu Server 24.04.4 LTS установлен с OpenSSH. Hostname: smr-srv-ot-share. Временная сеть установки — 192.168.1.229/24.

12. Базовые пакеты

sudo apt install -y   ca-certificates curl nano openssl iputils-ping tcpdump arping   bash-completion lsof qemu-guest-agent systemd-timesyncd ufw   ethtool rsync acl attr btrfs-progs snapper

13. QEMU Guest Agent

sudo systemctl enable --now qemu-guest-agent
systemctl status qemu-guest-agent --no-pager

Сервис подтверждён как active (running).

14. Время

sudo timedatectl set-timezone Europe/Samara
sudo timedatectl set-local-rtc 0
sudo timedatectl set-ntp true

15. Запрет маршрутизации между OT-сегментами

net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

VM является многосетевым файловым сервером, но не маршрутизатором. Для reverse path filtering используется loose mode rp_filter=2.

16. Production MAIN-DATA в VM 103

Logical drive MAIN-DATA передан в VM по стабильному идентификатору /dev/disk/by-id/scsi-3600508b1001c2abf1f734aef851f07c9. Имена /dev/sdX не считаются постоянными.

qm set 103   -scsi2 /dev/disk/by-id/scsi-3600508b1001c2abf1f734aef851f07c9,cache=none,iothread=1,backup=0

16.1. Production Btrfs

Label MAIN-DATA
UUID 98e5188a-407c-4d4a-adc1-24d8c90afb32
Размер 5.46 TiB
Data single
Metadata/System DUP
Mount /srv/main-data
UUID=98e5188a-407c-4d4a-adc1-24d8c90afb32 /srv/main-data btrfs defaults,nofail,x-systemd.device-timeout=10s 0 0

17. Логическая структура MAIN-DATA

/srv/main-data
└── baltikashare
    ├── clonezilla
    ├── exchange
    ├── pivoproduction
    ├── rozliv
    ├── utilities
    ├── software
    ├── documentation
    └── ot-admin
Ресурс Назначение
clonezilla образы рабочих станций и технологических ПК
exchange общий обмен инженеров
pivoproduction рабочие данные пивопроизводства
rozliv рабочие данные розлива
utilities инженерные и энергетические системы
software дистрибутивы, драйверы, firmware, утилиты
documentation инструкции, схемы, ТЗ и паспорта
ot-admin административные OT-материалы

18. Snapper

Для каждого из 8 функциональных Btrfs subvolume создана отдельная Snapper-конфигурация: clonezilla, exchange, pivoproduction, rozliv, utilities, software, documentation, ot-admin.

BACKGROUND_COMPARISON=no
TIMELINE_CREATE=yes
TIMELINE_CLEANUP=yes
TIMELINE_MIN_AGE=1800
Ресурс Hourly Daily Weekly Monthly Yearly
clonezilla 24 30 12 12 1
exchange 24 7 2 0 0
pivoproduction 72 30 12 12 0
rozliv 72 30 12 12 0
utilities 72 30 12 12 0
software 0 14 8 6 0
documentation 72 60 26 24 3
ot-admin 72 90 26 24 5
systemctl is-active snapper-timeline.timer snapper-cleanup.timer

Оба таймера подтверждены как active.

19. Модель доступа: группы и POSIX ACL

19.1. Группы

Группа Назначение
admins полный доступ ко всем ресурсам
engineers exchange RW; software/documentation RO
clonezilla-rw RW clonezilla
pivoproduction-rw RW pivoproduction
rozliv-rw RW rozliv
utilities-rw RW utilities
software-rw RW software
documentation-rw RW documentation
shared-ro RO exchange, software, documentation
pivoproduction-ro RO pivoproduction
rozliv-ro RO rozliv
utilities-ro RO utilities

Создание RO-групп:

sudo groupadd shared-ro
sudo groupadd pivoproduction-ro
sudo groupadd rozliv-ro
sudo groupadd utilities-ro

getent group shared-ro
getent group pivoproduction-ro
getent group rozliv-ro
getent group utilities-ro

19.2. Матрица доступа

Ресурс admins engineers Профильная RW-группа Профильная RO-группа shared-ro
clonezilla RW DENY clonezilla-rw → RW — DENY
exchange RW RW — — RO
pivoproduction RW DENY pivoproduction-rw → RW pivoproduction-ro → RO DENY
rozliv RW DENY rozliv-rw → RW rozliv-ro → RO DENY
utilities RW DENY utilities-rw → RW utilities-ro → RO DENY
software RW RO software-rw → RW — RO
documentation RW RO documentation-rw → RW — RO
ot-admin RW DENY только admins — DENY

Для производственных учётных записей с правом записи используется составная RW-модель: пользователь одновременно входит в engineers и свою профильную группу *-rw.

Тип учётной записи Группы Итоговые права
Пивопроизводство — RW engineers + pivoproduction-rw pivoproduction RW; exchange RW; software RO; documentation RO
Розлив — RW engineers + rozliv-rw rozliv RW; exchange RW; software RO; documentation RO
Утилиты — RW engineers + utilities-rw utilities RW; exchange RW; software RO; documentation RO

Для пользователей только для чтения используется отдельная составная RO-модель: shared-ro + одна профильная группа *-ro.

Тип учётной записи Группы Итоговые права
Пивопроизводство — RO shared-ro + pivoproduction-ro pivoproduction RO; exchange RO; software RO; documentation RO; остальные профильные shares DENY
Розлив — RO shared-ro + rozliv-ro rozliv RO; exchange RO; software RO; documentation RO; остальные профильные shares DENY
Утилиты — RO shared-ro + utilities-ro utilities RO; exchange RO; software RO; documentation RO; остальные профильные shares DENY

Важно: RO-пользователей нельзя добавлять в engineers, профильные *-rw или admins, иначе они могут получить права записи. Доступ к clonezilla и ot-admin для RO-модели не предоставляется.

19.3. Универсальные учётные записи

Учётная запись Группы доступа
baltikashare admins
engineer engineers
clonezilla clonezilla-rw
pivo engineers + pivoproduction-rw
rozliv engineers + rozliv-rw
utilities engineers + utilities-rw
software software-rw
documents documentation-rw

Актуализация существующих производственных учётных записей:

sudo usermod -aG engineers pivo
sudo usermod -aG engineers rozliv
sudo usermod -aG engineers utilities

id pivo
id rozliv
id utilities

getent group engineers

После изменения групп на Windows-клиенте необходимо завершить старую SMB-сессию. Для этого используется проверенный change_share.bat из раздела 20.15, после чего выполняется новое подключение к SHARE.

19.3.1. Персонифицированные учётные записи

Помимо универсальных технологических учётных записей допускается создавать персонифицированные Samba-учётные записи для конкретных сотрудников. В документации реальные логины не фиксируются; ниже используются условные user1 и user2.

Права персональной учётной записи формируются теми же Linux-группами, что и права универсальной учётки соответствующего подразделения. Например, для прав Розлива:

engineers
rozliv-rw

Создание двух новых персональных учётных записей с правами Розлива:

sudo useradd -M -U -s /usr/sbin/nologin   -G engineers,rozliv-rw user1

sudo useradd -M -U -s /usr/sbin/nologin   -G engineers,rozliv-rw user2

id user1
id user2

sudo smbpasswd -a user1
sudo smbpasswd -a user2

sudo pdbedit -L | grep -E 'user1|user2'

Итоговые права для такого пользователя:

Share Доступ
rozliv RW
exchange RW
software RO
documentation RO
pivoproduction DENY
utilities DENY
clonezilla DENY
ot-admin DENY

Для другого подразделения меняется только профильная группа: pivoproduction-rw для Пивопроизводства или utilities-rw для Утилит. Членство в engineers сохраняется, если пользователю требуются exchange RW и software/documentation RO.

Важно: Samba-пользователь должен существовать как локальный Linux-пользователь. Пароль Samba задаётся отдельно через smbpasswd -a. Пароли в документации не хранятся.

19.3.2. Учётные записи только для чтения

Для производственных подразделений введены отдельные RO-роли. Пользователь состоит в shared-ro и в одной профильной *-ro группе. Такой пользователь может читать свой производственный каталог и общие ресурсы exchange, software, documentation, но не может создавать, изменять, переименовывать или удалять данные.

Учётная запись Группы Назначение
rozliv_read shared-ro + rozliv-ro RO Розлив + общие RO-ресурсы
pivo_read shared-ro + pivoproduction-ro RO Пивопроизводство + общие RO-ресурсы
utilities_read shared-ro + utilities-ro RO Утилиты + общие RO-ресурсы

Пример создания пользователя Розлива только для чтения:

sudo useradd -M -U -s /usr/sbin/nologin   -G shared-ro,rozliv-ro rozliv_read

id rozliv_read

sudo smbpasswd -a rozliv_read
sudo pdbedit -L | grep '^rozliv_read:'

Для Пивопроизводства:

sudo useradd -M -U -s /usr/sbin/nologin   -G shared-ro,pivoproduction-ro pivo_read

sudo smbpasswd -a pivo_read

Для Утилит:

sudo useradd -M -U -s /usr/sbin/nologin   -G shared-ro,utilities-ro utilities_read

sudo smbpasswd -a utilities_read

Пароли в документации не хранятся. После создания пользователя или изменения групп перед проверкой с Windows необходимо сбросить существующие SMB-сессии через change_share.bat.

19.4. POSIX ACL

Для профильного RW-ресурса используется следующая базовая модель:

user::rwx
group::rwx
group:admins:rwx
mask::rwx
other::---

default:user::rwx
default:group::rwx
default:group:admins:rwx
default:mask::rwx
default:other::---

Для software и documentation дополнительно задан RO для engineers:

group:engineers:r-x
default:group:engineers:r-x

19.4.1. POSIX ACL для read-only групп

Для RO-доступа используется r-X: чтение файлов и право прохода по каталогам без предоставления записи. Для новых объектов на каталогах задаётся такой же default ACL.

exchange       → shared-ro = r-x
software       → shared-ro = r-x
documentation  → shared-ro = r-x

pivoproduction → pivoproduction-ro = r-x
rozliv          → rozliv-ro = r-x
utilities       → utilities-ro = r-x

Важно: не использовать простой setfacl -R по корню share. В дереве находятся Snapper .snapshots и Samba .recycle. Попытка менять ACL внутри read-only Btrfs snapshots приводит к Operation not supported, а распространение RO-группы на .recycle раскроет служебные корзины. Production-команды ниже намеренно исключают оба каталога.

19.4.2. Общая группа shared-ro

for dir in exchange software documentation
do
    BASE="/srv/main-data/baltikashare/$dir"

    sudo find "$BASE"       -path "$BASE/.snapshots" -prune -o       -path "$BASE/.recycle" -prune -o       -exec setfacl -m g:shared-ro:r-X {} +

    sudo find "$BASE"       -path "$BASE/.snapshots" -prune -o       -path "$BASE/.recycle" -prune -o       -type d       -exec setfacl -m d:g:shared-ro:r-X {} +
done

Проверка:

getfacl -p /srv/main-data/baltikashare/exchange
getfacl -p /srv/main-data/baltikashare/software
getfacl -p /srv/main-data/baltikashare/documentation

В корне каждого ресурса должны присутствовать:

group:shared-ro:r-x
default:group:shared-ro:r-x

19.4.3. Профильные RO-группы

Розлив:

BASE="/srv/main-data/baltikashare/rozliv"

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -exec setfacl -m g:rozliv-ro:r-X {} +

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -type d   -exec setfacl -m d:g:rozliv-ro:r-X {} +

Пивопроизводство:

BASE="/srv/main-data/baltikashare/pivoproduction"

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -exec setfacl -m g:pivoproduction-ro:r-X {} +

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -type d   -exec setfacl -m d:g:pivoproduction-ro:r-X {} +

Утилиты:

BASE="/srv/main-data/baltikashare/utilities"

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -exec setfacl -m g:utilities-ro:r-X {} +

sudo find "$BASE"   -path "$BASE/.snapshots" -prune -o   -path "$BASE/.recycle" -prune -o   -type d   -exec setfacl -m d:g:utilities-ro:r-X {} +

Контроль корней:

getfacl -p /srv/main-data/baltikashare/rozliv
getfacl -p /srv/main-data/baltikashare/pivoproduction
getfacl -p /srv/main-data/baltikashare/utilities

Контроль отсутствия RO-групп в корзинах:

getfacl -p /srv/main-data/baltikashare/rozliv/.recycle | grep rozliv-ro
getfacl -p /srv/main-data/baltikashare/pivoproduction/.recycle | grep pivoproduction-ro
getfacl -p /srv/main-data/baltikashare/utilities/.recycle | grep utilities-ro

Правильный результат последних трёх команд — пустой вывод.

19.4.4. Очистка ошибочно добавленного shared-ro из .recycle

Если ранее был выполнен рекурсивный setfacl -R и shared-ro попал в служебные корзины, удалить только эту ACL-запись:

for dir in exchange software documentation
do
    REC="/srv/main-data/baltikashare/$dir/.recycle"

    if [ -d "$REC" ]; then
        sudo find "$REC" \( -type d -o -type f \)           -exec setfacl -n -x g:shared-ro {} +
    fi
done

Ключ -n запрещает автоматический пересчёт ACL mask; остальные настроенные права корзины не изменяются.

20. Samba — production-конфигурация

20.1. Состояние

Версия Samba 4.19.5-Ubuntu
Роль standalone server
NetBIOS name SMR-OT-SHARE
Security user
Минимальный протокол SMB2_02; SMB1 отключён
Конфигурация /etc/samba/smb.conf
Сервис smbd.service — active

Проверка конфигурации:

sudo testparm
sudo systemctl restart smbd
sudo systemctl is-active smbd
sudo smbstatus

20.2. Опубликованные shares

\\SMR-OT-SHARE\exchange
\\SMR-OT-SHARE\clonezilla
\\SMR-OT-SHARE\pivoproduction
\\SMR-OT-SHARE\rozliv
\\SMR-OT-SHARE\utilities
\\SMR-OT-SHARE\software
\\SMR-OT-SHARE\documentation
\\SMR-OT-SHARE\ot-admin

20.3. Исправление ACL-маски при создании файлов через SMB

Первоначальная комбинация inherit acls = yes + inherit permissions = yes привела к тому, что новый файл через SMB получил эффективную маску mask::r--. Именованная ACL для admins присутствовала, но фактическая запись была запрещена.

-rwxr-----+
user::rwx
group::rwx                      #effective:r--
group:admins:rwx                #effective:r--
mask::r--
other::---

Production-схема изменена: default ACL наследуются Linux/Btrfs, а Samba создаёт файлы и каталоги с фиксированной базовой маской:

create mask = 0660
force create mode = 0660
directory mask = 0770
force directory mode = 0770

inherit acls = no
inherit permissions = no

После исправления новый файл через SMB:

-rw-rw----+
user::rw-
group::rwx                      #effective:rw-
group:admins:rwx                #effective:rw-
mask::rw-
other::---

Контрольная запись от пользователя baltikashare через ACL группы admins выполнена успешно.

20.4. DOS/Windows attributes

Чтобы DOS Archive/Hidden/System не превращались в UNIX execute-биты, Windows-атрибуты хранятся в xattr:

store dos attributes = yes
map archive = no
map hidden = no
map system = no

20.5. Актуальный smb.conf

# ============================================================
# Samba configuration
# Server: SMR-SRV-OT-SHARE
# Role: standalone OT file server
# Data root: /srv/main-data/baltikashare
# ============================================================

[global]

   # Рабочая группа Windows.
   # Используется для standalone Samba без Active Directory.
   workgroup = WORKGROUP

   # Сервер работает автономно и не является контроллером домена.
   server role = standalone server

   # Аутентификация пользователей по логину и паролю.
   security = user

   # Локальная база Samba-пользователей.
   # В неё пользователи добавляются командой smbpasswd -a.
   passdb backend = tdbsam

   # Короткое NetBIOS-имя Samba-сервера.
   # Ограничение NetBIOS — максимум 15 символов.
   # Linux hostname при этом остаётся smr-srv-ot-share.
   netbios name = SMR-OT-SHARE

   # Описание сервера, которое могут видеть SMB-клиенты.
   server string = SMR OT File Server

   # Никогда не преобразовывать неизвестного пользователя в guest.
   map to guest = never

   # Запрещаем usershare и guest usershare.
   usershare max shares = 0
   usershare allow guests = no

   # Samba не используется как print server.
   load printers = no
   disable spoolss = yes
   printcap name = /dev/null

   # Минимально разрешённая версия SMB — SMB2.
   # SMB1/CIFS не разрешаем.
   server min protocol = SMB2_02

   # Логирование.
   log file = /var/log/samba/log.%m
   logging = file
   max log size = 1000

   # PAM.
   obey pam restrictions = yes
   unix password sync = no
   pam password change = no

   # =========================================================
   # Права создаваемых файлов и каталогов
   # =========================================================

   # Обычные файлы:
   # владелец = RW, группа = RW, остальные = NO ACCESS.
   create mask = 0660
   force create mode = 0660

   # Каталоги:
   # владелец = RWX, группа = RWX, остальные = NO ACCESS.
   directory mask = 0770
   force directory mode = 0770

   # Специальное наследование Samba не используем.
   # Default POSIX ACL наследуются файловой системой Linux.
   #
   # inherit permissions = yes переопределяет create/directory mask
   # и в данной схеме использоваться не должен.
   inherit acls = no
   inherit permissions = no

   # =========================================================
   # DOS / Windows attributes
   # =========================================================

   # DOS/Windows-атрибуты храним в extended attributes,
   # а не кодируем UNIX execute-битами.
   store dos attributes = yes
   map archive = no
   map hidden = no
   map system = no


# ============================================================
# EXCHANGE
# admins = RW
# engineers = RW
# shared-ro = RO
# ============================================================

[exchange]

   path = /srv/main-data/baltikashare/exchange
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins @engineers @shared-ro

   # shared-ro принудительно работает только на чтение.
   read list = @shared-ro

   # =========================================================
   # Служебные каталоги
   # =========================================================

   # Каталог Snapper полностью скрываем от обычного SMB-доступа.
   # Пользователь работает со snapshots через Windows
   # «Свойства» -> «Предыдущие версии».
   veto files = /.snapshots/

   # Сетевую корзину скрываем из обычного списка файлов,
   # но оставляем доступной по прямому SMB-пути.
   hide files = /.recycle/

   # Snapper = Windows Previous Versions.
   # Recycle = сетевая корзина Samba.
   vfs objects = snapper recycle

   # Для каждого SMB-пользователя создаётся отдельная корзина.
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# CLONEZILLA
# admins = RW
# clonezilla-rw = RW
# ============================================================

[clonezilla]

   path = /srv/main-data/baltikashare/clonezilla
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins @clonezilla-rw

   # =========================================================
   # Служебные каталоги
   # =========================================================

   # Каталог Snapper полностью скрываем от обычного SMB-доступа.
   # Previous Versions продолжает работать через vfs_snapper.
   veto files = /.snapshots/

   # Только Snapper.
   # vfs_recycle намеренно не включён: большие образы могут
   # одновременно удерживаться корзиной и Btrfs snapshots.
   vfs objects = snapper


# ============================================================
# PIVOPRODUCTION
# admins = RW
# pivoproduction-rw = RW
# pivoproduction-ro = RO
# ============================================================

[pivoproduction]

   path = /srv/main-data/baltikashare/pivoproduction
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins @pivoproduction-rw @pivoproduction-ro
   read list = @pivoproduction-ro

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# ROZLIV
# admins = RW
# rozliv-rw = RW
# rozliv-ro = RO
# ============================================================

[rozliv]

   path = /srv/main-data/baltikashare/rozliv
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins @rozliv-rw @rozliv-ro
   read list = @rozliv-ro

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# UTILITIES
# admins = RW
# utilities-rw = RW
# utilities-ro = RO
# ============================================================

[utilities]

   path = /srv/main-data/baltikashare/utilities
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins @utilities-rw @utilities-ro
   read list = @utilities-ro

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# SOFTWARE
# admins = RW
# software-rw = RW
# engineers = RO
# shared-ro = RO
# ============================================================

[software]

   path = /srv/main-data/baltikashare/software
   browseable = yes
   guest ok = no

   # По умолчанию только чтение.
   read only = yes
   valid users = @admins @engineers @software-rw @shared-ro

   # Запись только для admins и software-rw.
   # shared-ro намеренно отсутствует в write list.
   write list = @admins @software-rw

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# DOCUMENTATION
# admins = RW
# documentation-rw = RW
# engineers = RO
# shared-ro = RO
# ============================================================

[documentation]

   path = /srv/main-data/baltikashare/documentation
   browseable = yes
   guest ok = no

   # По умолчанию только чтение.
   read only = yes
   valid users = @admins @engineers @documentation-rw @shared-ro

   # Запись только для admins и documentation-rw.
   # shared-ro намеренно отсутствует в write list.
   write list = @admins @documentation-rw

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle


# ============================================================
# OT-ADMIN
# admins = RW
# Все остальные = NO ACCESS
# ============================================================

[ot-admin]

   path = /srv/main-data/baltikashare/ot-admin
   browseable = yes
   guest ok = no
   read only = no
   valid users = @admins

   # Служебные каталоги.
   veto files = /.snapshots/
   hide files = /.recycle/

   vfs objects = snapper recycle
   recycle:repository = .recycle/%U
   recycle:keeptree = yes
   recycle:versions = yes
   recycle:touch_mtime = yes
   recycle:directory_mode = 0770
   recycle:subdir_mode = 0770
   recycle:exclude_dir = .recycle

20.6. Проверка матрицы доступа через smbclient

Пользователь engineer проверен фактическими SMB-операциями:

Share Ожидаемо Факт
exchange RW OK: put/del
software RO OK: ls; put → ACCESS_DENIED
documentation RO OK: ls; put → ACCESS_DENIED
clonezilla DENY ACCESS_DENIED
pivoproduction DENY ACCESS_DENIED
rozliv DENY ACCESS_DENIED
utilities DENY ACCESS_DENIED
ot-admin DENY ACCESS_DENIED

Изначально производственные универсальные учётные записи входили только в свои профильные *-rw группы. В результате, например, пользователь rozliv имел RW к rozliv, но не мог открыть exchange, software и documentation.

После добавления pivo, rozliv и utilities в группу engineers применяется следующая целевая модель:

Тип пользователя Свой профильный share exchange software documentation Чужие профильные shares / ot-admin
Пивопроизводство RW RW RO RO DENY
Розлив RW RW RO RO DENY
Утилиты RW RW RO RO DENY

На Windows-клиенте модель проверена для пользователя Розлива после сброса старой SMB-сессии через change_share.bat: профильный ресурс доступен на чтение и запись, exchange — на чтение и запись, software/documentation — только на чтение. Для Пивопроизводства и Утилит права формируются тем же сочетанием engineers + профильная *-rw.

Специализированные учётные записи остаются без членства в engineers:

Учётка Share Результат
clonezilla clonezilla RW
software software RW
documents documentation RW

Администратор baltikashare имеет полный доступ ко всем восьми shares, включая software и documentation, где запись разрешена через write list.

20.6.1. Проверка read-only модели

После создания RO-групп и применения POSIX ACL конфигурация Samba проверена через testparm -s. В конфигурации подтверждены read list/valid users для профильных RO-групп и отсутствие shared-ro в write list ресурсов software и documentation.

После изменения /etc/samba/smb.conf выполнен sudo systemctl reload smbd. Сервис остался в состоянии active (running); reload завершён status=0/SUCCESS.

Для rozliv_read выполнена локальная проверка Linux/POSIX ACL:

Share READ WRITE
rozliv OK DENY
exchange OK DENY
software OK DENY
documentation OK DENY
pivoproduction DENY DENY
utilities DENY DENY
clonezilla DENY DENY
ot-admin DENY DENY

Учётные записи pivo_read и utilities_read созданы с группами shared-ro + pivoproduction-ro и shared-ro + utilities-ro соответственно. Окончательную проверку RO-ролей через Windows SMB выполнить после сброса старых сессий с помощью change_share.bat.

Шаблон локальной проверки:

sudo -u rozliv_read bash -c '
for dir in     rozliv     exchange     software     documentation     pivoproduction     utilities     clonezilla     ot-admin
do
    echo "===== $dir ====="

    test -r "/srv/main-data/baltikashare/$dir"       && echo "READ  : OK"       || echo "READ  : DENY"

    test -w "/srv/main-data/baltikashare/$dir"       && echo "WRITE : OK"       || echo "WRITE : DENY"
done
'

20.7. Samba recycle

vfs_recycle включён на: exchange, pivoproduction, rozliv, utilities, software, documentation, ot-admin.

Для clonezilla recycle намеренно отключён: крупные образы могут одновременно удерживаться корзиной и Btrfs snapshots, что создаёт риск чрезмерного расхода MAIN-DATA. Clonezilla защищается Snapper; критичные образы дополнительно должны копироваться на CRITICAL-BACKUP.

20.7.1. Структура корзины

.recycle/%U

Пример для Pivoproduction:

/srv/main-data/baltikashare/pivoproduction/.recycle/pivo/recycle-test-dir/recycle-test.txt

Проверенный файл в корзине сохранил корректные ACL:

-rw-rw----+  pivo pivoproduction-rw

user::rw-
group::rwx                      #effective:rw-
group:admins:rwx                #effective:rw-
mask::rw-
other::---

20.7.1.1. Production ACL для корзин

Изначально recycle:directory_mode = 0700 и recycle:subdir_mode = 0700 приводили к созданию каталогов с ACL group:admins:rwx, но с mask::---. В результате группа admins фактически не имела доступа, и сервисный пользователь filebrowser не мог открыть большинство каталогов .recycle.

Для всех shares с vfs_recycle используется:

recycle:directory_mode = 0770
recycle:subdir_mode = 0770

Корень .recycle имеет следующую модель:

user::rwx
group::rwx
group:admins:rwx
mask::rwx
other::---

default:user::rwx
default:group::---
default:group:admins:rwx
default:mask::rwx
default:other::---

На корне .recycle установлен sticky bit. Типовой режим отображается как drwxrws--T+. Основная группа ресурса может войти в корень и создать свой .recycle/%U, но sticky bit не позволяет пользователю удалить чужой каталог верхнего уровня.

Персональный каталог .recycle/<user> имеет более строгую модель:

user::rwx
group::---
group:admins:rwx
mask::rwx
other::---

default:user::rwx
default:group::---
default:group:admins:rwx
default:mask::rwx
default:other::---

Таким образом, владелец видит собственную корзину, группа admins получает полный административный доступ, а остальные участники профильной группы ресурса не получают доступ к содержимому чужой корзины. Для software и documentation ACL engineers внутри .recycle удалены, чтобы RO-доступ к рабочим данным не распространялся на удалённые файлы.

Для ot-admin отдельная именованная запись group:admins не требуется, поскольку admins является основной группой каталога.

Схема проверена не только на существующих каталогах: .recycle/pivo был полностью удалён, после чего Samba повторно создала его при удалении файла. Новый каталог автоматически получил правильные default ACL, а filebrowser сохранил доступ к содержимому.

20.7.2. Сохранение структуры

recycle:keeptree = yes проверен удалением файла из вложенного каталога: исходная структура каталога появилась внутри персональной корзины.

20.7.3. Несколько версий

recycle:versions = yes проверен двойным удалением файла с одинаковым именем. В корзине появились:

version-test.txt
Copy #1 of version-test.txt

20.7.4. Удаление из самой корзины

recycle:exclude_dir = .recycle проверен удалением файла непосредственно из .recycle через SMB. Файл исчез окончательно и не был повторно перемещён во вложенную корзину.

20.7.5. Скрытие служебных каталогов

Для рабочих shares каталог Snapper полностью исключён из обычного SMB-просмотра, а Samba-корзина помечена как скрытая:

veto files = /.snapshots/
hide files = /.recycle/

veto files делает .snapshots недоступным по обычному SMB-пути, но не мешает vfs_snapper публиковать snapshots через Windows «Предыдущие версии». hide files присваивает .recycle атрибут Hidden; при необходимости корзину можно открыть напрямую, например \\SMR-OT-SHARE\exchange\.recycle.

На clonezilla используется только veto files = /.snapshots/, так как vfs_recycle для этого ресурса отключён.

20.8. Snapper и Windows «Предыдущие версии»

Цепочка Btrfs snapshot → Snapper → vfs_snapper → Samba → Windows Previous Versions проверена на реальном Windows-клиенте.

20.8.1. Контрольный тест

Для exchange были созданы две ручные точки Snapper с разными версиями одного файла, после чего текущая версия файла была изменена ещё раз. Windows отобразил обе сохранённые версии в свойствах файла и позволил восстановить более раннюю версию. После восстановления содержимое файла фактически вернулось к исходному варианту.

Отдельный тест выполнен на documentation: snapshot появился в «Свойства → Предыдущие версии», его содержимое успешно открывалось из Windows. Это подтвердило работу настройки не только на exchange, но и после её распространения на остальные shares.

20.8.2. Проверка автоматических timeline snapshots

Snapper создаёт timeline snapshots ежечасно. Контрольный вывод для exchange 28.10.2026 показывал последовательные snapshots с 05:00 до 14:00. Если Windows Explorer не сразу показывает последние точки, достаточно повторно открыть каталог или окно свойств: серверные snapshots при этом продолжают создаваться корректно.

20.9. Автоматическая очистка Samba recycle

Так как одновременно используется Snapper, корзина Samba предназначена для быстрого возврата случайно удалённых файлов и не должна хранить данные месяцами без ограничения. Для каждого ресурса задан отдельный срок хранения.

Ресурс Срок хранения .recycle
exchange 7 дней
pivoproduction 14 дней
rozliv 14 дней
utilities 14 дней
software 14 дней
documentation 30 дней
ot-admin 30 дней
clonezilla recycle отключён

В smb.conf используется recycle:touch_mtime = yes, поэтому при перемещении файла в корзину обновляется его mtime, и очистка может ориентироваться на время удаления через Samba.

20.9.1. Скрипт /usr/local/sbin/samba-recycle-cleanup

#!/usr/bin/env bash

# ============================================================
# Samba recycle cleanup
# Server: SMR-SRV-OT-SHARE
#
# Автоматическая очистка файлов из Samba .recycle
# по времени их нахождения в корзине.
#
# Режимы:
#   --dry-run  только показать, что было бы удалено
#   --delete   реально удалить просроченные файлы
# ============================================================

set -u
set -o pipefail

BASE="/srv/main-data/baltikashare"
MODE="${1:---dry-run}"

case "$MODE" in
    --dry-run)
        DELETE=false
        ;;
    --delete)
        DELETE=true
        ;;
    *)
        echo "Usage: $0 [--dry-run|--delete]"
        exit 2
        ;;
esac

# Не допускаем работу по каталогу на root FS,
# если production MAIN-DATA не смонтирован.
if ! mountpoint -q /srv/main-data; then
    echo "ERROR: /srv/main-data is not mounted."
    echo "Cleanup aborted."
    exit 1
fi

FS_TYPE="$(findmnt -n -o FSTYPE /srv/main-data 2>/dev/null || true)"
if [[ "$FS_TYPE" != "btrfs" ]]; then
    echo "ERROR: /srv/main-data filesystem is '$FS_TYPE', expected 'btrfs'."
    echo "Cleanup aborted."
    exit 1
fi

POLICY=(
    "exchange:7"
    "pivoproduction:14"
    "rozliv:14"
    "utilities:14"
    "software:14"
    "documentation:30"
    "ot-admin:30"
)

echo "============================================================"
echo "Samba recycle cleanup"
echo "Date: $(date '+%Y-%m-%d %H:%M:%S %z')"
echo "Mode: $MODE"
echo "============================================================"

TOTAL_FILES=0
TOTAL_BYTES=0

for ITEM in "${POLICY[@]}"; do
    SHARE="${ITEM%%:*}"
    DAYS="${ITEM##*:}"
    RECYCLE="${BASE}/${SHARE}/.recycle"

    echo
    echo "------------------------------------------------------------"
    echo "Share:     $SHARE"
    echo "Recycle:   $RECYCLE"
    echo "Retention: $DAYS days"
    echo "------------------------------------------------------------"

    if [[ ! -d "$RECYCLE" ]]; then
        echo "INFO: recycle directory does not exist, skipping."
        continue
    fi

    AGE_MINUTES=$((DAYS * 24 * 60))

    while IFS= read -r -d '' FILE; do
        SIZE="$(stat -c '%s' "$FILE" 2>/dev/null || echo 0)"
        TOTAL_FILES=$((TOTAL_FILES + 1))
        TOTAL_BYTES=$((TOTAL_BYTES + SIZE))

        if [[ "$DELETE" == true ]]; then
            echo "DELETE: $FILE"
            rm -f -- "$FILE"
        else
            echo "WOULD DELETE: $FILE"
        fi
    done < <(
        find "$RECYCLE" \
            -xdev \
            -type f \
            -mmin "+${AGE_MINUTES}" \
            -print0
    )

    if [[ "$DELETE" == true ]]; then
        find "$RECYCLE" \
            -xdev \
            -depth \
            -mindepth 1 \
            -type d \
            -empty \
            -delete
    fi
done

echo
echo "============================================================"
echo "Summary"
echo "============================================================"
echo "Matched files: $TOTAL_FILES"
echo "Matched bytes: $TOTAL_BYTES"

if command -v numfmt >/dev/null 2>&1; then
    echo "Matched size:  $(numfmt --to=iec-i --suffix=B "$TOTAL_BYTES")"
fi

if [[ "$DELETE" == true ]]; then
    echo "Result: expired files deleted."
else
    echo "Result: DRY-RUN only. Nothing was deleted."
fi

echo "Finished: $(date '+%Y-%m-%d %H:%M:%S %z')"

Права и контроль синтаксиса:

sudo chmod 0755 /usr/local/sbin/samba-recycle-cleanup
sudo bash -n /usr/local/sbin/samba-recycle-cleanup

20.9.2. Проверка dry-run и удаления

Сначала скрипт был запущен с --dry-run: при отсутствии просроченных файлов он вернул Matched files: 0. Затем в корзине exchange был создан искусственно состаренный на 8 дней файл. Dry-run обнаружил его как WOULD DELETE, но не удалил. Запуск с --delete удалил только этот файл и вернул успешный результат.

20.9.3. systemd service

/etc/systemd/system/samba-recycle-cleanup.service:

[Unit]
Description=Cleanup expired Samba recycle files
Documentation=man:find(1)
RequiresMountsFor=/srv/main-data

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/samba-recycle-cleanup --delete
PrivateTmp=yes
NoNewPrivileges=yes
StandardOutput=journal
StandardError=journal

20.9.4. systemd timer

/etc/systemd/system/samba-recycle-cleanup.timer:

[Unit]
Description=Daily Samba recycle cleanup

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=10m
Unit=samba-recycle-cleanup.service

[Install]
WantedBy=timers.target

Активация:

sudo systemctl daemon-reload
sudo systemctl enable --now samba-recycle-cleanup.timer

systemctl status samba-recycle-cleanup.timer --no-pager
systemctl list-timers samba-recycle-cleanup.timer --all

sudo journalctl \
  -u samba-recycle-cleanup.service \
  -n 100 \
  --no-pager

Контрольный статус: timer active (waiting). После включения 28.10.2026 следующий запуск был назначен на 29.10.2026 03:36:04 +04, что соответствует 03:30 плюс RandomizedDelaySec=10m.

20.10. Защита smbd от запуска без MAIN-DATA

Если D2700 или MAIN-DATA недоступны, каталог /srv/main-data всё равно может существовать на системном root filesystem. Без дополнительной защиты Samba могла бы запуститься и начать принимать данные в этот обычный каталог, заполняя системный диск.

Для smbd.service создан systemd drop-in: /etc/systemd/system/smbd.service.d/main-data.conf.

# ============================================================
# SMR-SRV-OT-SHARE
# Защита Samba от запуска без MAIN-DATA
#
# Не позволять smbd стартовать, если production-хранилище
# /srv/main-data не смонтировано.
# ============================================================

[Unit]

# systemd должен поднять все mount units, необходимые
# для доступа к /srv/main-data, до запуска smbd.
RequiresMountsFor=/srv/main-data


[Service]

# /srv/main-data должен быть именно mountpoint.
# Если MAIN-DATA не смонтирован, ExecStartPre завершится
# неуспешно и smbd не запустится.
ExecStartPre=/usr/bin/mountpoint -q /srv/main-data

Применение и проверка:

sudo systemctl daemon-reload
sudo systemctl cat smbd

mountpoint /srv/main-data
findmnt /srv/main-data

sudo systemctl restart smbd
sudo systemctl status smbd --no-pager

Фактически подтверждено:

/srv/main-data is a mountpoint

TARGET         SOURCE    FSTYPE OPTIONS
/srv/main-data /dev/sdb1 btrfs  rw,relatime,space_cache=v2,subvolid=5,subvol=/

ExecStartPre=/usr/bin/mountpoint -q /srv/main-data
(code=exited, status=0/SUCCESS)

Status: "smbd: ready to serve connections..."

Проверка UUID в ExecStartPre намеренно не добавлялась: для текущей схемы принято оставить защиту простой — systemd dependency плюс проверка факта монтирования.

20.11. NFS

NFS на текущем этапе не установлен и не публикуется. Решение отложено до появления реальной необходимости со стороны Clonezilla или другого клиента. При последующем внедрении необходимо отдельно определить разрешённые сети/клиенты, UID/GID-модель и root squashing.

20.12. Access Based Enumeration

Access Based Enumeration намеренно не включается. Недоступные SMB shares могут отображаться в списке ресурсов сервера, но попытка подключения к ним блокируется через valid users и файловые ACL. Для текущей эксплуатации такое поведение принято как штатное.

20.13. File Browser Next — административный web-доступ

Для административного web-доступа к MAIN-DATA установлен File Browser Next v3.0.0-next. Сервис предназначен для работы из management-сети и не заменяет SMB. Через web-интерфейс администратор видит все восемь функциональных каталогов, включая служебные .snapshots и .recycle.

Для web-интерфейса намеренно не включается скрытие dot-files: административная задача File Browser включает просмотр и обслуживание .snapshots и .recycle.

20.13.1. Версия и бинарный файл

File Browser Next v3.0.0-next
/usr/local/bin/filebrowser

Проверенная SHA-256 загруженного архива filebrowser-linux-amd64.tar.gz:

17a51c2b8fe2eaf88ca4f7a80bd2f2b2e7fe968961bbeb8569a86942696e08b0

20.13.2. Системная учётная запись

user: filebrowser
shell: /usr/sbin/nologin
supplementary group: admins

Сервис не запускается от root. Доступ к файловым ресурсам он получает через существующую POSIX ACL-модель и членство в admins.

id filebrowser
# uid=999(filebrowser) gid=987(filebrowser) groups=987(filebrowser),1001(admins)

20.13.3. Каталоги и база

/etc/filebrowser                  root:root             0755
/var/lib/filebrowser              filebrowser:filebrowser 0750
/var/lib/filebrowser/filebrowser.db

Основные параметры хранятся в BoltDB. Отдельный конфигурационный файл на текущем этапе не используется.

20.13.4. Основные параметры File Browser

Параметр Значение
Root /srv/main-data/baltikashare
Management address 10.44.100.229
TCP port 28443
Authentication json
Locale ru
File mode 0660
Directory mode 0770
Minimum password length 12
Execute disabled
Share disabled
External symlinks disabled
Hide dotfiles false

Первичная проверка выполнялась на 127.0.0.1:28443. После локальной проверки сервис предназначен для bind только на management-адрес 10.44.100.229:28443, а не на 0.0.0.0.

20.13.5. Web-учётная запись

login: baltikafile
scope: /
admin: true
execute: false
share: false

Пароль в документации не хранится.

20.13.6. systemd unit

Файл: /etc/systemd/system/filebrowser.service

# ============================================================
# SMR-SRV-OT-SHARE
# File Browser Next
#
# Web-доступ к данным MAIN-DATA.
# Сервис работает от отдельной системной учётной записи
# filebrowser и получает права через группу admins / POSIX ACL.
# ============================================================

[Unit]
Description=File Browser Next
After=network.target
RequiresMountsFor=/srv/main-data

[Service]
Type=simple
User=filebrowser
Group=filebrowser
SupplementaryGroups=admins
WorkingDirectory=/var/lib/filebrowser

# Не допускаем запуск на пустом каталоге /srv/main-data,
# если production Btrfs по какой-либо причине не смонтирован.
ExecStartPre=/usr/bin/mountpoint -q /srv/main-data

ExecStart=/usr/local/bin/filebrowser \
    -d /var/lib/filebrowser/filebrowser.db

Restart=on-failure
RestartSec=5s
NoNewPrivileges=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Проверка:

sudo systemctl daemon-reload
sudo systemctl start filebrowser
sudo systemctl status filebrowser --no-pager
sudo ss -ltnp | grep ':28443'
curl -s -o /dev/null -w '%{http_code}\n' http://10.44.100.229:28443/

Ожидаемый HTTP-код: 200.

После окончательной проверки для включения автозапуска:

sudo systemctl enable filebrowser
systemctl is-enabled filebrowser
systemctl is-active filebrowser

20.13.7. Проверенные права

От имени Linux-пользователя filebrowser проверены чтение и запись в рабочий ресурс, доступ ко всем восьми верхнеуровневым каталогам и административный проход в .recycle. Для корзин итоговая проверка дала ACCESS OK на всех семи ресурсах, где используется vfs_recycle.

Удаление файлов через File Browser выполняется непосредственно на файловой системе и не проходит через Samba vfs_recycle. Основной механизм защиты от ошибочных административных изменений в этом случае — Btrfs/Snapper snapshots.

20.13.8. Ограничение management-сети

Management-интерфейс VM: ens19 = 10.44.100.229/24, gateway 10.44.100.1. Целевая модель — публиковать на этом интерфейсе только необходимые административные web-сервисы, в первую очередь File Browser на 28443/tcp. Ограничение firewall выполняется отдельным этапом после инвентаризации текущих слушающих портов, чтобы не потерять административный доступ.

20.14. DNS-имена и DDNS многосетевого файлового сервера

Центральная конфигурация BIND9 описана в отдельной статье «Установка DNS сервера BIND9 на Ubuntu Server 24.04 с Webmin в Proxmox». Здесь фиксируется только конфигурация самого SMR-SRV-OT-SHARE и правила его использования клиентами.

20.14.1. Модель имён

Один multi-homed сервер не публикуется одной A-записью со всеми интерфейсами. Каждый OT-интерфейс получает собственный сегментный FQDN:

Сегмент IP FQDN
Legacy 10.255.0.229 smr-srv-ot-share.legacy.ot-samara.baltika.ru
Пивопроизводство 172.16.66.229 smr-srv-ot-share.pivo.ot-samara.baltika.ru
Розлив 172.16.68.229 smr-srv-ot-share.rozliv.ot-samara.baltika.ru
Утилиты 172.16.70.229 smr-srv-ot-share.utilities.ot-samara.baltika.ru
АСТУЭ 172.17.14.229 smr-srv-ot-share.astue.ot-samara.baltika.ru

PTR каждого адреса указывает на соответствующий сегментный FQDN.

20.14.2. Как клиенты используют короткое имя

На самом SHARE добавление suffix не заставляет удалённые компьютеры использовать его. DNS suffix search list задаётся на клиенте, который выполняет запрос.

Для обычного одноинтерфейсного Windows-клиента основной connection-specific suffix остаётся ot-samara.baltika.ru, а глобальный список поиска содержит два элемента:

Сегмент клиента 1-й suffix 2-й suffix
Legacy legacy.ot-samara.baltika.ru ot-samara.baltika.ru
Pivo pivo.ot-samara.baltika.ru ot-samara.baltika.ru
Rozliv rozliv.ot-samara.baltika.ru ot-samara.baltika.ru
Utilities utilities.ot-samara.baltika.ru ot-samara.baltika.ru
АСТУЭ astue.ot-samara.baltika.ru ot-samara.baltika.ru

Например, клиент Розлива при обращении к \\SMR-SRV-OT-SHARE\exchange сначала проверит SMR-SRV-OT-SHARE.rozliv.ot-samara.baltika.ru и получит 172.16.68.229.

Не добавлять на обычный клиент suffix всех сегментов. Первым должен быть только suffix его локального сегмента, вторым — общая зона.

20.14.3. Установка DNS-утилит

sudo apt update
sudo apt install -y dnsutils

command -v nsupdate
command -v dig

20.14.4. Скрипт /usr/local/sbin/ot-ddns-register

sudo tee /usr/local/sbin/ot-ddns-register >/dev/null <<'SCRIPT_EOF'
#!/usr/bin/env bash

# ============================================================
# SMR-SRV-OT-SHARE
# Регистрация интерфейсных DNS-имён многосетевого сервера
# в авторитетном BIND9 через RFC 2136 / nsupdate.
# ============================================================

set -euo pipefail

TTL=3600
ZONE="ot-samara.baltika.ru."

register_dns()
{
    local iface="$1"
    local ip="$2"
    local dns="$3"
    local fqdn="$4"
    local ptr="$5"

    echo
    echo "============================================================"
    echo "Interface : $iface"
    echo "IP        : $ip"
    echo "DNS       : $dns"
    echo "FQDN      : $fqdn"
    echo "============================================================"

    if ! ip -4 addr show dev "$iface" | grep -qw "$ip"; then
        echo "ERROR: IP $ip отсутствует на интерфейсе $iface"
        return 1
    fi

    route_info="$(ip route get "$dns" | head -n1)"
    echo "Route     : $route_info"

    if ! grep -qw "src $ip" <<< "$route_info"; then
        echo "ERROR: запрос к $dns пойдёт не с source IP $ip"
        return 1
    fi

    nsupdate <<EOF
server $dns
zone $ZONE
update delete $fqdn A
update add $fqdn $TTL A $ip
send
EOF

    nsupdate <<EOF
server $dns
update delete $ptr PTR
update add $ptr $TTL PTR $fqdn
send
EOF

    result_a="$(dig +short +norecurse @"$dns" "$fqdn" A | head -n1)"

    if [[ "$result_a" != "$ip" ]]; then
        echo "ERROR: A verification failed: '$result_a'"
        return 1
    fi

    result_ptr="$(dig +short +norecurse @"$dns" -x "$ip" | head -n1)"

    if [[ "$result_ptr" != "$fqdn" ]]; then
        echo "ERROR: PTR verification failed: '$result_ptr'"
        return 1
    fi

    echo "OK: A   $fqdn -> $ip"
    echo "OK: PTR $ip -> $fqdn"
}

# Legacy OT / VLAN 1.
register_dns \
    "ens23" \
    "10.255.0.229" \
    "10.255.0.53" \
    "smr-srv-ot-share.legacy.ot-samara.baltika.ru." \
    "229.0.255.10.in-addr.arpa."

# Пивопроизводство. Пока 172.16.66.229 находится на ens23.
# После миграции VLAN2030 заменить ens23 на ens21.
register_dns \
    "ens23" \
    "172.16.66.229" \
    "172.16.66.53" \
    "smr-srv-ot-share.pivo.ot-samara.baltika.ru." \
    "229.66.16.172.in-addr.arpa."

# Розлив / VLAN2002.
register_dns \
    "ens20" \
    "172.16.68.229" \
    "172.16.68.53" \
    "smr-srv-ot-share.rozliv.ot-samara.baltika.ru." \
    "229.68.16.172.in-addr.arpa."

# Утилиты / VLAN2040.
register_dns \
    "ens22" \
    "172.16.70.229" \
    "172.16.70.53" \
    "smr-srv-ot-share.utilities.ot-samara.baltika.ru." \
    "229.70.16.172.in-addr.arpa."

# АСТУЭ / VLAN2006.
register_dns \
    "enp2s1" \
    "172.17.14.229" \
    "172.17.14.53" \
    "smr-srv-ot-share.astue.ot-samara.baltika.ru." \
    "229.14.17.172.in-addr.arpa."

echo
echo "============================================================"
echo "OT DDNS registration completed successfully."
echo "============================================================"
SCRIPT_EOF

sudo chown root:root /usr/local/sbin/ot-ddns-register
sudo chmod 0755 /usr/local/sbin/ot-ddns-register

Перед включением автозапуска скрипт проверяется вручную:

sudo /usr/local/sbin/ot-ddns-register

Успешный результат содержит по всем пяти интерфейсам строки OK: A и OK: PTR.

20.14.5. systemd unit

sudo tee /etc/systemd/system/ot-ddns-register.service >/dev/null <<'UNIT_EOF'
[Unit]
Description=Register SMR-SRV-OT-SHARE DNS records in OT BIND9
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/ot-ddns-register

[Install]
WantedBy=multi-user.target
UNIT_EOF

sudo chown root:root /etc/systemd/system/ot-ddns-register.service
sudo chmod 0644 /etc/systemd/system/ot-ddns-register.service

sudo systemctl daemon-reload
sudo systemctl enable ot-ddns-register.service
sudo systemctl start ot-ddns-register.service
sudo systemctl status ot-ddns-register.service --no-pager
sudo journalctl -u ot-ddns-register.service -n 100 --no-pager

Для Type=oneshot состояние inactive (dead) после выполнения является нормальным. Критерий успеха: code=exited, status=0/SUCCESS и успешные проверки A/PTR.

20.14.6. Фактически зарегистрированные A/PTR

FQDN A PTR
smr-srv-ot-share.legacy.ot-samara.baltika.ru 10.255.0.229 на это же FQDN
smr-srv-ot-share.pivo.ot-samara.baltika.ru 172.16.66.229 на это же FQDN
smr-srv-ot-share.rozliv.ot-samara.baltika.ru 172.16.68.229 на это же FQDN
smr-srv-ot-share.utilities.ot-samara.baltika.ru 172.16.70.229 на это же FQDN
smr-srv-ot-share.astue.ot-samara.baltika.ru 172.17.14.229 на это же FQDN

PTR для сетей /23. У SHARE адреса Пивопроизводства, Розлива и Утилит находятся в первых половинах соответствующих /23: 172.16.66.229, 172.16.68.229 и 172.16.70.229. Поэтому их PTR находятся соответственно только в reverse-зонах 66.16.172.in-addr.arpa, 68.16.172.in-addr.arpa и 70.16.172.in-addr.arpa.

Парные зоны 67.16.172.in-addr.arpa, 69.16.172.in-addr.arpa и 71.16.172.in-addr.arpa существуют и обслуживаются тем же BIND9, но используются для узлов с адресами 172.16.67.x, 172.16.69.x и 172.16.71.x. Дублировать в них PTR адресов SHARE нельзя.

05.11.2026 ручной запуск и запуск через systemd завершились успешно для всех пяти пар A/PTR.

20.14.7. Миграция Пивопроизводства на VLAN2030

При переносе 172.16.66.229/23 с ens23 на ens21 одновременно:

  • перенести IP в Netplan; один IP не должен одновременно присутствовать на двух интерфейсах;
  • перенести DNS 172.16.66.53 и route-only domains ~ot-samara.baltika.ru, ~66.16.172.in-addr.arpa и ~67.16.172.in-addr.arpa на ens21; на ens23 оставить только Legacy DNS/домены;
  • в /usr/local/sbin/ot-ddns-register для Pivo заменить ens23 на ens21;
  • запустить sudo systemctl start ot-ddns-register.service и проверить журнал.

20.15. Переключение Samba-учётной записи на Windows-клиенте

Windows не позволяет одновременно использовать разные наборы SMB-учётных данных для одного и того же сервера в рамках одной пользовательской сессии. Типичный сценарий: пользователь сначала открыл \\SMR-SRV-OT-SHARE\clonezilla под clonezilla, а затем попытался открыть ot-admin под baltikashare. Windows может вернуть ошибку о невозможности множественных подключений к одному серверу с использованием разных имён пользователя.

Закрытие окна Проводника не гарантирует немедленного завершения SMB-сессии: могут оставаться mapping, скрытое соединение IPC$ и сохранённые Windows credentials. Для штатного переключения пользователя используется проверенный клиентский BAT change_share.bat.

Назначение BAT: отключить только SMB-подключения к SMR-SRV-OT-SHARE независимо от того, через какой его IP, короткое имя или сегментный FQDN было открыто подключение. Другие сетевые серверы и сетевые диски не затрагиваются.

20.15.1. Какие адреса и имена учитывает скрипт

Тип Значения
Сервисные и management IP 192.168.1.229
10.44.100.229
10.255.0.229
172.16.66.229
172.16.68.229
172.16.70.229
172.17.14.229
Короткие имена SMR-SRV-OT-SHARE
SMR-OT-SHARE
Сегментные FQDN smr-srv-ot-share.legacy.ot-samara.baltika.ru
smr-srv-ot-share.pivo.ot-samara.baltika.ru
smr-srv-ot-share.rozliv.ot-samara.baltika.ru
smr-srv-ot-share.utilities.ot-samara.baltika.ru
smr-srv-ot-share.astue.ot-samara.baltika.ru

20.15.2. Какие SMB-ресурсы очищаются

Скрипт учитывает все восемь опубликованных shares:

exchange
clonezilla
pivoproduction
rozliv
utilities
software
documentation
ot-admin

Дополнительно удаляется скрытое соединение IPC$, поскольку оно может сохранять старый SMB-контекст даже после закрытия окон Проводника.

20.15.3. Пользовательские учётные записи

Учётная запись Основное назначение
baltikashare административный доступ, включая ot-admin и остальные ресурсы
engineer RW exchange; RO software и documentation
clonezilla RW clonezilla
pivo RW pivoproduction
rozliv RW rozliv
utilities RW utilities
software RW software
documents RW documentation
rozliv_read RO rozliv + RO exchange/software/documentation
pivo_read RO pivoproduction + RO exchange/software/documentation
utilities_read RO utilities + RO exchange/software/documentation

BAT не хранит пароли и не выбирает новую учётную запись автоматически. Он только удаляет текущие SMB-подключения и сохранённые credentials, относящиеся к SHARE. После этого пользователь заново открывает нужный ресурс и вводит требуемый логин/пароль.

20.15.4. Полный проверенный BAT change_share.bat

@echo off
chcp 65001 >nul
title Смена пользователя SMR-SRV-OT-SHARE

echo ============================================================
echo   SMR-SRV-OT-SHARE - отключение текущих SMB-сессий
echo ============================================================
echo.
echo Будут отключены ТОЛЬКО подключения к файловому серверу SHARE.
echo Подключения к другим серверам и сетевым ресурсам не трогаются.
echo.

powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^
  "$targets = @(" ^
  "'192.168.1.229'," ^
  "'10.44.100.229'," ^
  "'10.255.0.229'," ^
  "'172.16.66.229'," ^
  "'172.16.68.229'," ^
  "'172.16.70.229'," ^
  "'172.17.14.229'," ^
  "'SMR-SRV-OT-SHARE'," ^
  "'SMR-OT-SHARE'," ^
  "'smr-srv-ot-share.legacy.ot-samara.baltika.ru'," ^
  "'smr-srv-ot-share.pivo.ot-samara.baltika.ru'," ^
  "'smr-srv-ot-share.rozliv.ot-samara.baltika.ru'," ^
  "'smr-srv-ot-share.utilities.ot-samara.baltika.ru'," ^
  "'smr-srv-ot-share.astue.ot-samara.baltika.ru'" ^
  ");" ^
  "$mappings = Get-SmbMapping -ErrorAction SilentlyContinue | Where-Object {" ^
  "  $remote = $_.RemotePath;" ^
  "  $targets | Where-Object { $remote -like ('\\' + $_ + '\*') }" ^
  "};" ^
  "if ($mappings) {" ^
  "  $mappings | Sort-Object RemotePath -Unique | ForEach-Object {" ^
  "    Write-Host ('Отключение: ' + $_.RemotePath);" ^
  "    Remove-SmbMapping -RemotePath $_.RemotePath -Force -UpdateProfile -ErrorAction SilentlyContinue" ^
  "  }" ^
  "} else {" ^
  "  Write-Host 'Явных SMB mappings к SHARE не найдено.'" ^
  "}"

echo.
echo Очистка скрытых IPC$ и известных SMB-ресурсов...
echo.

for %%S in (
    192.168.1.229
    10.44.100.229
    10.255.0.229
    172.16.66.229
    172.16.68.229
    172.16.70.229
    172.17.14.229
    SMR-SRV-OT-SHARE
    SMR-OT-SHARE
    smr-srv-ot-share.legacy.ot-samara.baltika.ru
    smr-srv-ot-share.pivo.ot-samara.baltika.ru
    smr-srv-ot-share.rozliv.ot-samara.baltika.ru
    smr-srv-ot-share.utilities.ot-samara.baltika.ru
    smr-srv-ot-share.astue.ot-samara.baltika.ru
) do (
    net use \\%%S\IPC$ /delete /y >nul 2>&1
    net use \\%%S\exchange /delete /y >nul 2>&1
    net use \\%%S\clonezilla /delete /y >nul 2>&1
    net use \\%%S\pivoproduction /delete /y >nul 2>&1
    net use \\%%S\rozliv /delete /y >nul 2>&1
    net use \\%%S\utilities /delete /y >nul 2>&1
    net use \\%%S\software /delete /y >nul 2>&1
    net use \\%%S\documentation /delete /y >nul 2>&1
    net use \\%%S\ot-admin /delete /y >nul 2>&1
)

echo.
echo Удаление сохраненных учетных данных SHARE...
echo.

for %%S in (
    192.168.1.229
    10.44.100.229
    10.255.0.229
    172.16.66.229
    172.16.68.229
    172.16.70.229
    172.17.14.229
    SMR-SRV-OT-SHARE
    SMR-OT-SHARE
    smr-srv-ot-share.legacy.ot-samara.baltika.ru
    smr-srv-ot-share.pivo.ot-samara.baltika.ru
    smr-srv-ot-share.rozliv.ot-samara.baltika.ru
    smr-srv-ot-share.utilities.ot-samara.baltika.ru
    smr-srv-ot-share.astue.ot-samara.baltika.ru
) do (
    cmdkey /delete:%%S >nul 2>&1
)

echo.
echo ============================================================
echo   Готово.
echo.
echo   SMB-сессии к SMR-SRV-OT-SHARE сброшены.
echo   Остальные серверы и сетевые подключения не затронуты.
echo.
echo   Теперь заново открой нужный ресурс и введи другую учетку.
echo ============================================================
echo.
pause

20.15.5. Порядок использования

  1. Завершить активное копирование/изменение файлов на SHARE.
  2. Желательно закрыть окна Проводника, открытые на ресурсах SHARE.
  3. Запустить change_share.bat от того же Windows-пользователя, который работал с SMB.
  4. Дождаться сообщения, что SMB-сессии к SMR-SRV-OT-SHARE сброшены.
  5. Снова открыть требуемый ресурс, например \\SMR-SRV-OT-SHARE\ot-admin.
  6. Ввести новую Samba-учётную запись и пароль.

Пример переключения:

Было:
\\SMR-SRV-OT-SHARE\clonezilla
user: clonezilla

↓ запустить change_share.bat

Стало:
\\SMR-SRV-OT-SHARE\ot-admin
user: baltikashare

Важно: скрипт использует принудительное отключение SMB mappings. Не запускать его во время копирования, сохранения или изменения файлов на SHARE: активная файловая операция может быть оборвана.

20.15.6. Что именно выполняет скрипт

  1. Get-SmbMapping находит явные SMB mappings только к известным адресам/именам SHARE.
  2. Remove-SmbMapping -Force -UpdateProfile удаляет найденные mappings.
  3. net use ... /delete дополнительно очищает известные shares и скрытый IPC$.
  4. cmdkey /delete удаляет сохранённые Windows credentials только для известных targets SHARE.
  5. Подключения к другим серверам не очищаются; команда net use * /delete не используется.

20.15.7. Сопровождение BAT

Список targets и shares внутри BAT является частью production-конфигурации клиента. При изменении сетевой схемы SHARE его необходимо актуализировать.

Обновить BAT требуется при:

  • добавлении или удалении IP-адреса файлового сервера;
  • добавлении нового DNS/FQDN/короткого имени, используемого для SMB;
  • добавлении или переименовании Samba share;
  • окончательном удалении временного адреса 192.168.1.229;
  • изменении общей схемы доступа к файловому серверу.

Изменение Samba-паролей или состава групп само по себе не требует изменения BAT, поскольку пароли в скрипте не хранятся.

20.16. Резервное копирование критической конфигурации сервера

Для SMR-SRV-OT-SHARE введён отдельный recovery-backup конфигурации. Цель — иметь на внешнем компьютере набор, достаточный для повторного разворачивания служб после отказа системного диска/VM без необходимости заново вспоминать сетевую схему, Samba ACL, Snapper, DDNS, File Browser и системные unit-файлы.

Backup не заменяет резервирование пользовательских данных MAIN-DATA и CRITICAL-BACKUP. Он предназначен именно для конфигурации и служебного состояния.

20.16.1. Скрипт /usr/local/sbin/share-config-backup

Production-скрипт:

#!/usr/bin/env bash

# ============================================================
# SMR-SRV-OT-SHARE
# Backup critical server configuration
#
# Output:
#   CONFIG archive  - ordinary configuration and inventory
#   SECRETS archive - Samba/File Browser databases, encrypted
#   SHA256SUMS      - archive integrity
#
# Destination:
#   /srv/main-data/baltikashare/ot-admin/server-backups
# ============================================================

set -Eeuo pipefail
umask 077

HOST="$(hostname -s)"
STAMP="$(date '+%Y%m%d-%H%M%S')"

DEST="/srv/main-data/baltikashare/ot-admin/server-backups"
WORK="$(mktemp -d "/var/tmp/${HOST}-config-backup.XXXXXX")"

CONFIG_ROOT="${WORK}/config"
SECRET_ROOT="${WORK}/secrets"
INVENTORY="${CONFIG_ROOT}/inventory"

CONFIG_ARCHIVE="${DEST}/${HOST}-config-${STAMP}.tar.gz"
SECRET_PLAIN="${WORK}/${HOST}-secrets-${STAMP}.tar.gz"
SECRET_ARCHIVE="${DEST}/${HOST}-secrets-${STAMP}.tar.gz.enc"
SUMS="${DEST}/SHA256SUMS-${STAMP}.txt"

STOPPED_SERVICES=()

cleanup()
{
    for svc in "${STOPPED_SERVICES[@]:-}"
    do
        systemctl start "$svc" >/dev/null 2>&1 || true
    done

    rm -rf "$WORK"
}

trap cleanup EXIT

echo "============================================================"
echo "SMR-SRV-OT-SHARE configuration backup"
echo "Host:        $HOST"
echo "Timestamp:   $STAMP"
echo "Destination: $DEST"
echo "============================================================"
echo

if ! mountpoint -q /srv/main-data
then
    echo "ERROR: /srv/main-data is not mounted."
    exit 1
fi

FS_TYPE="$(findmnt -n -o FSTYPE /srv/main-data 2>/dev/null || true)"

if [[ "$FS_TYPE" != "btrfs" ]]
then
    echo "ERROR: /srv/main-data is '$FS_TYPE', expected btrfs."
    exit 1
fi

install -d \
    -o root \
    -g admins \
    -m 0770 \
    "$DEST"

mkdir -p "$CONFIG_ROOT" "$SECRET_ROOT" "$INVENTORY"

copy_path()
{
    local SRC="$1"

    if [[ -e "$SRC" || -L "$SRC" ]]
    then
        echo "COPY: $SRC"
        cp -a --parents "$SRC" "$CONFIG_ROOT"
    else
        echo "SKIP: $SRC does not exist"
    fi
}

echo
echo "=== Static configuration ==="

copy_path /etc/samba

copy_path /etc/netplan
copy_path /etc/hostname
copy_path /etc/hosts
copy_path /etc/nsswitch.conf
copy_path /etc/fstab

copy_path /etc/systemd/resolved.conf
copy_path /etc/systemd/timesyncd.conf

copy_path /etc/sysctl.conf
copy_path /etc/sysctl.d

copy_path /etc/ufw

copy_path /etc/snapper
copy_path /etc/default/snapper

copy_path /etc/systemd/system/smbd.service.d

copy_path /usr/local/sbin/samba-recycle-cleanup
copy_path /etc/systemd/system/samba-recycle-cleanup.service
copy_path /etc/systemd/system/samba-recycle-cleanup.timer

copy_path /usr/local/sbin/ot-ddns-register
copy_path /etc/systemd/system/ot-ddns-register.service

copy_path /etc/filebrowser
copy_path /etc/systemd/system/filebrowser.service
copy_path /usr/local/bin/filebrowser

copy_path /usr/local/sbin/share-config-backup

copy_path /etc/passwd
copy_path /etc/group

copy_path /etc/ssh/sshd_config
copy_path /etc/ssh/sshd_config.d

copy_path /etc/apt/sources.list
copy_path /etc/apt/sources.list.d

echo
echo "=== Collecting inventory ==="

hostnamectl > "${INVENTORY}/hostnamectl.txt" 2>&1 || true

ip -br link \
    > "${INVENTORY}/ip-link.txt" 2>&1 || true

ip -br address \
    > "${INVENTORY}/ip-address.txt" 2>&1 || true

ip route show table all \
    > "${INVENTORY}/ip-route-all.txt" 2>&1 || true

ip rule show \
    > "${INVENTORY}/ip-rule.txt" 2>&1 || true

resolvectl status \
    > "${INVENTORY}/resolvectl-status.txt" 2>&1 || true

timedatectl \
    > "${INVENTORY}/timedatectl.txt" 2>&1 || true

lsblk -o \
NAME,PATH,SIZE,TYPE,FSTYPE,LABEL,UUID,PARTUUID,MOUNTPOINTS \
    > "${INVENTORY}/lsblk.txt" 2>&1 || true

blkid \
    > "${INVENTORY}/blkid.txt" 2>&1 || true

findmnt \
    > "${INVENTORY}/findmnt.txt" 2>&1 || true

findmnt /srv/main-data \
    > "${INVENTORY}/findmnt-main-data.txt" 2>&1 || true

btrfs filesystem show /srv/main-data \
    > "${INVENTORY}/btrfs-filesystem-show.txt" 2>&1 || true

btrfs filesystem usage /srv/main-data \
    > "${INVENTORY}/btrfs-filesystem-usage.txt" 2>&1 || true

btrfs subvolume list -t /srv/main-data \
    > "${INVENTORY}/btrfs-subvolumes.txt" 2>&1 || true

snapper list-configs \
    > "${INVENTORY}/snapper-list-configs.txt" 2>&1 || true

testparm -s \
    > "${INVENTORY}/samba-testparm.txt" 2>&1 || true

pdbedit -L -v \
    > "${INVENTORY}/samba-users.txt" 2>&1 || true

getent passwd \
    > "${INVENTORY}/passwd-getent.txt"

getent group \
    > "${INVENTORY}/group-getent.txt"

dpkg-query -W \
    -f='${binary:Package}\t${Version}\n' \
    > "${INVENTORY}/packages.txt" 2>&1 || true

apt-mark showmanual \
    > "${INVENTORY}/packages-manual.txt" 2>&1 || true

systemctl is-enabled \
    smbd \
    filebrowser \
    samba-recycle-cleanup.timer \
    ot-ddns-register.service \
    > "${INVENTORY}/services-enabled.txt" 2>&1 || true

systemctl is-active \
    smbd \
    filebrowser \
    samba-recycle-cleanup.timer \
    > "${INVENTORY}/services-active.txt" 2>&1 || true

systemctl list-timers --all \
    > "${INVENTORY}/systemd-timers.txt" 2>&1 || true

ss -lntup \
    > "${INVENTORY}/listening-ports.txt" 2>&1 || true

ufw status verbose \
    > "${INVENTORY}/ufw-status.txt" 2>&1 || true

echo
echo "=== Collecting ACL state ==="

ACL="${INVENTORY}/acl-important.txt"
BASE="/srv/main-data/baltikashare"

: > "$ACL"

for share in \
    clonezilla \
    exchange \
    pivoproduction \
    rozliv \
    utilities \
    software \
    documentation \
    ot-admin
do
    DIR="${BASE}/${share}"

    if [[ -d "$DIR" ]]
    then
        echo >> "$ACL"
        echo "==================================================" >> "$ACL"
        echo "SHARE: $share" >> "$ACL"
        echo "==================================================" >> "$ACL"

        getfacl -p "$DIR" >> "$ACL" 2>&1 || true

        if [[ -d "${DIR}/.recycle" ]]
        then
            echo >> "$ACL"
            echo "--- .recycle ---" >> "$ACL"

            getfacl -p "${DIR}/.recycle" \
                >> "$ACL" 2>&1 || true

            find "${DIR}/.recycle" \
                -mindepth 1 \
                -maxdepth 1 \
                -type d \
                -exec getfacl -p {} + \
                >> "$ACL" 2>&1 || true
        fi
    fi
done

cat > "${CONFIG_ROOT}/RESTORE_ORDER.txt" <<'EOF'
SMR-SRV-OT-SHARE
Recommended restore order
=========================

1. Install Ubuntu Server and required packages.

2. Recreate local users/groups while preserving required UID/GID
   where existing MAIN-DATA files are retained.

3. Restore:
   /etc/netplan
   /etc/fstab
   /etc/hostname
   /etc/hosts
   relevant sysctl/systemd configuration.

4. Mount MAIN-DATA and verify:
   mountpoint /srv/main-data
   findmnt /srv/main-data

5. Restore Snapper configuration.

6. Restore scripts:
   /usr/local/sbin/samba-recycle-cleanup
   /usr/local/sbin/ot-ddns-register

7. Restore systemd units:
   samba-recycle-cleanup.service/timer
   smbd.service.d/main-data.conf
   filebrowser.service
   ot-ddns-register.service

8. Restore /etc/samba/smb.conf.

9. Restore Samba private database from encrypted SECRETS archive
   ONLY with Samba stopped.

10. Restore File Browser database from encrypted SECRETS archive
    ONLY with File Browser stopped.

11. Run:
    systemctl daemon-reload
    testparm -s
    netplan generate

12. Verify POSIX ACL against:
    inventory/acl-important.txt

13. Start and verify services.

14. Check:
    Samba RW/RO matrix
    Snapper Previous Versions
    recycle
    File Browser
    DDNS A/PTR
    split DNS
EOF

echo
echo "=== Creating configuration archive ==="

tar \
    --acls \
    --xattrs \
    --numeric-owner \
    -C "$CONFIG_ROOT" \
    -czf "$CONFIG_ARCHIVE" \
    .

chown root:admins "$CONFIG_ARCHIVE"
chmod 0640 "$CONFIG_ARCHIVE"

echo
echo "============================================================"
echo "Sensitive database backup"
echo
echo "Samba/File Browser will be stopped briefly."
echo "Do not run this script during active file transfers."
echo "============================================================"
echo

for svc in smbd nmbd winbind filebrowser
do
    if systemctl is-active --quiet "$svc"
    then
        echo "STOP: $svc"
        systemctl stop "$svc"
        STOPPED_SERVICES+=("$svc")
    fi
done

if [[ -d /var/lib/samba ]]
then
    cp -a --parents /var/lib/samba "$SECRET_ROOT"
fi

if [[ -f /var/lib/filebrowser/filebrowser.db ]]
then
    cp -a --parents \
        /var/lib/filebrowser/filebrowser.db \
        "$SECRET_ROOT"
fi

sync

for svc in "${STOPPED_SERVICES[@]:-}"
do
    echo "START: $svc"
    systemctl start "$svc"
done

STOPPED_SERVICES=()

tar \
    --acls \
    --xattrs \
    --numeric-owner \
    -C "$SECRET_ROOT" \
    -czf "$SECRET_PLAIN" \
    .

echo
echo "============================================================"
echo "Enter a password for the encrypted SECRETS archive."
echo "IMPORTANT: without this password the archive cannot be restored."
echo "============================================================"
echo

openssl enc \
    -aes-256-cbc \
    -salt \
    -pbkdf2 \
    -iter 200000 \
    -in "$SECRET_PLAIN" \
    -out "$SECRET_ARCHIVE"

rm -f "$SECRET_PLAIN"

chown root:admins "$SECRET_ARCHIVE"
chmod 0640 "$SECRET_ARCHIVE"

(
    cd "$DEST"

    sha256sum \
        "$(basename "$CONFIG_ARCHIVE")" \
        "$(basename "$SECRET_ARCHIVE")"
) > "$SUMS"

chown root:admins "$SUMS"
chmod 0640 "$SUMS"

echo
echo "============================================================"
echo "BACKUP COMPLETED"
echo "============================================================"
echo
echo "CONFIG:"
echo "  $CONFIG_ARCHIVE"
echo
echo "SECRETS:"
echo "  $SECRET_ARCHIVE"
echo
echo "CHECKSUMS:"
echo "  $SUMS"
echo
echo "Copy all three files to an external PC/storage."
echo "============================================================"

Права скрипта:

sudo chown root:root /usr/local/sbin/share-config-backup
sudo chmod 0750 /usr/local/sbin/share-config-backup

sudo bash -n /usr/local/sbin/share-config-backup

При успешной синтаксической проверке bash -n не выводит ничего.

20.16.2. Что входит в CONFIG-архив

Обычный архив не содержит Samba password DB и не предназначен для хранения секретов. В него входят критичные конфиги и снимок состояния сервера:

Категория Содержимое
Samba /etc/samba, эффективный testparm -s, список Samba-пользователей без паролей
Сеть /etc/netplan, hostname/hosts, fstab, IP/route/rule, resolvectl
Snapper/Btrfs /etc/snapper, Btrfs filesystem/subvolume/usage, UUID и mount-инвентаризация
systemd unit-файлы Samba protection, recycle cleanup, File Browser, DDNS
Скрипты samba-recycle-cleanup, ot-ddns-register, сам share-config-backup
File Browser конфигурация, unit, бинарный файл; рабочая DB хранится отдельно в SECRETS
Linux users/groups /etc/passwd, /etc/group, getent для фиксации UID/GID
ACL ACL корней восьми shares и служебных .recycle
Пакеты/сервисы установленные/manual packages, активные/enabled службы, systemd timers, listening ports
Recovery RESTORE_ORDER.txt с рекомендуемым порядком восстановления

20.16.3. Что входит в SECRETS-архив

Секретная часть резервируется отдельно и перед записью на MAIN-DATA шифруется. В неё входят:

/var/lib/samba/
/var/lib/filebrowser/filebrowser.db

Для получения согласованной копии база снимается при кратковременно остановленных smbd и filebrowser. После копирования скрипт запускает ранее активные службы обратно до начала шифрования.

Шифрование:

openssl enc \
    -aes-256-cbc \
    -salt \
    -pbkdf2 \
    -iter 200000

Пароль шифрования не должен храниться вместе с SECRETS-архивом. Его необходимо хранить отдельно, например в менеджере паролей или в другом защищённом хранилище. В текст инструкции пароль не заносится.

20.16.4. Запуск backup

Перед запуском необходимо убедиться, что в этот момент нет активного копирования или изменения файлов по SMB, поскольку Samba на короткое время останавливается.

sudo /usr/local/sbin/share-config-backup

В процессе будет запрошен пароль для шифрования SECRETS. Готовые файлы создаются в:

/srv/main-data/baltikashare/ot-admin/server-backups/

Формат имён:

smr-srv-ot-share-config-YYYYMMDD-HHMMSS.tar.gz
smr-srv-ot-share-secrets-YYYYMMDD-HHMMSS.tar.gz.enc
SHA256SUMS-YYYYMMDD-HHMMSS.txt

20.16.5. Проверка SHA256

cd /srv/main-data/baltikashare/ot-admin/server-backups

sha256sum -c SHA256SUMS-YYYYMMDD-HHMMSS.txt

Ожидается:

smr-srv-ot-share-config-...tar.gz: OK
smr-srv-ot-share-secrets-...tar.gz.enc: OK

20.16.6. Вынос backup на Windows-компьютер

Перед подключением под административной учётной записью рекомендуется запустить проверенный change_share.bat, чтобы убрать старый SMB credential context.

Ресурс:

\\SMR-OT-SHARE\ot-admin\server-backups

Допустим также доступ по сегментному IP, например:

\\10.255.0.229\ot-admin\server-backups

На внешнее хранилище необходимо копировать комплект целиком:

*-config-*.tar.gz
*-secrets-*.tar.gz.enc
SHA256SUMS-*.txt

После копирования на ПК рекомендуется повторно проверить SHA256 (например через certutil -hashfile или другой проверенный инструмент) и хранить как минимум ещё одну независимую копию recovery-набора.

20.16.7. Первый сформированный recovery-набор

10.11.2026 сформирован первый recovery-набор с timestamp 20261110-154701:

smr-srv-ot-share-config-20261110-154701.tar.gz
smr-srv-ot-share-secrets-20261110-154701.tar.gz.enc
SHA256SUMS-20261110-154701.txt

Наличие этих файлов подтверждает фактический запуск backup-процедуры. Recovery-набор необходимо хранить вне самой VM/MAIN-DATA, поскольку backup, лежащий только на том же сервере, не защищает от полного отказа сервера или массива.

20.16.8. Расшифровка SECRETS при восстановлении

На recovery-системе зашифрованный архив можно преобразовать обратно во временный tar.gz:

openssl enc -d \
    -aes-256-cbc \
    -pbkdf2 \
    -iter 200000 \
    -in smr-srv-ot-share-secrets-YYYYMMDD-HHMMSS.tar.gz.enc \
    -out smr-srv-ot-share-secrets-YYYYMMDD-HHMMSS.tar.gz

После проверки содержимого временный незашифрованный архив должен быть удалён или храниться только на защищённом носителе.

20.16.9. Рекомендуемый порядок восстановления

  1. Установить Ubuntu Server и необходимые пакеты.
  2. Восстановить пользователей/группы с учётом UID/GID из inventory.
  3. Восстановить сеть, hostname/hosts, fstab и системные настройки.
  4. Смонтировать MAIN-DATA и проверить mountpoint/findmnt.
  5. Восстановить конфигурацию Snapper.
  6. Восстановить локальные скрипты и systemd unit/drop-in.
  7. Восстановить /etc/samba/smb.conf и проверить testparm -s.
  8. Остановить Samba и только после этого восстановить /var/lib/samba из SECRETS.
  9. Остановить File Browser и восстановить его DB из SECRETS.
  10. Выполнить systemctl daemon-reload и проверить конфигурацию сети.
  11. Сверить POSIX ACL с inventory/acl-important.txt.
  12. Запустить сервисы и проверить RW/RO-матрицу Samba.
  13. Проверить Snapper Previous Versions, recycle, File Browser, DDNS A/PTR и split DNS.

При восстановлении Samba private DB желательно использовать ту же major/minor ветку Samba, на которой backup был создан. Перед заменой рабочего /var/lib/samba всегда необходимо сохранить его текущую копию.

20.16.10. Что backup не заменяет

  • backup пользовательских файлов MAIN-DATA;
  • копирование критичных данных на CRITICAL-BACKUP;
  • резервную копию самой VM/системного диска;
  • внешнюю/offline-копию recovery-набора;
  • документированную проверку восстановления.

Production-подход: конфигурационный recovery-набор + резервные копии данных + актуальная BookStack-инструкция должны храниться раздельно и позволять восстановить сервис без зависимости от единственного экземпляра VM.

21. Текущая контрольная точка

Этап Состояние
P411 Slot 1, firmware 6.64, 512 MB FBWC, PCIe Gen2 x8, Status OK
D2700 firmware 0150, 25/25 дисков OK
MAIN-DATA RAID50, 5.46 TiB, production Btrfs, VM 103
RECOVERY RAID1, около 136 GiB
CRITICAL-BACKUP RAID50, около 3.64 TiB
GLOBAL-SPARE bay 15, shared spare, OK
Parity RAID50 Queued; эксплуатацию не блокирует, контролируется
Production Btrfs LABEL MAIN-DATA, mount /srv/main-data
Subvolume 8 functional Btrfs subvolume
Snapper 8 configs; timeline/cleanup timers active
POSIX ACL SGID/default ACL настроены; корзины переведены на приватную модель .recycle/<user> + административный доступ admins; добавлены shared-ro и профильные *-ro ACL с исключением .snapshots/.recycle
Samba введена в эксплуатацию; 8 shares; RW-модель: engineers + профильная *-rw; RO-модель: shared-ro + профильная *-ro; testparm OK, конфигурация перечитана через systemctl reload smbd
vfs_recycle 7 shares; directory_mode/subdir_mode = 0770; sticky bit и ACL проверены; clonezilla исключён намеренно
Очистка .recycle production-скрипт + systemd timer; dry-run/delete проверены
vfs_snapper Windows Previous Versions: просмотр и восстановление проверены
Служебные каталоги .snapshots veto; .recycle hidden
Защита smbd RequiresMountsFor + mountpoint ExecStartPre работают
File Browser Next v3.0.0-next; отдельный user filebrowser; web-admin baltikafile; root MAIN-DATA; port 28443
Management route default via 10.44.100.1 dev ens19; 192.168.1.229/24 без default gateway
File Browser / recycle доступ к .recycle на всех 7 recycle-shares проверен; повторное создание .recycle/pivo проверено
ABE не используется по принятому решению
NFS не установлен; внедрение отложено до реальной необходимости
Split DNS systemd-resolved: per-link OT DNS и route-only domains для прямой и reverse-зон; проверено
DNS-имена SHARE 5 сегментных FQDN; A/PTR зарегистрированы и проверены. Для сетей /23 PTR находится только в reverse-зоне /24, соответствующей фактическому IP; дублирования в парную зону нет.
Linux DDNS ot-ddns-register + ot-ddns-register.service; systemd запуск завершён status=0/SUCCESS
Переключение SMB credentials change_share.bat проверен на Windows-клиенте; очищает SMB mappings, IPC$ и сохранённые credentials только для адресов/имён SHARE, не затрагивая подключения к другим серверам.
Персонифицированные Samba-учётки создаются как локальные Linux-пользователи без shell; права задаются членством в engineers + профильной *-rw; в документации реальные логины не фиксируются
Read-only Samba-учётки rozliv_read, pivo_read, utilities_read созданы; rozliv_read локально проверен: свой профильный share + exchange/software/documentation только RO, остальные DENY. Windows SMB-проверка RO-ролей остаётся отдельным контрольным шагом.
Recovery backup конфигурации /usr/local/sbin/share-config-backup; CONFIG + зашифрованный SECRETS + SHA256; destination ot-admin/server-backups; первый набор 20261110-154701 сформирован и подготовлен для внешнего хранения.

21.1. Следующие этапы

После существенных изменений сети, Samba, ACL, Snapper, File Browser или systemd повторно запускать /usr/local/sbin/share-config-backup, выносить новый комплект с сервера и проверять SHA256. Отдельно провести тестовое восстановление recovery-набора в изолированной VM.

Проверить RO-роли через Windows SMB после запуска change_share.bat: rozliv_read, pivo_read, utilities_read. Для каждого подтвердить чтение своего профильного share и exchange/software/documentation, запрет записи и DENY к чужим профильным ресурсам, clonezilla и ot-admin.

После следующей плановой перезагрузки один раз проверить boot-журнал ot-ddns-register.service.

При переводе Пивопроизводства на VLAN2030 выполнить DNS-миграцию ens23 → ens21 по разделу 20.14.7.

При вводе клиентов новых сегментов стандартизировать двухэлементный DNS suffix search list: локальный сегментный suffix + ot-samara.baltika.ru.

  1. Провести инвентаризацию слушающих портов и настроить firewall для management-интерфейса 10.44.100.229; оставить только сознательно необходимые административные сервисы.
  2. Настроить копирование выбранных критичных данных на CRITICAL-BACKUP.
  3. Добавить мониторинг P410i/P411, D2700, physical disks, Btrfs usage, Snapper, mount, Samba и File Browser.
  4. NFS внедрять только при появлении реальной необходимости; первым потенциальным потребителем остаётся Clonezilla.
  5. Отдельно решить вопрос постоянного использования hpsa_simple_mode=1.
  6. Отдельно оценить необходимость Dual Domain через второй порт P411 и I/O Module B.

22. Порядок включения и выключения D2700

22.1. Включение

  1. Подать питание на оба БП D2700.
  2. Включить полку и дождаться инициализации.
  3. Включить DL380 G7.
  4. Проверить POST P411 и доступность logical drive.

22.2. Выключение

  1. Корректно остановить VM.
  2. Корректно остановить Proxmox/DL380.
  3. Дождаться полного выключения сервера.
  4. Перевести D2700 в Standby.
  5. При необходимости снять AC с БП полки.

22.3. Восстановление питания

Желаемая последовательность: сначала D2700 и её инициализация, затем запуск DL380 G7 с задержкой. Поведение после полного снятия и возврата AC требуется отдельно проверить в production-конфигурации.

23. Справочные материалы

  • Btrfs documentation
  • Snapper documentation
  • Samba vfs_snapper / vfs_recycle
  • HPE Smart Array / D2700 documentation
  • File Browser Next documentation / release v3.0.0-next

BookStack page: HP D2700: схема дисковых массивов и назначение хранилищ

Обновление 1.0: фактическая конфигурация Samba и результаты тестов добавлены 28.10.2026.
Обновление 1.1: проверены Windows Previous Versions, скрытие служебных каталогов, автоматическая очистка Samba recycle и защита smbd от запуска без MAIN-DATA; ABE оставлен отключённым.
Обновление 1.2: добавлены File Browser Next, management gateway 10.44.100.1, production ACL для Samba recycle, проверка повторного создания персональной корзины и актуальная контрольная точка на 30.10.2026.

BookStack: Установка DNS сервера BIND9 на Ubuntu Server 24.04 с Webmin в Proxmox

Обновление 1.3: добавлены split DNS через systemd-resolved, сегментные FQDN файлового сервера, RFC 2136/DDNS через nsupdate, ot-ddns-register.service, клиентская модель DNS suffix search list и процедура миграции Pivo на ens21. 05.11.2026.

Обновление 1.4: уточнена логика reverse DNS для сетей /23. Обе половины /23 обслуживаются отдельными reverse-зонами /24, но PTR конкретного адреса SHARE создаётся только в той зоне, которой принадлежит его фактический IP. Для 172.16.66.229, 172.16.68.229 и 172.16.70.229 это зоны 66, 68 и 70.16.172.in-addr.arpa; зоны 67, 69 и 71 предназначены для других адресов второй половины соответствующих /23. 06.11.2026.

Обновление 1.5: добавлена проверенная Windows-процедура переключения Samba-учётной записи. BAT change_share.bat обрабатывает все текущие IP, короткие имена и сегментные FQDN SMR-SRV-OT-SHARE, очищает явные SMB mappings, IPC$ и сохранённые credentials только для SHARE, после чего пользователь может повторно открыть ресурс под другой Samba-учётной записью. Остальные сетевые серверы и mappings не затрагиваются. 06.11.2026.

Обновление 1.6: скорректирована эксплуатационная модель доступа производственных пользователей. Учётные записи Пивопроизводства, Розлива и Утилит теперь одновременно состоят в engineers и своей профильной *-rw группе, благодаря чему получают RW к своему производственному ресурсу и exchange, RO к software/documentation и не получают доступ к чужим профильным shares. Добавлен шаблон создания персонифицированных учётных записей на примере user1/user2; реальные персональные логины в документации не хранятся. Обновлённая модель проверена на Windows-клиенте для профиля Розлива. 10.11.2026.

Обновление 1.7: добавлена read-only модель доступа для производственных подразделений. Созданы группы shared-ro, pivoproduction-ro, rozliv-ro, utilities-ro; shared-ro предоставляет RO к exchange/software/documentation, профильная *-ro — RO только к своему производственному share. Обновлён /etc/samba/smb.conf с использованием read list и valid users. Для POSIX ACL зафиксирован безопасный способ применения через find ... -prune без обхода .snapshots и .recycle. Созданы тестовые ролевые учётки rozliv_read, pivo_read, utilities_read; локальная матрица прав rozliv_read проверена успешно. 10.11.2026.

Обновление 1.8: введён recovery-backup критической конфигурации SMR-SRV-OT-SHARE. Добавлен production-скрипт /usr/local/sbin/share-config-backup, формирующий обычный CONFIG-архив с конфигурацией и инвентаризацией, отдельный зашифрованный AES-256-CBC/PBKDF2 SECRETS-архив с Samba/File Browser state DB и файл SHA256. Описаны состав архивов, запуск, проверка SHA256, вынос на Windows-компьютер, расшифровка и рекомендуемый порядок восстановления. Первый recovery-набор 20261110-154701 сформирован 10.11.2026.