Dwanaście instalacji

Prywatny Nextcloud na NVMe z magazynem obiektów za nim

Nextcloud na instancji Ryzen z Postgresem i Redisem na lokalnym NVMe, każdy plik użytkownika w buckecie na węźle pamięci masowej, połączonym prywatnym tunelem.

Co to buduje

Dwie maszyny. Instancja Ryzen uruchamia Nextcloud, PHP-FPM, Postgres i Redis, wszystko na lokalnym Gen4 NVMe, gdzie mieszka praca wrażliwa na opóźnienia. Węzeł magazynujący obok trzyma faktyczną zawartość plików w zasobniku obiektowym, gdzie mieszkają tanie terabajty. Pomiędzy nimi znajduje się tunel WireGuard, więc nic w tym układzie nie jest wystawione na nic innego.

Ten podział ma znaczenie, ponieważ Nextcloud z podstawowym magazynem obiektów całkowicie przestaje zapisywać dane użytkowników na lokalnym dysku. Twój NVMe trzyma bazę danych i kod; zasobnik trzyma każdy bajt, który ktoś wgra. Wzrost z dwustu gigabajtów do dwudziestu terabajtów staje się wtedy aktualizacją węzła magazynującego, a nie migracją.

Zanim zaczniesz

  • R-8 dla aplikacji i S-50 dla zasobnika, najlepiej w tym samym mieście, aby czas w obie strony tunelu był poniżej milisekundy.
  • Tunel między nimi. Przewodnik WireGuard buduje dokładnie to; użyj 10.9.0.1 dla aplikacji i 10.9.0.2 dla węzła magazynującego.
  • Nazwa hosta wskazująca na instancję aplikacji, cloud.example.com poniżej.

1. Magazyn obiektów na węźle magazynującym

MinIO to pojedynczy plik binarny i nie potrzebuje niczego więcej. Pobierz go, zweryfikuj, zainstaluj:

cd /usr/local/bin
wget https://dl.min.io/server/minio/release/linux-amd64/minio
wget https://dl.min.io/server/minio/release/linux-amd64/minio.sha256sum
sha256sum -c minio.sha256sum
chmod +x minio
useradd -r -s /sbin/nologin minio
install -d -o minio -g minio /srv/objects

Pojemność masowa na węźle magazynującym jest montowana oddzielnie od NVMe. Umieść zasobnik na pojemności masowej, a NVMe zostaw na cache zapisu, do czego on służy. Potem unit, w /etc/systemd/system/minio.service:

[Unit]
Description=MinIO
After=network-online.target [email protected]
Wants=network-online.target

[Service]
User=minio
Group=minio
Environment=MINIO_ROOT_USER=nextcloud
Environment=MINIO_ROOT_PASSWORD=<forty random characters>
ExecStart=/usr/local/bin/minio server /srv/objects --address 10.9.0.2:9000
Restart=always
LimitNOFILE=65535
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/srv/objects

[Install]
WantedBy=multi-user.target

Wiązanie z adresem tunelu zamiast ze wszystkim jest ważną linią. Magazyn obiektów nie ma prawa odpowiadać na publicznym interfejsie, a w ten sposób błąd w zaporze nie może go wystawić.

systemctl daemon-reload && systemctl enable --now minio
ss -ltn | grep 9000

2. Host aplikacji: pakiety

Na instancji Ryzen:

apt update && apt install -y nginx postgresql redis-server unzip \
  php8.4-fpm php8.4-pgsql php8.4-gd php8.4-curl php8.4-zip php8.4-xml \
  php8.4-mbstring php8.4-intl php8.4-bcmath php8.4-gmp php8.4-imagick \
  php8.4-redis php8.4-apcu

3. Baza danych

sudo -u postgres psql -c "CREATE USER nextcloud WITH PASSWORD '<a long password>';"
sudo -u postgres psql -c "CREATE DATABASE nextcloud OWNER nextcloud TEMPLATE template0 ENCODING UTF8;"

Domyślne ustawienia Postgresa są dobre w tej skali. Jeśli to Nextcloud ma obsługiwać kilkaset osób, przewodnik po strojeniu Postgresa ma zastosowanie, a liczby w nim są warte godziny.

4. Nextcloud, skonfigurowany przed instalacją

cd /var/www
wget https://download.nextcloud.com/server/releases/latest.zip
unzip -q latest.zip && rm latest.zip
chown -R www-data:www-data /var/www/nextcloud

Teraz część, która musi się wydarzyć przed uruchomieniem instalatora, ponieważ podstawowego magazynu obiektów nie można dodać do istniejącej instancji bez ręcznego przenoszenia każdego pliku. Utwórz /var/www/nextcloud/config/config.php:

<?php
$CONFIG = array(
  "objectstore" => array(
    "class" => "\\OC\\Files\\ObjectStore\\S3",
    "arguments" => array(
      "bucket" => "nextcloud",
      "autocreate" => true,
      "key" => "nextcloud",
      "secret" => "<the same forty characters>",
      "hostname" => "10.9.0.2",
      "port" => 9000,
      "use_ssl" => false,
      "use_path_style" => true,
      "region" => "local",
    ),
  ),
);

use_ssl jest fałszywe celowo. Ruch przechodzi przez tunel WireGuard, który jest już uwierzytelniony i zaszyfrowany, a kończenie TLS po raz drugi na węźle magazynującym daje tylko cykle procesora i certyfikat do zapomnienia o odnowieniu. Gdyby te dwie maszyny kiedykolwiek znalazły się w różnych miastach, włącz to.

chown www-data:www-data /var/www/nextcloud/config/config.php
chmod 640 /var/www/nextcloud/config/config.php
cd /var/www/nextcloud
sudo -u www-data php occ maintenance:install --database pgsql \
  --database-name nextcloud --database-user nextcloud \
  --database-pass "<a long password>" \
  --admin-user admin --admin-pass "<another long password>"

5. Cache, cron i ostatnie ustawienia

sudo -u www-data php occ config:system:set memcache.local --value "\\OC\\Memcache\\APCu"
sudo -u www-data php occ config:system:set memcache.distributed --value "\\OC\\Memcache\\Redis"
sudo -u www-data php occ config:system:set memcache.locking --value "\\OC\\Memcache\\Redis"
sudo -u www-data php occ config:system:set redis host --value /run/redis/redis-server.sock
sudo -u www-data php occ config:system:set redis port --value 0
sudo -u www-data php occ config:system:set trusted_domains 0 --value cloud.example.com
sudo -u www-data php occ config:system:set overwrite.cli.url --value https://cloud.example.com
sudo -u www-data php occ background:cron

Redis przez unix socket zamiast TCP oszczędza jedno okrążenie syscall przy każdej operacji blokady, a Nextcloud wykonuje dużo blokad. Dodaj www-data do grupy redis, aby mógł dotrzeć do socketa, potem podłącz zadanie w tle do timera:

usermod -aG redis www-data
systemctl restart php8.4-fpm redis-server
echo "*/5 * * * * php -f /var/www/nextcloud/cron.php" | crontab -u www-data -

Domyślne ustawienia PHP-FPM zakładają współdzieloną maszynę. Twoja nie jest współdzielona, więc w /etc/php/8.4/fpm/pool.d/www.conf ustaw pm = dynamic, pm.max_children = 60, pm.start_servers = 12, pm.min_spare_servers = 8 i pm.max_spare_servers = 20, a memory_limit podnieś do 1G w /etc/php/8.4/fpm/php.ini. Wgrywanie chce upload_max_filesize i post_max_size na 16G, chyba że lubisz tłumaczyć, dlaczego wideo nie powiodło się w dziewięćdziesięciu procentach.

Zweryfikuj to

Sednem tej konstrukcji jest to, że pliki użytkowników nie znajdują się na serwerze aplikacji. Udowodnij to trzema poleceniami.

sudo -u www-data php occ status
du -sh /var/www/nextcloud/data

Status powinien zgłaszać zainstalowany i nie w trybie konserwacji. Katalog danych powinien mieć kilka megabajtów i taki pozostać na zawsze; trzyma logi i nic więcej, gdy magazyn obiektów jest podstawowy.

Teraz wgraj coś i obserwuj, gdzie to ląduje:

head -c 50M /dev/urandom > /tmp/test.bin
curl -u admin -T /tmp/test.bin https://cloud.example.com/remote.php/dav/files/admin/test.bin
du -sh /var/www/nextcloud/data

Wgrywanie się udaje, a katalog danych nie urósł o pięćdziesiąt megabajtów. Na węźle magazynującym obiekt jest widoczny bezpośrednio:

ls -R /srv/objects/nextcloud | tail -5
du -sh /srv/objects/nextcloud

Obiekty są nazwane urn:oid: po którym następuje id pliku, dlatego zasobnik nie jest przeglądarkową kopią folderów użytkownika i dlatego tworzysz kopię zapasową bazy danych i zasobnika razem albo wcale.

Potem

Weź dodatek do kopii zapasowej poza węzłem dla zrzutu Postgresa i zasobnika, albo zrób własną do trzeciej lokalizacji. Zasobnik bez bazy danych to sterta ponumerowanych blobów, a baza danych bez zasobnika to indeks plików, które już nie istnieją. Utrata jednego oznacza utratę obu.

Gotowi, gdy jesteś

Wybierz miasto. Wybierz rozmiar. Płać kryptowalutą.

Bez formularzy o tym, kim jesteś, bez czekania na akceptację człowieka, bez telefonu w celu weryfikacji. Faktura zostaje uregulowana, a dane logowania trafiają do Twojej skrzynki.