Configuração do nginx como proxy reverso para WordPress, Nextcloud e Proxmox

Nenhuma das publicações sobre instalação de WordPress ou Nextcloud aborda acesso via HTTPS ou certificados SSL, apenas HTTP.

Acontece que, na minha infraestrutura, isso é centralizado em uma instalação do nginx, atuando como proxy reverso. O servidor que hospeda o nginx e o servidor de OpenVPN são a mesma máquina: um VPS com 512 MB de RAM e 1vCPU.

O nginx recebe as requisições em HTTPS e as encaminha em HTTP* de forma segura para os outros servidores – clientes da VPN: WordPress, Nextcloud e Proxmox – 3 máquinas diferentes.

* Proxmox usa HTTPS por padrão mas com um certificado verificado por uma CA interna

Vantagens:

  • só é necessário gerenciar os certificados em um servidor, independente de quantos sites são.
  • as 3 máquinas diferentes poderiam estar em qualquer rede, qualquer lugar – isso é, se não fossem virtualizadas dentro do Proxmox, podendo até ser uma rede residencial que bloqueia tráfego de entrada (muito obrigado, Claro), basta se conectar na VPN.

Desvantagem:

  • existe um pouco de latência devido à distância entre as máquinas (Rio de Janeiro) e o VPS (São Paulo).

Ainda que fosse possível abrir as portas para a rede e o OpenVPN não fosse necessário, usar o nginx como um proxy reverso na mesma LAN ainda poderia ser vantajoso pelo o gerenciamento centralizado dos certificados SSL e monitoramento de logs de acesso.

Os arquivos de configuração do nginx para cada site devem ficar localizados em /etc/nginx/sites-available e para habilitá-los basta criar um symlink em /etc/nginx/sites-enabled com:

# ln -s /etc/nginx/sites-available/sua_config /etc/nginx/sites-enabled/

A primeira configuração recomendada é redirecionar todo o tráfego de entrada em HTTP para a porta segura HTTPS. No arquivo /etc/nginx/sites-enabled/default, configure o servidor padrão da seguinte forma:

server {
    listen 80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

Em todos os exemplos de configuração abaixo, substitua o nome do servidor (FQDN), o caminho para o certificado e chave SSL e o IP privado para onde deve ser encaminhada a solicitação.

Como mencionado, é possível usar a mesma porta para todos os servidores, como a porta padrão HTTPS, desde que cada um tenha o parâmetro server_name diferente, cada um com um nome de domínio (FQDN).

Configuração para o Proxmox:

upstream proxmox {
    server "seuproxmox.dominio.com";
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name seuproxmox.dominio.com;
    ssl_certificate /etc/letsencrypt/live/seu.dominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/seu.dominio.com/privkey.pem;
    proxy_redirect off;
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass https://10.8.0.2:8006;
        proxy_buffering off;
        client_max_body_size 0;
        proxy_connect_timeout  3600s;
        proxy_read_timeout  3600s;
        proxy_send_timeout  3600s;
        send_timeout  3600s;
    }
}

Para o Nextcloud:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/seu.dominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/seu.dominio.com/privkey.pem;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff";
    server_name seunextcloud.dominio.com;
    location / {
        proxy_pass http://10.8.0.3;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }
    send_timeout 1800;
}

Configurações adicionais são recomendadas no lado do servidor Nextcloud, no arquivo /var/www/nextcloud/config/config.php

  'trusted_proxies' =>
  array (
    0 => '10.8.0.1',
  ),
  'overwritehost' => 'seunextcloud.dominio.com',
  'overwriteprotocol' => 'https',
  'overwritecondaddr' => '^10\\.8\\.0\\.1$',
  'overwritewebroot' => '/',
  'overwrite.cli.url' => 'https://seunextcloud.dominio.com',

O nginx limita por padrão o corpo das requisições HTTP a 1 MB de tamanho, retornando o erro 413 para tentativas de upload de arquivos maiores que isso.

Essa configuração pode ser ajustada com os parâmetros a seguir no arquivo /etc/nginx/nginx.conf, devendo ser ajustada de acordo com a sua necessidade e a capacidade do seu servidor.

http {
	client_max_body_size 30M;
	client_body_buffer_size 30M;
}

Os aplicativos do Nextcloud, tanto para smartphone quanto desktop, usam o protocolo WebDAV, uma extensão do HTTP, que divide os arquivos em pedaços que são enviados em cada requisição. Ou seja, arquivos maiores que 30M podem ser enviados através dos aplicativos. Navegadores web, no entanto, não usam o mesmo protocolo, e podem acabar enviando os arquivos sem fragmentá-los.

Para o WordPress:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/seu.dominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/seu.dominio.com/privkey.pem;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff";
    server_name seuwordpress.dominio.com;
    location / {
        proxy_pass http://10.8.0.4;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }
    send_timeout 1800;
}

Configurações adicionais são requeridas no lado do servidor do WordPress, no arquivo /var/www/html/wp-config.php:

define('WP_HOME', 'https://seuwordpress.dominio.com');
define('WP_SITEURL', 'https://seuwordpress.dominio.com');

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}

Sugestão de configuração adicional para o WordPress – o WordPress não tem um mecanismo de proteção contra tentativas de acesso por força bruta. Para mitigar isso, além de usar boas senhas, você pode limitar o acesso por IP às localizações /wp-admin, /wp-login.php e /xmlrpc.php na configuração do proxy reverso adicionando essa configuração:

server {
    location ~* ^/(wp-admin|wp-login.php) {
        allow 186.205.1.165;    # seu IP de casa
        allow 191.252.110.50;    # seu IP do trabalho
        deny all;
        proxy_pass http://10.8.0.4;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /xmlrpc.php {
        deny all;
    }
}

Após configurado, reinicie o serviço.

# systemctl restart nginx

Caso ainda não tenha certificados SSL válidos, eles podem ser obtidos gratuitamente com a Let’s Encrypt, uma organização sem fins lucrativos, com o comando certbot. Primeiro, pare o serviço nginx, já que o certbot vai criar um processo que também vai escutar na porta 80. Então, use o comando nesse formato:

# certbot certonly --standalone -d seu.dominio.com -d seunextcloud.dominio.com -d seuproxmox.dominio.com -d seuwordpress.dominio.com

Siga os prompts do programa e, ao terminar, reinicie o nginx.service mais uma vez.

Caso esteja usando o proxy reverso para servidores dentro de uma VPN, você pode querer ver isso aqui.