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 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 512mb 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 na 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, logs de acesso e uso de múltiplos nomes de domínio em diferentes servidores pro mesmo IP na mesma porta.

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 é para receber a solicitação HTTP na porta 80 e redirecionar o cliente para fazer uma solicitação HTTPS na porta padrão 443.

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',

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 e /wp-login.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;
    }
}

Por conveniência, você também pode fazer o nginx escutar pra solicitações a HTTP na porta 80 e redirecionar todos os clientes para uma solicitação HTTPS:

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

Após configurado, inicie o serviço.

# systemctl enable --now 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, inicie o nginx.service novamente.

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