por Tiago Silva

Visão geral

Infográfico da arquitetura do site, desde o desenvolvimento local e a validação no GitHub até o deploy na VPS, os serviços Docker e o acesso por navegadores e dispositivos IoT.

O infográfico apresenta as principais tecnologias e os fluxos que compõem a arquitetura do site, desde o desenvolvimento e a validação do código até o deploy na VPS, a disponibilização do site, o acesso aos serviços privados e a comunicação com clientes MQTT.

Desenvolvimento local

O ponto de partida é o monorepo MyVPS, acessível no meu computador em C:\Projects\MyVPS. Nele ficam o código-fonte do site, as configurações de infraestrutura e os scripts de implantação. O acesso e a edição são feitos com o VS Code.

O Jekyll é o gerador do site. Ele transforma arquivos Markdown, layouts e assets em HTML estático. Durante o desenvolvimento, um servidor local é utilizado para revisar conteúdo e alterações sem envolver a VPS.

O Git, além de controlar e versionar as alterações do código, permite sincronizar as cópias do repositório no meu computador e na VPS por meio do GitHub.

O PowerShell é utilizado como interface para o Git e permite executar scripts de automação. O deploy.ps1 conecta-se à VPS por SSH e aciona o processo de produção; o deploy-local.ps1 inicia um servidor Jekyll local na porta 4000.

GitHub e integração contínua

O GitHub é o repositório remoto e a referência compartilhada do código. Depois de um commit e um push, a mesma versão passa a estar disponível para validação e para a VPS.

O GitHub Actions executa a integração contínua, ou CI. Em um ambiente Linux limpo, ele baixa o repositório, prepara Ruby 3.4, instala as dependências e tenta construir o site Jekyll. Isso verifica se o conteúdo enviado continua gerando um site válido sem depender da configuração do computador de desenvolvimento.

O resultado dessa etapa é uma confirmação de qualidade, não uma publicação. O workflow não possui acesso à VPS, não abre uma sessão SSH e não substitui os arquivos de produção.

VPS Linux e deploy

A VPS é o servidor Linux que mantém a aplicação disponível continuamente. A distribuição utilizada é o Debian 13. Ela concentra a cópia local do repositório usada pelo deploy, os containers permanentes, os arquivos publicados, os dados operacionais e os segredos de produção.

O deploy é iniciado localmente com:

.\controlandoeletrons-site\deploy.ps1

Esse script usa SSH, o protocolo de acesso remoto seguro, para pedir à VPS que execute /opt/MyVPS/tools/deploy. O computador não envia diretamente seus arquivos locais; a VPS atualiza sua própria cópia do repositório com os commits que já chegaram ao GitHub.

O pipeline remoto segue sete passos principais:

  1. faz pull dos commits mais recentes do GitHub para a cópia do projeto na VPS;
  2. sincroniza o site e a configuração de infraestrutura;
  3. valida as configurações antes de aplicá-las;
  4. cria ou atualiza os serviços com Docker Compose;
  5. constrói o site Jekyll em um container temporário Ruby;
  6. publica o HTML estático gerado;
  7. verifica os endpoints e o estado dos containers.

O rsync faz a sincronização entre a cópia do repositório na VPS e os diretórios usados em produção. Essa separação permite copiar apenas arquivos versionados e preservar certificados, credenciais, bancos locais e outros dados que não pertencem ao Git.

Docker e os serviços permanentes

O Docker isola cada serviço em um container com suas dependências. O Docker Compose descreve como esses containers são iniciados, quais portas publicam, quais diretórios montam e de qual rede participam.

Caddy, Authelia, Node-RED e Mosquitto possuem projetos Compose separados. Isso permite atualizar um serviço sem transformar toda a infraestrutura em uma única unidade. Os quatro participam da rede Docker controlandoeletrons, pela qual podem se localizar por nome e conversar sem expor toda comunicação à Internet.

Tecnologia Papel na arquitetura Relação com os demais componentes
Caddy servidor web, HTTPS e proxy reverso recebe o tráfego web, serve arquivos estáticos e encaminha requisições ao Authelia ou ao Node-RED
Authelia autenticação central dos serviços privados o Caddy consulta o Authelia antes de liberar Console e MQTT Web
Node-RED automações, fluxos e APIs recebe do Caddy as requisições dinâmicas autorizadas e acessa o broker para consumir mensagens dos clientes MQTT
Mosquitto broker de mensagens MQTT recebe diretamente as conexões dos dispositivos IoT nas portas 1883 e 8883

O Caddy é a entrada do ambiente web. Ele gerencia HTTPS, publica o site principal e decide qual serviço deve tratar cada domínio ou caminho. Como o site Jekyll já foi convertido em HTML, o Caddy pode servi-lo diretamente, sem executar Ruby a cada acesso.

O Authelia centraliza o login. Para uma área privada, o Caddy primeiro pergunta ao Authelia se a sessão é válida. Se não for, o usuário é direcionado ao login; se for, a requisição continua para o conteúdo ou serviço solicitado.

O Node-RED implementa as partes dinâmicas: fluxos de automação, integrações e APIs. Sua porta 1880 fica restrita ao host e à rede interna; o acesso externo normal acontece por meio do Caddy e, nas áreas privadas, depois da autenticação. Ele não participa mais do armazenamento ou da publicação OTA.

O Mosquitto implementa um protocolo diferente do tráfego web. Ele é o broker MQTT usado pelos dispositivos para publicar e receber mensagens. Por isso, os clientes IoT chegam diretamente às portas 1883 (MQTT) ou 8883 (MQTT sobre TLS), sem passar pelo Caddy ou pelo Authelia. As contas e permissões dos clientes precisam ser criadas e configuradas, com usuário e senha, pelo Console MQTT.

Files e distribuição de firmware OTA

O Files não é um container nem uma aplicação. Ele é composto por:

  • Workspace local — MyVPS/controlandoeletrons-files: local onde os firmwares são organizados por cliente, projeto e canal;
  • Script de publicação — deploy-files.ps1: valida a estrutura local, gera os manifestos e envia os firmwares para a VPS por SSH;
  • Diretório na VPS — /opt/controlandoeletrons-files/ota: armazena o snapshot de firmwares publicado pelo script;
  • Caddy: atua como servidor estático e entrega os manifestos e arquivos .bin aos dispositivos.

O serviço não possui página inicial, upload pelo navegador, listagem de arquivos, integração com o Node-RED ou autenticação pelo Authelia. Os arquivos são organizados diretamente no computador, de forma estruturada:

controlandoeletrons-files/
└── CompanyA/
    └── ProjectB/
        ├── .ota-key
        ├── dev/
        │   ├── firmware.bin
        │   ├── manifest.json
        │   └── ota-urls.txt
        ├── beta/
        │   ├── firmware.bin
        │   ├── manifest.json
        │   └── ota-urls.txt
        └── stable/
            ├── firmware.bin
            ├── manifest.json
            └── ota-urls.txt

O arquivo .ota-key deve ser criado e preenchido com um UUID v4 aleatório. Ele identifica o projeto e é compartilhado por seus três canais: quem conhece a chave de ProjectB consegue acessar dev, beta e stable desse projeto, mas não os projetos dos demais clientes. Chaves e binários são versionados pelo Git junto com a estrutura do projeto.

Inicialmente, basta colocar o firmware.bin na pasta do canal. Ao validar ou publicar, o script cria na mesma pasta:

  • manifest.json: metadados derivados do binário, incluindo tamanho, SHA-256 e endereço de download;
  • ota-urls.txt: os endereços completos do manifesto e do binário que podem ser embarcados ou provisionados na placa.

Ao executar deploy-files.ps1, o script valida a árvore, calcula tamanho e SHA-256 de cada binário, gera os manifestos e envia um snapshot por SSH. A VPS valida novamente o pacote, guarda a publicação anterior para rollback e ativa o novo diretório. Com o script, ao remover arquivos localmente, também remove-se o snapshot do servidor.

O manifesto será gerado automaticamente pelo script:

{
  "sha256": "sha256-do-binario",
  "size": 1048576,
  "file": "https://files.controlandoeletrons.com.br/ota/CompanyA/ProjectB/stable/{chave}/firmware.bin"
}

O manifesto contém somente as informações necessárias para a atualização:

  • sha256: identifica o conteúdo publicado e permite conferir sua integridade;
  • size: informa quantos bytes tem o arquivo;
  • file: fornece o endereço exato do binário.

A placa pode usar essas duas rotas de maneiras diferentes para realizar o GET:

  • GET direto em firmware.bin: o Caddy responde imediatamente com o conteúdo do binário. Não há redirecionamento nem consulta ao manifesto.
  • GET em manifest.json: o Caddy devolve somente o JSON. Essa resposta não redireciona automaticamente. A placa interpreta os metadados, decide se há uma atualização e então faz uma segunda requisição GET para o endereço do campo file.

Para verificações periódicas, consultar o manifesto oferece três vantagens: a resposta é muito menor que o firmware; o sha256 permite descobrir se o conteúdo mudou antes do download; e size e sha256 permitem validar o binário recebido antes de instalá-lo. O acesso direto ao .bin é útil quando a atualização já foi decidida por outro mecanismo, como um comando MQTT.

A resposta binária usa application/octet-stream e recebe o Content-Length do servidor de arquivos. Não há gzip, página HTML, cookie ou cabeçalho de autenticação. Os diretórios não são listados, e qualquer outro caminho retorna 404. A chave na URL é uma credencial compartilhada pelo projeto e não deve aparecer em logs. Como ela é intencionalmente versionada, o repositório precisa permanecer privado e o acesso ao Git também concede acesso aos canais OTA.

Esse modelo não usa certificados de cliente nem mTLS. O HTTPS comum continua necessário para a placa autenticar a VPS e para impedir que a chave, o manifesto e o firmware trafeguem abertamente pela rede.

Build do site e armazenamento

Jekyll não é um serviço permanente nessa arquitetura. Durante o deploy, um container temporário baseado em ruby:3.4 gera o site e outro valida o resultado. Ao final, os containers temporários são removidos e somente o HTML publicável permanece.

Os dados da VPS são separados conforme sua função:

  • HTML estático: resultado do build Jekyll, montado pelo Caddy em modo somente leitura;
  • arquivos e firmware: snapshot OTA enviado diretamente do workspace local e montado no Caddy em modo somente leitura;
  • volumes: dados persistentes dos containers, preservados quando um serviço é recriado;
  • certificados e segredos: credenciais mantidas somente na VPS e excluídas da sincronização com o Git.

Essa separação permite atualizar código e containers sem incorporar dados de produção às imagens Docker e sem publicar credenciais no repositório.

Responsabilidades bem separadas

Cada tecnologia resolve uma parte específica do sistema: Jekyll gera o site, Git e GitHub controlam suas versões, GitHub Actions valida, PowerShell e SSH acionam o deploy, Linux hospeda o ambiente, Docker organiza os processos, Caddy recebe o tráfego web, Authelia autentica, Node-RED executa automações e Mosquitto transporta mensagens MQTT. Files combina o workspace local, os scripts de publicação, o armazenamento da VPS e o Caddy para distribuir firmwares sem uma aplicação administrativa.

Essa divisão torna o fluxo mais fácil de acompanhar e limita o impacto de uma falha. Um problema de build pode ser investigado no Jekyll ou na CI; um problema de login, no Authelia; uma falha de rota, no Caddy; e uma falha de comunicação dos dispositivos, no Mosquitto. O Git permanece como fonte de verdade para código e configuração, enquanto a VPS concentra execução, dados e segredos.