Sam4 ~ House
Sam4 ~ House

Arquitetura De Defesa Em Camadas Para Infraestruturas Hibridas

Uma abordagem prática utilizando VPN site-to-site, reverse proxy e mTLS

Recentemente participei de um projeto cujo objetivo era expor serviços web de um ambiente on-premise de forma segura.

O desafio, porém, não estava apenas na publicação dos serviços, mas nas limitações e particularidades da infraestrutura disponível.

O ambiente não possuía IP público e também não havia acesso ao roteador de borda, o que inviabilizava qualquer abordagem tradicional baseada em NAT, port forwarding ou exposição direta.

Diante desse cenário, a solução que foi elaborada deveria respeitar as restrições e, ao mesmo tempo, reduzir ao máximo a superfície de ataques por meio da empregabilidade de conceitos de arquiteturas de defesa em camadas (Defense in Depth).

Para o desenvolvimento deste projeto, foi adotada a arquitetura apresentada abaixo como modelo de solução.

Topologia Cloudflare Tunnel com mTLS e WireGuard

Essa abordagem parte de um princípio simples porém poderoso: nenhuma camada de segurança é suficiente sozinha.

Em vez de confiar em um único controle, a arquitetura é construída com múltiplas camadas independentes, onde cada uma atua mitigando um tipo específico de risco. Caso uma falhe, as demais continuam protegendo o ambiente.

Nesta solução, as camadas foram organizadas da seguinte forma:

  • 🔒 Camada de rede → VPN site-to-site com WireGuard, garantindo conectividade segura e privada

  • 🌐 Camada de exposição → Reverse Proxy hospedado em uma VPS, atuando como ponto único de entrada

  • 🚧 Camada de identidade e autenticação → mTLS (Mutual TLS), elevando a identidade para a camada de aplicação

  • ☁️ Camada perimetral → Cloudflare, fornecendo WAF, proteção contra DDoS, TLS gerenciado e controle de tráfego

O resultado é uma arquitetura onde nenhum serviço interno é exposto diretamente à internet, o acesso é sempre intermediado, autenticado e auditável, e a segurança não depende de um único mecanismo, mas do conjunto das camadas trabalhando em harmonia.

Como etapa inicial deste projeto, dei início à criação e à configuração da VPN utilizando o WireGuard, com o objetivo de estabelecer um túnel direto e seguro entre o ambiente local e a VPS.

Passo a Passo

Começamos atualizando os sistemas operacionais. Nesse cenário, eu estava utilizando o Debian 13 na VPS e uma distribuição baseada em Proxmox no homelab.

~# apt update

atualização

Agora, vamos iniciar a instalação do pacote principal do WireGuard:

~# apt install wireguard

atualização

O WireGuard utiliza criptografia assimétrica para validar identidades e criptografia simétrica para proteger o tráfego que passa pelo túnel.

Com o comando abaixo, vamos gerar o par de chaves do servidor para verificação de identidade entre os nós(Autenticação mútua). As chaves vão ficar salvas dentro do diretório /etc/wireguard/

~# wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

Com isso concluído, já podemos verificar se a criação foi realizada com êxito.

~# cat /etc/wireguard/server_private.key

atualização

~# cat /etc/wireguard/server_public.key

atualização

É nesta etapa da configuração que informamos ao WireGuard quais endereços de rede serão utilizados na VPN, quais nós farão parte do túnel e quais são as chaves públicas de cada um, estabelecendo assim a base para uma comunicação segura e organizada entre todos os pontos da rede.

Edite o arquivo principal da VPN:

~# nano /etc/wireguard/wg0.conf

atualização
atualização

Exemplo básico de configuração

[Interface]

Address = 10.3.1.1/24
ListenPort = 5555
PrivateKey = 

Habilitando o roteamento (NAT) ao subir a interface

Essa configuração é fundamental, pois sem ela o tráfego não conseguiria fluir corretamente entre os nós. Ao adicionarmos essas linhas no arquivo de configuração, o sistema passa a encaminhar todo o tráfego da interface da VPN para a interface física. Sem esse direcionamento, o tráfego saberia o destino, mas não o caminho para chegar até ele.

- PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; 
iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE

- PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; 
iptables -t nat -D POSTROUTING -o ens33 -j MASQUERADE

Obs: Troque o ens33 pelo nome correto de sua interface fisica.

Após a realização dessas edições, o arquivo de configuração final deverá ficar da seguinte forma:

atualização

Precisamos habilitar o IP Forwarding quando a máquina não é apenas um destino, mas precisa encaminhar pacotes para outra rede, ou seja, quando ela age como roteador/gateway.

Primeiro verifique se IP Forwarding já não esta habilitado.

~# sysctl net.ipv4.ip_forward

atualização

Se a saída for igual a 0 então siga para habilitar o roteamento de trafego no kernel do Linux.

~# sysctl -w net.ipv4.ip_forward=1

atualização

Para persistir após reboot, edite:

~# nano /etc/sysctl.conf

E garanta que exista a linha:

net.ipv4.ip_forward=1

atualização

Ativar o serviço no boot:

~# systemctl enable wg-quick@wg0

atualização

Iniciar a VPN:

~# systemctl start wg-quick@wg0

atualização

Realizada todas as configurações podemos validar com o comando abaixo se a interface está ativa.

~# systemctl status wg-quick@wg0

atualização

Verificar a interface de rede da VPN:

~# ip a

atualização

Verificar status dos peers WireGuard:

~# Wg

atualização

No lado do nosso homelab, podemos repetir todos os passos já realizados na VPS com exceção da parte de habilitar o roteamento (NAT) ao subir a interface na parte 4.

A principal diferença está na adição da seção de peers em cada arquivo de configuração da interface wg0.

Essa seção é responsável pela verificação de identidade entre os nós. Em ambos os lados da conexão, cada nó mantém a chave pública do outro, que será utilizada durante o processo de handshake, garantindo a autenticação segura e o estabelecimento confiável da sessão VPN.

Após reproduzirmos todos os passos anteriores, adicionamos a chave pública da VPS e ajustamos o nosso endereço IP dentro da VPN.

A seguir, estão descritas as informações que indicam a finalidade de cada campo da seção [Peer]:

[Peer]

PublicKey → Chave pública do peer remoto (VPS)

AllowedIPs → Define quais redes terão o tráfego encaminhado por esse peer

Endpoint → IP público e porta do peer remoto separados por “:”

PersistentKeepalive → Intervalo (em segundos) para manter a conexão ativa, útil atrás de NAT

Agora, edite o arquivo principal da VPN no Homelab:

~# nano /etc/wireguard/wg0.conf

atualização

Observação: a porta deve ser preenchida com o mesmo valor definido anteriormente nas configurações da interface da VPS.


Adicionamos a chave pública da outra extremidade do túnel(Homelab). Dessa forma, cada ponta do túnel passa a possuir a chave pública da outra, utilizando-a como forma de identificação e validação de que a comunicação está sendo realizada com o peer correto.

Sendo os campos definidos da seguinte forma:

[Peer]

PublicKey = Chave pública da Homelab

AllowedIPs = Endereço IP da Homelab na VPN. Ex: 10.8.0.2/32

atualização

Agora que ambas as extremidades do túnel possuem a chave pública uma da outra, estamos prontos para estabelecer a conexão por meio do túnel.

Feito isso, podemos utilizar o comando wg na VPS para verificar se o peer foi criado com sucesso.

~# Wg

atualização

Ao adicionar o peer na VPS, o WireGuard estabelece a conexão automaticamente. Não há necessidade de um comando manual, pois, estando as chaves públicas, os IPs permitidos e o endpoint corretamente configurados em ambas as pontas, o túnel é formado de forma automática.


A adoção de um proxy reverso resolve algumas limitações desse projeto como a ausência de IP público ou de um roteador de borda, ao mesmo tempo em que agrega ganhos significativos de segurança.

Ao manter o ambiente doméstico isolado da internet e utilizar uma VPS como ponto único de entrada, obtém-se uma arquitetura mais segura, com todo o tráfego protegido por criptografia via WireGuard. Além da VPS poder atuar como camada de otimização, oferecendo cache, compressão e suporte a protocolos modernos como HTTP/2 e HTTP/3.

À também a flexibilidade para expor múltiplos serviços internos sem abrir portas no roteador, além de tornar essa abordagem uma base sólida para a adoção de princípios de Zero Trust, com segurança e controle por padrão.

Primeiramente, vamos instalar o Nginx com o comando abaixo:

~# apt install nginx

Com o Nginx devidamente instalado, podemos prosseguir com a criação do arquivo de configuração responsável por encaminhar o tráfego HTTPS de forma segura para o ambiente do homelab.

~# nano /etc/nginx/sites-available/homelab.conf

Exemplo de configuração:

server {
    listen 80;
    server_name seudominio.com;

    location / {
        proxy_pass http://10.10.0.2:8080;
        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;
    }
}

atualização

Onde:

  • seudominio.com é o domínio público.
  • 10.10.0.2 é o IP do homelab no túnel WireGuard.
  • 1313 é a porta do serviço interno(Homelab).

Agora, vamos criar um link simbólico para ativar o site:

~# ln -s /etc/nginx/sites-available/homelab.conf /etc/nginx/sites-enabled/

Podemos confirmar a criação por meio do comando abaixo:

~# ls /etc/nginx/sites-enabled/

atualização

Após a conclusão dessas etapas, podemos testar a configuração e recarregar o NGINX para aplicar as alterações.

Teste a configuração para verificar se está correta:

~# nginx -t

atualização

Caso a configuração não apresente nenhum erro, recarregue o serviço para que as alterações entrem em vigor.

~# systemctl reload nginx

Para verificar se o serviço está funcionando corretamente podemos utilizar o comando abaixo:

~# systemctl status nginx

atualização

Nesta etapa da configuração, assumirei que o domínio já foi previamente criado na Cloudflare, a fim de manter este tutorial mais objetivo e sucinto.

A primeira etapa a ser realizada consiste no download e na instalação dos pacotes da Cloudflare em nossa VPS.

O cloudflared é o cliente de linha de comando responsável por estabelecer a conexão segura entre o servidor e a rede da Cloudflare. Sem ele instalado, o terminal retornará o erro “command not found”.

~# curl -L –output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb

~# dpkg -i cloudflared.deb

atualização

Agora, vamos criar o túnel mTLS. Essa etapa é necessária para podermos estabelecer uma conexão segura e autenticada entre o servidor(VPS) e a Cloudflare, garantindo que apenas máquinas autorizadas possam se comunicar, sem expor o servidor diretamente à internet.

Antes de criarmos o túnel precisaremos de autenticar a VPS na conta da Cloudflare.

~# cloudflared tunnel login

atualização

Esse comando irá gerar um link para autenticação. Acesse-o em um navegador, realize o login na Cloudflare e selecione o domínio desejado.

atualização
atualização
atualização

Após a conclusão, será realizado automáticamente o download do arquivo de certificado (cert.pem) para a sua máquina.

É possível verificar se o arquivo foi corretamente baixado no diretório /root/.cloudflared.

~# cat cert.pem

atualização
atualização

Para a criação do túnel, pode-se utilizar o comando abaixo. Esse processo irá gerar um identificador único (ID) e um arquivo .json contendo as credenciais.

~# cloudflared tunnel create meu-tunel

É possível verificar se o arquivo foi corretamente criado no diretório /root/.cloudflared.

atualização

~# cat {seu ID}.json

atualização

Com o tunel criado, precisamos de configurar o DNS para associar o domínio ao túnel criado, permitindo que a Cloudflare direcione o tráfego corretamente.

O comando abaixo cria automaticamente um registro CNAME no painel da Cloudflare, apontando para o túnel.

~# cloudflared tunnel route dns meu-tunel meusite.seudominio.com

A partir de agora, a Cloudflare consegue direcionar o tráfego corretamente para a VPS.

Podemos validar se a criação foi realizada com sucesso na Cloudflare, em DNS > Registros.

atualização

Agora, precisaremos de criar um arquivo chamado config.yml dentro de /root/.cloudflared/):

~# nano /etc/cloudflared/config.yml

tunnel: 
credentials-file: /root/.cloudflared/.json

ingress:
  - hostname: meusite.seudominio.com
  - service: https://localhost:443
  - service: http_status:404

atualização

Com o túnel criado e o DNS devidamente configurado, basta iniciarmos o túnel para que ele fique online

~# systemctl enable cloudflared

~# systemctl start cloudflared

Após concluir essas etapas, é possível validar se o serviço está funcionando corretamente.

~# systemctl status cloudflared

atualização

Nesta etapa, o servidor(VPS) será configurado para aceitar apenas o tráfego proveniente do túnel, garantindo que somente conexões autorizadas sejam processadas.

Vamos configurar o NGINX na VPS para validar o mTLS para deixar passar somente quem apresentar certificado válido (Cloudflare).

Com isso, o proxy reverso passa a confiar exclusivamente no tráfego proveniente do túnel Cloudflared, bloqueando qualquer acesso direto ou não autorizado.

No NGINX, podemos adicionar a seguinte configuração no proxy reverso:

~# cd /etc/nginx/sites-available

~# nano site.conf

server {
    listen 443;
    server_name example.com www.example.com;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src https: data: 'self' 
	'unsafe-inline' 'unsafe-eval'" always;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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 https;
    }
}

atualização

Agora, podemos recarregar as configurações do NGINX para validar se não há erros de sintaxe ou configuração:

~# systemctl reload nginx

Se nenhum erro for apresentado, significa que as configurações estão corretas e já podemos reiniciar o serviço normalmente para aplicar as mudanças por completo:

~# systemctl restart nginx

Podemos alterar a utilização do TLS no modo Strict na Cloudflare para garantir um alto nível de segurança na comunicação. Esse modo exige que o servidor de origem(VPS) possua um certificado TLS válido e confiável, assegurando que a conexão entre o Cloudflare e o servidor seja totalmente criptografada e autenticada. Dessa forma, evita-se o uso de certificados inválidos ou inseguros, reduzindo o risco de ataques de interceptação de dados e adotando uma configuração alinhada às boas práticas de segurança para ambientes de produção.

Primeiramente, acessamos o menu SSL/TLS > Overview e, em seguida, clicamos na opção Configure.

atualização

Na próxima etapa, selecionamos a opção Strict, garantindo uma comunicação segura e validada entre o Cloudflare e o servidor de origem.

atualização

Com todas essas configurações concluídas, podemos fechar no firewall todas as portas que não serão utilizadas, reduzindo significativamente os vetores de ataque ao servidor.

No meu caso, mantive apenas a porta UDP da VPN e a porta 22, destinada ao acesso via SSH, utilizando o parâmetro limit para controle. Para isso, estou utilizando o firewall UFW (Uncomplicated Firewall).

Caso o UFW ainda não esteja instalado, podemos instalá-lo com o comando abaixo:

~# apt install ufw

Em seguida, criamos as regras para permitir apenas as portas necessárias:

~# ufw limit ssh

~# ufw allow {Porta da VPN}/udp

Dessa forma, garantimos que somente os serviços essenciais permaneçam acessíveis, aumentando a segurança do ambiente.

Agora, vamos bloquear todo o restante do tráfego, definindo as políticas padrão do UFW como deny:

~# ufw default deny incoming

~# ufw default allow outgoing

Onde:

ufw default deny incoming

Bloqueia todo tráfego de entrada por padrão, exceto aquelas que liberamos explicitamente.

ufw default allow outgoing

Permite todo tráfego de saída por padrão.

Depois, podemos ativar o firewall (se ainda não estiver ativo):

~# ufw enable

Podemos verificar e confirmar as regras configuradas utilizando o comando abaixo:

~# ufw status

atualização