Deploy com Kamal

Published on: 2026-09-27

Para o blog em si, em termos de seu funcionamento, não faltam exemplos bons nas interwebs. Por exemplo, temos o post do blog do Dashbit, e também essa lição sobre nimble_publisher do Elixir School.

Para servir o blog com o bandit, o que eu fiz foi apontar a configuração do bandit para um router, e criar as rotas específicas que eu precisava. O código abaixo exemplifica um pouco isso:

# Save this to a file, ie., server.exs, and run with "elixir server.exs"

Mix.install(
  [
    {:bandit, "~> 1.12"}
  ]
)

defmodule Server.Router do
  use Plug.Router

  plug(:match)
  plug(:dispatch)

  get "/" do
    send_resp(conn, 200, "hello!")
  end

  get "/posts/:id" do
    # This is just a super simple example, but in a nutshell you get the post and then render
    # post = Blog.get_post_by_id!(id)
    # send_resp(conn, 200, post)
  end

  match _ do
    send_resp(conn, 404, "oops")
  end
end

defmodule Server.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Bandit, plug: Server.Router}
    ]

    opts = [strategy: :one_for_one, name: Server.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

{:ok, _} = Server.Application.start(:normal, [])

Process.sleep(:infinity)

Por padrão o bandit irá rodar o servidor na porta 4000; abra http://localhost:4000 para ver o resultado.

Kamal

Utilizar o Kamal é, de certa forma, bastante simples considerando o meu caso (somente um site estático, sem outros serviços como banco de dados). Eu tive que fazer alguns ajustes dado a minha escolha pelo Hetzner e por não ter um endereço IPV4 para o servidor.

O Kamal leva em conta que a sua aplicação esteja dockerizada e servida em algum repositório de containers, como por exemplo o Docker Hub. Não vou entrar em detalhes aqui pois já existem diversos exemplos bons na internet, inclusive o próprio Phoenix tem um comando mix para gerar um Dockerfile bem legal.

O primeiro passo é ter um servidor acessível via ssh, e um usuário com as permissões corretas. Comprei um servidor na Hetzner, o tier mais barato, que já dispõe de um endereço IPV6 (endereços IPV4 tem um custo extra).

Certifique-se que o servidor esteja acessível via ssh. Para facilitar eu criei uma entrada em ~/.ssh/config para apenas usar ssh hetzer e entrar como root no servidor.

Outro problema que tive foi em relação ao IPV6. No momento que eu estava configurando o deploy, meu roteador não estava com suporte a IPV6, assim eu não conseguia acessar o servidor diretamente. Eu usei o Cloudlare WARP para rotear o tráfego de modo que a "origem" também fosse IPV6:

desktop --(IPv4, túnel WARP)--> Cloudflare --(IPv6)--> servidor

Uma vez que a conexão ssh estava correta, Docker Hub configurado, eu consegui executar o kamal setup. Caso você queira que o Kamal forneça HTTPS via Let's Encrypt, certifique-se de ligar a config ssl no arquivo de deploy.