Arquitetura De Defesa Em Camadas Para Infraestruturas Hibridas
Uma abordagem prática utilizando VPN site-to-site, reverse proxy e mTLS
Índice
- Introdução
- Arquitetura
- Solução
- Atualizar o sistema
- Instalar o WireGuard
- Gerar as chaves criptográficas do servidor
- Criar o arquivo de configuração da interface (wg0)
- Habilitar IP Forwarding
- Subir a interface WireGuard
- Validando a interface
- Ingressando na VPN pela outra ponta
- Retornando à VPS
- Configurando o Reverse Proxy
- Configurando o Cloudflare Tunnel (VPS)
- Criando o Túnel mTLS
- Controle de Acesso: Aceitando Somente Tráfego do Túnel Cloudflared (mTLS)
- Hardening: Fechando as portas de casa
Introdução
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).
Arquitetura
Para o desenvolvimento deste projeto, foi adotada a arquitetura apresentada abaixo como modelo de solução.

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.
Solução
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
1. Atualizar o sistema
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

2. Instalar o WireGuard
Agora, vamos iniciar a instalação do pacote principal do WireGuard:
~# apt install wireguard

3. Gerar as chaves criptográficas do servidor
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

~# cat /etc/wireguard/server_public.key

4. Criar o arquivo de configuração da interface (wg0)
É 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


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:

5. Habilitar IP Forwarding
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

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

Para persistir após reboot, edite:
~# nano /etc/sysctl.conf
E garanta que exista a linha:
net.ipv4.ip_forward=1

6. Subir a interface WireGuard
Ativar o serviço no boot:
~# systemctl enable wg-quick@wg0

Iniciar a VPN:
~# systemctl start wg-quick@wg0

7. Validando a interface
Realizada todas as configurações podemos validar com o comando abaixo se a interface está ativa.
~# systemctl status wg-quick@wg0

Verificar a interface de rede da VPN:
~# ip a

Verificar status dos peers WireGuard:
~# Wg

8. Ingressando na vpn pela outra ponta
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

Observação: a porta deve ser preenchida com o mesmo valor definido anteriormente nas configurações da interface da VPS.
9. Retornando à 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

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

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.
10. Configurando o Reverse Proxy
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;
}
}

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/

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

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

11. Configurando o Cloudflare Tunnel (VPS)
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

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

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.



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


12. Criando o Túnel mTLS
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.

~# cat {seu ID}.json

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.

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

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

13. Controle de Acesso: Aceitando Somente Tráfego do Túnel Cloudflared (mTLS)
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;
}
}

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.

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

14. Hardening: Fechando as portas de casa
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

