
Há um harvester muito legal para gerenciamento conjunto de projetos, autorização LDAP, sincronização de arquivos com controle de versão e algo como um mensageiro corporativo com videoconferência, que estavam bagunçados nas versões mais recentes. Sim, estou falando sobre Nextcloud. Por um lado, sou um defensor do modo Unix e de uma clara divisão de aplicativos em funções separadas. Por outro lado, este produto é mais do que estável, tem trabalhado por muitos anos em vários projetos sem problemas e apitos adicionais não interferem particularmente no seu trabalho. Se você realmente quiser, pode estragar quase qualquer jogo lá. A comunidade é animada e completa vários plug-ins que estão disponíveis como aplicativos separados.
Hoje iremos implantá-lo. Não darei instruções passo a passo completas, mas tentarei mencionar os pontos-chave da arquitetura que valem a pena prestar atenção. Em particular, analisaremos o balanceamento de carga, a replicação do banco de dados e a manutenção de rotina sem interrupção do serviço.
Vamos implantá-lo em uma versão à prova de falhas para uma pequena empresa com 150-1000 usuários, mas também será útil para usuários domésticos.
O que as empresas precisam?
A principal diferença entre o atendimento em um aconchegante servidor doméstico feito de bolotas e fósforos do segmento corporativo é a responsabilidade com os usuários. Porém, mesmo na minha instalação doméstica, considero uma boa forma de enviar mensagens aos usuários avisando sobre trabalhos planejados ou um potencial acidente. Afinal, é sábado à noite que seu amigo pode repentinamente decidir trabalhar com os dados que ele hospeda com você.
No caso de uma empresa, mesmo pequena, qualquer serviço simples e importante significa perdas e problemas potenciais. Principalmente se houver muitos processos vinculados ao serviço.
Em particular, em minha experiência, Nextcloud está em demanda por vários recursos entre pequenas empresas:
- Fornecendo acesso a diretórios compartilhados e sincronização.
- Um recurso matador com o fornecimento de acesso externo dentro da federação. Você pode integrar com um produto semelhante de colegas e de outra empresa.
- Fornecimento de acesso externo por meio de um link direto. Isso ajuda muito se você, por exemplo, trabalha na indústria gráfica e precisa trocar grandes quantidades de dados pesados com os clientes.
- Editor de documentos Collabora que roda no lado do servidor e atua como um frontend para o LibreOffice.
- Chats e videochamadas. Um recurso um pouco controverso e não totalmente estável, mas está lá e funciona. Na versão mais recente, ele já foi estabilizado.
Nós construímos arquitetura
Infelizmente, nas versões mais recentes, a documentação do Nextcloud Enterprise Implementation está disponível apenas para membros pagos. No entanto, como referência, você pode pegar os manuais mais antigos que ainda são de domínio público.

Típico para uso doméstico e instalações individuais.
Uma opção “multifuncional” não é ruim, contanto que você tenha poucos usuários e possa permitir o tempo de inatividade para manutenção de rotina. Por exemplo, durante uma atualização. Além disso, um esquema monolítico com colocação em um nó tem problemas com dimensionamento. Portanto, tentaremos a segunda opção.

Opção de implantação escalável recomendada para cargas de trabalho mais altas.
Os principais componentes do sistema:
- 1 balanceador. Você pode usar HAproxy ou Nginx. Vou considerar a opção com o Nginx.
- Servidor de aplicativos de 2 a 4 peças (servidor web). A instalação do Nextcloud com o código principal em php.
- 2 DB. Na configuração padrão recomendada, é MariaDB.
- Armazenamento NFS.
- Redis para consultas de banco de dados em cache
Balanceador
Com essa arquitetura, você terá menos pontos de falha. O principal ponto de falha é o balanceador de carga. Se não estiver disponível, os usuários não conseguirão acessar o serviço. Felizmente, sua configuração do mesmo nginx é bastante simples, como consideraremos mais adiante, e mantém a carga sem problemas. A maioria das falhas no balanceador é resolvida reiniciando o daemon, o nó inteiro ou implementando a partir de um backup. Não será supérfluo ter uma reserva fria configurada em outro local com o tráfego manual mudando para ele no DNS.
Observe que o balanceador também é um ponto de terminação SSL / TLS para seus clientes, e a comunicação com o back-end pode ir por HTTP para redes internas confiáveis ou com HTTPS adicional se o tráfego para o servidor de aplicativos passar por canais não confiáveis gerais.
Base de dados
Uma solução típica é MySQL / MariaDB na execução de cluster em replicação mestre-escravo. Ao mesmo tempo, você tem apenas um banco de dados ativo e o segundo opera em modo de espera ativa em caso de falha de emergência do principal ou durante o trabalho programado. O balanceamento de carga pode ser considerado, mas é tecnicamente mais difícil. Ao usar MariaDB Galera Cluster com a opção de replicação mestre-mestre, você precisa usar um número ímpar de nós, mas pelo menos três. Assim, o risco de situações de divisão do cérebro é minimizado, quando a conectividade entre os nós é cortada.
Armazenamento
Qualquer solução que seja melhor para você fornecida pelo protocolo NFS. Para cargas altas, considere o IBM Elastic Storage ou Ceph. Também é possível usar o armazenamento de objetos compatível com S3, mas esta é mais uma opção para instalações muito grandes.
HDD ou SSD
Em princípio, para instalações de médio porte, usar apenas o HDD é suficiente. O gargalo aqui serão iops durante a leitura do banco de dados, o que afeta muito a capacidade de resposta do sistema, mas se você tiver o Redis, que armazena tudo em cache na RAM, isso não será um grande problema. Além disso, parte do cache será armazenada em memcached nos servidores de aplicativos. No entanto, eu recomendaria hospedar seus servidores de aplicativos em um SSD sempre que possível. A interface da web parece muito mais ágil. Ao mesmo tempo, a mesma sincronização de arquivo em clientes de desktop funcionará quase da mesma maneira que ao usar o HDD para esses nós.
A velocidade de sincronização e upload de arquivo será determinada pelo desempenho do seu armazenamento NFS.
Configurando o balanceador
Como exemplo, vou dar uma configuração básica simples e nginx eficaz. Sim, vários failover-buns adicionais estão disponíveis apenas na versão paga, mas mesmo na versão básica cumpre perfeitamente sua tarefa. Observe que o balanceamento round robin ou aleatório não é adequado para nós, pois os servidores de aplicativos armazenam caches para clientes específicos.
Felizmente, isso é resolvido com o método ip_hash . Nesse caso, as sessões do usuário serão atribuídas a um back-end específico, para o qual todas as solicitações do usuário serão direcionadas. Este ponto é descrito na documentação:
, IP- . IPv4- IPv6- . , . , . .
Infelizmente, ao usar esse método, pode haver problemas com usuários que estão atrás de um IP dinâmico e o estão constantemente mudando. Por exemplo, em clientes com Internet móvel, que podem ser lançados por diferentes rotas ao alternar entre células. O cookie pegajoso que resolve esse problema está disponível apenas na versão paga.
O arquivo de configuração nginx descreve isso da seguinte maneira:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com;
server backend2_nextcloud.example.com;
server backend3_nextcloud.example.com;
server backend4_nextcloud.example.com;
}
Nesse caso, a carga será distribuída da maneira mais uniforme possível entre os servidores de aplicativos, embora possam ocorrer desequilíbrios de carga devido ao cliente estar vinculado a uma sessão específica. Para instalações de pequeno a médio porte, isso pode ser negligenciado. Se seus back-ends forem diferentes em potência, você poderá definir o peso de cada um deles. Em seguida, o balanceador tentará distribuir a carga proporcionalmente aos pesos dados:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com weight=3;
server backend2_nextcloud.example.com;
server backend3_nextcloud.example.com;
}
No exemplo fornecido, de 5 solicitações recebidas, 3 irão para backend1, 1 para backend2 e 1 para backend3.
Se um dos servidores de aplicativos falhar, o nginx tentará redirecionar a solicitação para o próximo servidor da lista de back-ends.
Configurando o banco de dados
Detalhes da configuração Master-Slave podem ser encontrados na documentação principal .
Vamos dar uma olhada em alguns pontos-chave. Primeiro, criamos um usuário para replicação de dados:
create user 'replicant'@'%' identified by 'replicant_password';
grant replication slave on *.* to replicant;
flush privileges;
Em seguida, editamos a configuração principal:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Na área do bloco "Logging and Replication", faça as edições necessárias:
[mysqld]
log-bin = /var/log/mysql/master-bin
log-bin-index = /var/log/mysql/master-bin.index
binlog_format = mixed
server-id = 01
replicate-do-db = nextcloud
bind-address = 192.168.0.6
No Slave, configuramos a configuração:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Na área do bloco "Logging and Replication", faça as edições necessárias:
[mysqld]
server-id = 02
relay-log-index = /var/log/mysql/slave-relay-bin.index
relay-log = /var/log/mysql/slave-relay-bin
replicate-do-db = nextcloud
read-only = 1
bind-address = 192.168.0.7
Reinicie os dois servidores:
sudo systemctl restart mariadb
Em seguida, você precisará copiar o banco de dados para o Slave.
No Master, primeiro executamos o bloqueio de tabela:
flush tables with read lock;
E então olhamos para o status:
MariaDB [(none)]> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000001 | 772 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.000 sec)
Não saia do console do banco de dados, caso contrário os bloqueios serão removidos!
Precisamos de master_log_file e master_log_pos daqui para a configuração do Slave.
Despejar e remover bloqueios:
sudo mysqldump -u root nextcloud > nextcloud.sql
> unlock tables;
> exit;
Em seguida, importamos o dump para o Slave e reiniciamos o daemon:
sudo mysqldump -u root nextcloud < nextcloud.sql
sudo systemctl restart mariadb
Depois disso, configure a replicação no console:
MariaDB [(none)]> change master 'master01' to
master_host='192.168.0.6',
master_user='replicant',
master_password='replicant_password',
master_port=3306,
master_log_file='master-bin.000001',
master_log_pos=772,
master_connect_retry=10,
master_use_gtid=slave_pos;
Lançamos e verificamos:
> start slave 'master01';
show slave 'master01' status\G;
Não deve haver erros na resposta e dois pontos indicarão o sucesso do procedimento:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Implantar nós de aplicativo
Existem várias opções de implantação:
- estalo
- imagem docker
- atualização manual
Snap está disponível principalmente para Ubuntu. É muito bom em entregar aplicativos proprietários complexos, mas por padrão. Mas ele tem um recurso que é bastante irritante em um ambiente industrial - ele atualiza automaticamente seus pacotes várias vezes ao dia. Você também terá que serrar acessos adicionais para o exterior se tiver uma rede interna rigidamente delimitada. Ao mesmo tempo, espelhar seus repositórios internos não é totalmente trivial.
Sim, existem canais de assinatura e grandes lançamentos, em teoria, não deve mudar, mas pense nisso. Eu recomendaria controle total sobre o processo de atualização, especialmente porque muitas vezes é acompanhado por uma mudança na estrutura de dados no banco de dados.
Docker-image é uma boa opção, especialmente se sua infraestrutura já estiver em execução no Kubernetes. O mesmo nó do Redis provavelmente irá para o cluster após os servidores de aplicativos.
Se você não tem a infraestrutura para fazer isso, atualizar e implantar manualmente a partir do tar.gz é bastante conveniente e controlado.
Lembre-se de que você precisará instalar um servidor da web no servidor de aplicativos para lidar com as solicitações de entrada. Eu recomendaria um pacote de nginx + php-fpm7.4. Com as últimas versões do php-fmp, o desempenho e a capacidade de resposta melhoraram significativamente.
Configurando SSL / TLS
Você definitivamente deve contar com o TLS 1.3 se estiver fazendo uma nova instalação e não houver problemas com os pacotes nginx que dependem da atualização do sistema openssl. Em particular, 0-RTT e outros goodies permitem às vezes acelerar significativamente a reconexão do cliente devido ao cache. A segurança também é maior devido ao corte de protocolos desatualizados.
Darei a configuração real do servidor de aplicativos nginx, que se comunica com o balanceador via TLS:
Nginx config
upstream php-handler {
server unix:/var/run/php/php7.4-fpm.sock;
}
server {
listen 80;
server_name backend1_nextcloud.example.com;
# enforce https
root /var/www/nextcloud/;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
ssl_early_data on;
# listen [::]:443 ssl http2;
server_name backend1_nextcloud.example.com;
# Path to the root of your installation
root /var/www/nextcloud/;
# Log path
access_log /var/log/nginx/nextcloud.nginx-access.log;
error_log /var/log/nginx/nextcloud.nginx-error.log;
### SSL CONFIGURATION ###
ssl_certificate /etc/letsencrypt/live/backend1_nextcloud.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/backend1_nextcloud.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/backend1_nextcloud.example.com/fullchain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
#ssl_ciphers "EECDH+AESGCM:EECDH+CHACHA20:EECDH+AES256:!AES128";
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POL>
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8;
add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload' always;
### SSL ###
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
# add_header Strict-Transport-Security "max-age=15768000;
# includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# The following 2 rules are only needed for the user_webfinger app.
# Uncomment it if you're planning to use this app.
#rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
#rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
# last;
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;
# Enable gzip but do not remove ETag headers
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fon>
# Uncomment if your server is build with the ngx_pagespeed module
# This module is currently not supported.
#pagespeed off;
location / {
rewrite ^ /index.php;
}
location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
# Avoid sending the security headers twice
fastcgi_param modHeadersAvailable true;
# Enable pretty urls
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
# Adding the cache control header for js, css and map files
# Make sure it is BELOW the PHP block
location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
try_files $uri /index.php$request_uri;
add_header Cache-Control "public, max-age=15778463";
# Add headers to serve security related headers (It is intended to
# have those duplicated to the ones above)
# Before enabling Strict-Transport-Security headers please read into
# this topic first.
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Download-Options "noopen" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
add_header X-Robots-Tag "none" always;
add_header X-XSS-Protection "1; mode=block" always;
# Optional: Don't log access to assets
access_log off;
}
location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
try_files $uri /index.php$request_uri;
# Optional: Don't log access to other assets
access_log off;
}
}
Manutenção de rotina
Lembre-se, em um ambiente industrial, você precisa fornecer um tempo de inatividade mínimo e zero para atualizações ou até mais backups. A principal dificuldade aqui é a dependência do estado dos metadados no banco de dados e dos próprios arquivos, que estão disponíveis via NFS ou armazenamento de objetos.
Ao atualizar os servidores de aplicativos para uma nova versão secundária, não há problemas especiais. Mas o cluster ainda precisa ser alternado para o modo de manutenção para atualizar a estrutura do banco de dados.
Desligue o balanceador no momento de menor carga e prossiga com a atualização.
Depois disso, realizamos o processo de atualização manual a partir do tar.gz baixado, enquanto salvamos o arquivo de configuração config.php. Atualizar pela web em grandes instalações é uma péssima ideia!
Nós atualizamos através da linha de comando:
sudo -u www-data php /var/www/nextcloud/occ upgrade
Depois disso, ligamos o balanceador e enviamos o tráfego para o servidor atualizado. Para fazer isso, removemos todos os servidores de aplicativos não atualizados do balanceamento:
upstream backend {
ip_hash;
server backend1_nextcloud.example.com;
server backend2_nextcloud.example.com down;
server backend3_nextcloud.example.com down;
server backend4_nextcloud.example.com down;
}
O restante dos nós está sendo gradualmente atualizado e colocado em operação. Neste caso, a atualização occ não precisa ser realizada! Você só precisa substituir os arquivos php e salvar a configuração.
Ao fazer backup, você precisa interromper a replicação para o Slave e executar um despejo simultâneo de metadados do banco de dados simultaneamente com a criação de um instantâneo de arquivos no armazenamento. Você precisa armazená-los em pares. A recuperação deve ser realizada de forma semelhante a partir de um despejo de banco de dados e arquivos para o mesmo período. Caso contrário, a perda de dados é possível, pois o arquivo pode estar no armazenamento, mas não possui metadados no banco de dados.

