<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:webfeeds="http://webfeeds.org/rss/1.0"><channel><title>proxyjump | Self-Hosted!</title><link>https://blog.brumarino.com/tags/proxyjump/</link><description>Post novo no “Rack” todo dia às 7AM. Proxmox, rede, backup, UPS, IA e tudo o que tenho estudado.</description><language>pt-BR</language><managingEditor>Bruno Marino</managingEditor><image><url>https://blog.brumarino.com/brand/icon-144.png</url><title>proxyjump | Self-Hosted!</title><link>https://blog.brumarino.com/tags/proxyjump/</link><width>144</width><height>144</height></image><webfeeds:icon>https://blog.brumarino.com/brand/icon-192.png</webfeeds:icon><webfeeds:logo>https://blog.brumarino.com/brand/symbol.svg</webfeeds:logo><webfeeds:accentColor>2B3036</webfeeds:accentColor><lastBuildDate>Thu, 15 Oct 2026 07:00:00 -0300</lastBuildDate><atom:link href="https://blog.brumarino.com/tags/proxyjump/index.xml" rel="self" type="application/rss+xml"/><item><title>SSH sem porta 22 aberta: Cloudflare Tunnel e ProxyJump</title><link>https://blog.brumarino.com/ssh-cloudflare-tunnel-proxyjump/</link><pubDate>Thu, 15 Oct 2026 07:00:00 -0300</pubDate><guid>https://blog.brumarino.com/ssh-cloudflare-tunnel-proxyjump/</guid><category>Rede e acesso</category><description>O fail2ban não deu conta dos bots na porta 22. O que resolveu foi tirar o SSH da internet: entrada pelo Cloudflare Tunnel e ProxyJump para o resto.</description><content:encoded><![CDATA[<p>Quem deixa a porta 22 aberta para a internet conhece a cena: o log de autenticação enche de tentativas de login vindas do mundo inteiro, o tempo todo. Eu sofri bastante com isso. Instalei o fail2ban, coloquei uma aplicação para monitorar os acessos e gerar relatórios dos bloqueios, e mesmo assim os bots continuavam batendo.</p>
<p>O que resolveu de verdade não foi bloquear melhor, foi <strong>parar de expor a porta</strong>. Hoje o meu SSH entra só pelo Cloudflare Tunnel e, de lá, eu pulo para as outras máquinas com <code>ProxyJump</code>. Neste post mostro como montar esse esquema.</p>
<h2 id="por-que-o-fail2ban-não-basta">Por que o fail2ban não basta <a class="anchor" href="#por-que-o-fail2ban-n%c3%a3o-basta" aria-label="Link para esta seção">#</a></h2>
<p>O fail2ban lê os logs e bane, no firewall, os IPs que erram a senha várias vezes. Ele funciona e ajuda, mas tem um limite: ele <strong>reage</strong> a ataques que já estão chegando. Com a porta aberta, cada IP novo tem direito a algumas tentativas antes do banimento, e existem muitos IPs novos.</p>
<p>A solução mais limpa é não ter porta nenhuma para o bot encontrar.</p>
<h2 id="como-fica-o-desenho">Como fica o desenho <a class="anchor" href="#como-fica-o-desenho" aria-label="Link para esta seção">#</a></h2>
<p>O caminho de um acesso meu, de fora de casa, fica assim:</p>
<ol>
<li>O meu notebook chama <code>ssh</code> normalmente.</li>
<li>Um <code>ProxyCommand</code> no <code>~/.ssh/config</code> faz o <code>cloudflared</code> levar a conexão até a Cloudflare.</li>
<li>A Cloudflare entrega a conexão pelo tunnel ao <code>cloudflared</code> que roda num container LXC no meu Proxmox.</li>
<li>O <code>cloudflared</code> repassa para a porta 22 do <strong>jump server</strong>, a única máquina que recebe SSH de fora.</li>
<li>Do jump server, o <code>ProxyJump</code> me leva a qualquer outro container da rede.</li>
</ol>
<p>Como o tunnel é uma conexão de <strong>saída</strong> do meu homelab para a Cloudflare, não preciso de nenhum redirecionamento de porta no roteador. Para quem varre a internet atrás da porta 22, o meu IP simplesmente não tem SSH.</p>
<figure class="prose-figure">
  <img src="/ssh-cloudflare-tunnel-proxyjump/cloudflare-tunnel-diagrama_hu_90a9a400f1b96915.webp" alt="Diagrama da Cloudflare: o navegador chega à rede da Cloudflare, que entrega a requisição pelo tunnel ao cloudflared rodando no servidor, que repassa ao serviço local" loading="lazy" width="1400" height="873"><figcaption>Como funciona o Cloudflare Tunnel. Diagrama: Cloudflare (CC BY 4.0).</figcaption>
</figure><h2 id="lado-do-servidor-a-rota-no-tunnel">Lado do servidor: a rota no tunnel <a class="anchor" href="#lado-do-servidor-a-rota-no-tunnel" aria-label="Link para esta seção">#</a></h2>
<p>Considerando que você já tem um Cloudflare Tunnel funcionando, o passo é publicar o SSH como uma rota. Segundo a documentação da Cloudflare, no painel:</p>
<ol>
<li>Abra o tunnel em <strong>Networking &gt; Tunnels</strong> e vá na aba <strong>Routes</strong>.</li>
<li>Clique em <strong>Add route</strong> e escolha <strong>Published application</strong>.</li>
<li>Defina um subdomínio, por exemplo <code>ssh.seudominio.com</code>.</li>
<li>Em <strong>Service</strong>, escolha <strong>SSH</strong> e informe o destino. Use <code>localhost:22</code> se o <code>cloudflared</code> roda na mesma máquina do SSH, ou <code>IP-do-servidor:22</code> se roda em outra, como é o meu caso com o <code>cloudflared</code> num container separado.</li>
</ol>
<aside class="alert alert--important">
  <p class="alert__title">Importante</p>
  <p>A Cloudflare recomenda proteger essa rota com uma aplicação do <strong>Cloudflare Access</strong>, exigindo login antes de a conexão chegar ao seu servidor. Sem isso, o tunnel esconde a porta, mas qualquer um que descubra o subdomínio ainda chega até a tela de senha do SSH.</p>
</aside><h2 id="lado-do-cliente-o-proxycommand">Lado do cliente: o ProxyCommand <a class="anchor" href="#lado-do-cliente-o-proxycommand" aria-label="Link para esta seção">#</a></h2>
<p>No computador de onde você acessa, instale o <code>cloudflared</code> e adicione ao <code>~/.ssh/config</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Host ssh.seudominio.com
</span></span><span class="line"><span class="cl">  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
</span></span></code></pre></div><p>O caminho do <code>cloudflared</code> muda conforme o sistema e o gerenciador de pacotes. Confira com <code>which cloudflared</code>.</p>
<p>A partir daí, <code>ssh usuario@ssh.seudominio.com</code> funciona como qualquer SSH, só que passando pelo tunnel. Se a rota estiver protegida pelo Access, o <code>cloudflared</code> abre o navegador para você fazer login antes da sessão começar.</p>
<h2 id="proxyjump-um-só-ponto-de-entrada">ProxyJump: um só ponto de entrada <a class="anchor" href="#proxyjump-um-s%c3%b3-ponto-de-entrada" aria-label="Link para esta seção">#</a></h2>
<p>Com o jump server acessível pelo tunnel, não faz sentido publicar cada container. O OpenSSH resolve isso com <code>ProxyJump</code>: você pede para entrar numa máquina interna e ele passa primeiro pelo jump server, de forma transparente.</p>
<p>Um <code>~/.ssh/config</code> nessa lógica fica assim (nomes e IPs são exemplos):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Host jump
</span></span><span class="line"><span class="cl">  HostName ssh.seudominio.com
</span></span><span class="line"><span class="cl">  User bruno
</span></span><span class="line"><span class="cl">  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Host app-*
</span></span><span class="line"><span class="cl">  User root
</span></span><span class="line"><span class="cl">  ProxyJump jump
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Host app-blog
</span></span><span class="line"><span class="cl">  HostName 192.168.1.50
</span></span></code></pre></div><p>Com isso, <code>ssh app-blog</code> sai do meu notebook, atravessa o tunnel até o jump server e de lá chega ao container do blog, tudo num comando só. Para uma conexão pontual, o equivalente na linha de comando é <code>ssh -J jump root@192.168.1.50</code>.</p>
<p>Esse desenho tem um bônus: toda conexão externa passa pelo mesmo lugar. É no jump server que fica a monitoria de acessos, então tenho um único ponto para olhar.</p>
<h2 id="endurecendo-o-jump-server">Endurecendo o jump server <a class="anchor" href="#endurecendo-o-jump-server" aria-label="Link para esta seção">#</a></h2>
<p>Mesmo escondido, o ponto de entrada merece cuidado. No <code>sshd_config</code> do jump server, o básico é:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">PasswordAuthentication no
</span></span><span class="line"><span class="cl">PermitRootLogin no
</span></span></code></pre></div><p>Com chave SSH obrigatória e root bloqueado, mesmo alguém que chegue até o servidor precisa da sua chave privada. Depois de editar, valide a configuração antes de reiniciar, para não se trancar para fora:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sshd -t <span class="o">&amp;&amp;</span> systemctl reload ssh
</span></span></code></pre></div><aside class="alert alert--caution">
  <p class="alert__title">Cuidado</p>
  <p>Mantenha uma sessão SSH aberta enquanto testa as mudanças no <code>sshd_config</code> e só feche depois de confirmar que uma conexão nova funciona. Se algo der errado, você ainda tem por onde corrigir.</p>
</aside><h2 id="resumindo">Resumindo <a class="anchor" href="#resumindo" aria-label="Link para esta seção">#</a></h2>
<ul>
<li><strong>O fail2ban reage; esconder a porta evita.</strong> Os dois podem conviver, mas a porta fechada resolve a raiz do problema.</li>
<li><strong>O Cloudflare Tunnel</strong> publica o SSH sem redirecionamento de porta no roteador.</li>
<li><strong>Proteja a rota com Cloudflare Access</strong> para exigir login antes do SSH.</li>
<li><strong>ProxyJump</strong> dá um único ponto de entrada para todas as máquinas internas.</li>
<li><strong>Chave obrigatória e root bloqueado</strong> no jump server.</li>
</ul>
<p>Desde que o SSH passou a entrar só pelo tunnel, os bots sumiram do meu log. Não porque eu bloqueio melhor, mas porque não há mais nada para eles encontrarem.</p>
]]></content:encoded></item></channel></rss>