Pular para o conteúdo principal

Guia do LAB IoT Mail

Este guia explica como montar o laboratório da disciplina com o script gen_iot_vps_mail_portal.py e como usá-lo no dia a dia.

  • Parte 1 — Professor: preparar o servidor do laboratório (Windows 11) e o VPS, gerar o ambiente, publicar na internet e administrar o lab.
  • Parte 2 — Aluno: acessar no laboratório ou de casa, programar no Node-RED, usar MQTT, enviar e-mails de teste, conversar no chat e versionar no Gitea.
Visão geral em uma frase

Todos os serviços rodam no servidor do laboratório (Windows 11 + Docker Desktop). Na rede do laboratório, o acesso é direto pelo IP (http://192.168.0.102/). De qualquer outro lugar, o acesso é por https://iot.adrianoruseler.com/: um túnel SSH que sai do laboratório leva as requisições do Apache do VPS até o portal. Nenhuma porta precisa ser aberta na rede da instituição.

Arquitetura​

Dois endereços, o mesmo laboratório​

Onde você estáEndereço baseObservações
Na rede do laboratóriohttp://192.168.0.102 (IP do servidor)mais rápido; não depende da internet nem do VPS
Em qualquer outro lugarhttps://iot.adrianoruseler.comHTTPS; só funciona com o servidor do lab ligado

Os serviços ficam em caminhos do endereço base, iguais nos dois casos:

ServiçoCaminhoNo labDe fora
Portal/✅✅
Node-RED do grupo A/lab05-a/✅✅
Dashboard do grupo A/lab05-a/dashboard✅✅
Gitea/git/✅✅
Chat (Mattermost)/chat/✅✅
E-mail do grupo A (Mailpit)/mail/lab05-a/✅✅
E-mail central do professor/mail/✅✅
MQTT Explorerporta 3001✅❌
Broker MQTTporta 1883✅❌

Convenção de nomes​

O nome do lab (--lab, padrão lab05) é combinado com uma letra:

ItemNomeObservação
Grupos de alunoslab05-a, lab05-b, …um por grupo (máx. 24)
Professorlab05-pletra p reservada
Painel de notaslab05-nletra n reservada
Organização no Gitealab05-grupo-a, …uma por grupo
Canal privado no chatlab05-a, …grupo + professor
Caixa de e-mail (Mailpit)/mail/lab05-a/, servidor SMTP lab05-a-mailpituma por grupo; tag lab05-a na central
Tópicos MQTT do grupolab05-a/...prefixo obrigatório por convenção

Parte 1 — Professor​

1. Visão geral da preparação​

2. Preparar o servidor do laboratório (Windows 11)​

2.1 Hardware recomendado​

RecursoMínimoRecomendado
Memória RAM8 GB16 GB ou mais
Disco livre20 GB40 GB (SSD)
Redecabo, na rede dos alunoscabo + IP fixo

Com 10 grupos, o laboratório usa cerca de 3 a 4 GB de RAM: perto de 100 MB por Node-RED, mais o Mattermost (cerca de 1 GB), o PostgreSQL, o Gitea e os demais serviços.

2.2 Instalar os programas​

No PowerShell como administrador:

wsl --install # WSL 2 (reinicie se for pedido)
winget install -e --id Docker.DockerDesktop
winget install -e --id Python.Python.3.12
winget install -e --id Git.Git # opcional

Reinicie o computador e abra o Docker Desktop uma vez. Em Settings → General, marque Use the WSL 2 based engine e Start Docker Desktop when you sign in. Depois, num PowerShell comum:

py -m pip install bcrypt
docker version; docker compose version; py --version
Energia e suspensão

O servidor não pode suspender durante a aula, nem quando os alunos acessam de casa. Em Configurações → Sistema → Energia, ajuste a suspensão para Nunca quando estiver na tomada.

2.3 Imagem do MQTT Explorer​

O laboratório usa a imagem local ruseler/mqtt-explorer:local, que precisa existir no servidor:

docker image ls ruseler/mqtt-explorer # deve listar a tag "local"
# vinda de outro computador:
docker save -o mqtt-explorer.tar ruseler/mqtt-explorer:local # na origem
docker load -i mqtt-explorer.tar # no servidor

2.4 IP fixo, perfil de rede e firewall​

  1. Descubra o IP com ipconfig (Endereço IPv4, por exemplo 192.168.0.102).
  2. Fixe-o por reserva de DHCP no roteador ou em Configurações → Rede e Internet → Ethernet → Atribuição de IP → Manual.
  3. Deixe a rede como Privada e libere as portas usadas dentro do laboratório. No PowerShell como administrador:
Set-NetConnectionProfile -InterfaceAlias "Ethernet" -NetworkCategory Private

New-NetFirewallRule -DisplayName "LAB IoT - HTTP (portal)" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "LAB IoT - MQTT" -Direction Inbound -Protocol TCP -LocalPort 1883 -Action Allow -Profile Private
New-NetFirewallRule -DisplayName "LAB IoT - MQTT Explorer" -Direction Inbound -Protocol TCP -LocalPort 3001 -Action Allow -Profile Private
O túnel não precisa de porta aberta

O túnel é uma conexão de saída (SSH, porta 22) do servidor do lab até o VPS. Basta que a rede da instituição permita sair para a porta 22 do VPS. Não é preciso redirecionar portas no roteador nem pedir liberação de entrada.

3. Preparar o VPS​

O VPS não roda os serviços. Ele só recebe o HTTPS e repassa pelo túnel, o que cabe folgado em 1 GB de RAM.

Antes de começar, confira:

RequisitoComo verificar no VPS
Apache servindo HTTPS para iot.adrianoruseler.com (certificado do certbot)sudo apache2ctl -S lista um VirtualHost *:443 com esse nome
Acesso SSH com sudo (usuário ubuntu na Oracle)ssh ubuntu@iot.adrianoruseler.com
Portas 22 e 443 abertas (Security List da Oracle + firewall)já usadas hoje para SSH e o site
python3 e curljá vêm no Ubuntu

Se ainda não houver certificado:

sudo certbot --apache -d iot.adrianoruseler.com
A raiz do domínio passa a ser o laboratório

Depois do setup, todo o https://iot.adrianoruseler.com/ é encaminhado ao laboratório. Se esse domínio já mostra outro conteúdo, ele deixa de aparecer. As exceções são a validação do certbot (/.well-known/acme-challenge/) e a página lab-offline.html.

4. Gerar o ambiente​

Coloque o gen_iot_vps_mail_portal.py em C:\lab, abra o PowerShell nessa pasta e rode:

cd C:\lab
py .\gen_iot_vps_mail_portal.py --lab lab05 --grupos 10 --ip 192.168.0.102

O script não sobe nada: ele só gera os arquivos em C:\lab\lab05. Saída (resumida):

🐳 docker-compose.yml
🌐 nginx/nginx.conf
🐙 gitea/init/gitea-init.sh
🐘 postgres/init/bancos.sql
💬 mattermost/init/
🔐 tunel/ e 🌍 vps/ (proxy.conf, lab-offline.html, setup-vps.sh)

✅ lab05: 10 grupos (lab05-a..lab05-j) + professor (lab05-p) + notas (lab05-n)

Local: http://192.168.0.102/
Público: https://iot.adrianoruseler.com/ (túnel SSH -> Apache do VPS iot.adrianoruseler.com)

🌍 Publicação em https://iot.adrianoruseler.com — passos (uma vez):
1) docker compose run --rm --no-deps --build tunel chave (gera e mostra a chave)
2) ssh ubuntu@iot.adrianoruseler.com mkdir -p iot-lab
scp -r vps tunel/chave/id_ed25519.pub ubuntu@iot.adrianoruseler.com:iot-lab/
3) ssh -t ubuntu@iot.adrianoruseler.com sudo bash iot-lab/vps/setup-vps.sh iot-lab/id_ed25519.pub
4) docker compose up -d --build
Pasta curta e sem OneDrive

Use uma pasta local e curta como C:\lab. Evite Área de Trabalho e Documentos se estiverem sincronizados com o OneDrive, porque a sincronização pode travar arquivos usados pelos containers.

4.1 Todos os parâmetros​

ParâmetroPadrãoO que faz
--lablab05Nome do lab; prefixo de tudo (deve começar com letra).
--grupos10Quantidade de grupos (1 a 24).
--ip127.0.0.1IP do servidor na rede do lab (acesso local, MQTT, MQTT Explorer).
--publico-urlhttps://iot.adrianoruseler.comEndereço público servido pelo Apache do VPS.
--vps-hosthost da --publico-urlHost ou IP do VPS para o SSH do túnel.
--vps-ssh-porta22Porta SSH do VPS.
--vps-usuariotunelUsuário restrito criado no VPS para o túnel.
--vps-porta-tunel8080Porta, só em 127.0.0.1 do VPS, onde o túnel entrega o portal.
--sem-tuneldesligadoSem publicação: só a rede local (http://IP/).
--sem-giteadesligadoNão inclui o Gitea.
--gitea-dbpostgresBanco do Gitea: postgres (compartilhado) ou sqlite.
--gitea-reponoderedRepositório criado em cada organização ('' = nenhum).
--sem-chatdesligadoNão inclui o Mattermost.
--sem-mailpitdesligadoNão inclui o Mailpit (caixas de e-mail de teste).
--proteger-httpdesligadoDashboards e endpoints HTTP do Node-RED passam a pedir usuário e senha do grupo.
--novas-senhasdesligadoSorteia senhas novas para todos (por padrão, as senhas são mantidas).
--dominioiot.labUsado só nos e-mails internos das contas (lab05-a@iot.lab).
--saidanome do labPasta onde tudo é gerado.
--mqtt-explorer-authdesligadoExige login no MQTT Explorer.
--mqtt-explorer-usuario / --mqtt-explorer-senhaadmin / geradaCredenciais do MQTT Explorer.
--mqtt-explorer-porta3001Porta do MQTT Explorer.
Não esqueça o --ip

Com o padrão 127.0.0.1, o lab só funciona no próprio servidor. Sempre gere com o IP real da rede do laboratório.

4.2 Outros exemplos​

# Dashboards protegidos por senha quando acessados de fora
py .\gen_iot_vps_mail_portal.py --lab lab05 --ip 192.168.0.102 --proteger-http

# Laboratório enxuto: sem chat e Gitea em SQLite (não cria o PostgreSQL)
py .\gen_iot_vps_mail_portal.py --lab lab05 --ip 192.168.0.102 --sem-chat --gitea-db sqlite

# Só rede local, sem VPS
py .\gen_iot_vps_mail_portal.py --lab lab05 --ip 192.168.0.102 --sem-tunel

5. O que foi gerado​

lab05\
├── docker-compose.yml # todos os serviços (inclui o "tunel")
├── Dockerfile # imagem do Node-RED com nós extras
├── credenciais.txt # ⚠️ senhas e endereços de todos
├── .segredos.json # ⚠️ senhas e chaves persistentes — NÃO apague
├── nginx\nginx.conf # um servidor, tudo em caminhos
├── nginx\html\index.html # portal (links relativos: valem no IP e no domínio)
├── settings\lab05-a.js ... # configuração de cada Node-RED
├── data\lab05-a\ ... # fluxos, projetos e bancos SQLite de cada grupo
├── mosquitto\ mqtt-explorer\ # broker e explorer
├── gitea\init\gitea-init.sh # usuários, organizações, times e repositórios
├── mattermost\init\ # equipe, usuários e canais do chat
├── postgres\init\bancos.sql # bancos do Gitea e do Mattermost
├── tunel\ # cliente do túnel SSH
│ ├── Dockerfile, entrypoint.sh
│ └── chave\ # ⚠️ chave privada do túnel (gerada no 1º uso)
└── vps\ # vai para o VPS
├── setup-vps.sh # configura usuário, sshd e Apache
├── proxy.conf # trecho do Apache (proxy + WebSocket)
└── lab-offline.html # página "laboratório desligado"

Bancos, repositórios Git, anexos do chat e e-mails ficam em volumes do Docker (lab05_postgres_data, lab05_gitea_data, lab05_mm_*, lab05_mailpit_data, lab05_mosquitto_data). O backup está na seção 15.

6. Publicar no VPS​

Faça isto uma vez, no PowerShell, dentro de C:\lab\lab05. O Windows 11 já traz ssh e scp.

1) Gerar a chave do túnel

docker compose run --rm --no-deps --build tunel chave

A chave fica em tunel\chave\. A linha ssh-ed25519 … exibida é a parte pública.

2) Enviar os arquivos ao VPS

ssh ubuntu@iot.adrianoruseler.com mkdir -p iot-lab
scp -r vps tunel\chave\id_ed25519.pub ubuntu@iot.adrianoruseler.com:iot-lab/

3) Rodar o setup no VPS

ssh -t ubuntu@iot.adrianoruseler.com sudo bash iot-lab/vps/setup-vps.sh iot-lab/id_ed25519.pub
[setup-vps] usuário tunel criado
[setup-vps] chave do túnel autorizada (só 127.0.0.1:8080)
[setup-vps] sshd recarregado
[setup-vps] MPM event: limite de conexões simultâneas ajustado para 400
[setup-vps] VirtualHost HTTPS: /etc/apache2/sites-available/iot.adrianoruseler.com-le-ssl.conf
[setup-vps] Include inserido (backup: ...-le-ssl.conf.bak-iot-lab-20261001110743)
[setup-vps] Apache recarregado
[setup-vps] OK: Apache pronto; o túnel ainda não está conectado (página 'laboratório desligado').

O setup-vps.sh pode rodar de novo quantas vezes for preciso (por exemplo, para trocar a chave). Ele faz o seguinte:

EtapaO que fazPor quê
Usuário tunelsem senha nem shell; a chave só pode abrir 127.0.0.1:8080se a chave vazar, não dá acesso ao VPS
sshdregras só para tunel e detecção de conexão morta a cada 15 slibera a porta rápido após uma queda
Apacheliga proxy, proxy_http, proxy_wstunnel, headers e insere o Include no VirtualHost 443, com backupencaminhar HTTPS e WebSocket
MPM eventaté 400 conexões simultâneascada editor, dashboard e chat aberto mantém uma conexão
Validaçãoapache2ctl configtest; se falhar, restaura o backupnão derrubar o site

4) Subir o laboratório (próxima seção)

Como uma requisição chega ao Node-RED​

7. Subir o laboratório​

cd C:\lab\lab05
docker compose up -d --build

A primeira subida leva vários minutos. A ordem de inicialização é:

Confira o estado e os logs:

docker compose ps -a # db-init, gitea-init, mattermost-init: "exited (0)"
docker compose logs gitea-init mattermost-init
docker compose logs -f tunel
[tunel] chave pública: ssh-ed25519 AAAAC3Nza... tunel-iot-lab
[tunel] conectando tunel@iot.adrianoruseler.com:22 (VPS 127.0.0.1:8080 -> nginx:80)
Warning: Permanently added 'iot.adrianoruseler.com' (ED25519) to the list of known hosts.

Sem novas mensagens depois de "conectando", o túnel está no ar. Se ele cair, o container tenta de novo a cada 10 s.

8. Verificar​

TesteOndeEsperado
http://192.168.0.102/PC na rede do labportal com os cartões
https://iot.adrianoruseler.com/celular no 4Go mesmo portal, com cadeado
https://iot.adrianoruseler.com/ com o lab desligadoqualquer lugarpágina "O laboratório está desligado no momento"
http://192.168.0.102:3001/rede do labMQTT Explorer
http://192.168.0.102/mail/rede do labpede login; com lab05-p, mostra a caixa central
http://192.168.0.102/robots.txtqualquer lugarDisallow: /

9. Credenciais​

O credenciais.txt traz as senhas e os dois endereços de cada serviço. Um par usuário/senha por grupo vale para Node-RED, Gitea, chat e e-mail:

UsuárioNode-REDGiteaChatE-mail (Mailpit)
lab05-aedita o próprio Node-REDescreve em lab05-grupo-acanal privado lab05-a + avisossó a caixa /mail/lab05-a/
lab05-a-viewsó visualiza———
lab05-p (professor)edita o Node-RED do professoradministradoradministrador, está em todos os canaiscaixa central + caixas de todos os grupos
lab05-n (notas)edita o painel de notasleitura em todas as organizações—caixa central

As senhas são mantidas quando o script roda de novo (ficam em .segredos.json). Para sortear novas, use --novas-senhas.

Proteja credenciais.txt, .segredos.json e tunel\chave

Os três contêm segredos em texto puro. Não os coloque em repositório, em OneDrive compartilhado nem em pasta acessível aos alunos. Para entregar a senha, copie só a linha do grupo.

10. Gitea​

O gitea-init cria, para cada grupo, o usuário (mesma senha do Node-RED), a organização privada, os times grupo (escrita) e avaliacao (leitura, para lab05-n) e o repositório nodered com README.md na branch main. O cadastro público fica desligado e é preciso login até para ver.

A imagem do Gitea fica fixada na versão 28 (gitea/gitea:28), para que uma versão nova não mude o comportamento no meio do semestre.

O endereço "oficial" do Gitea (links e URLs de clone exibidos) é o público, https://iot.adrianoruseler.com/git/. Mesmo assim, ele funciona normalmente pelo IP dentro do laboratório. Os repositórios ficam no volume lab05_gitea_data, e o banco, no PostgreSQL.

11. Chat (Mattermost)​

O mattermost-init cria:

  • a equipe privada lab05;
  • o canal avisos, com todos;
  • um canal privado por grupo, só com o grupo e o professor;
  • os usuários com as senhas do credenciais.txt. lab05-p é o administrador do sistema.

As contas são por grupo: a mensagem aparece como lab05-a, e não com o nome do aluno. Peça aos alunos que assinem quando isso importar. O app Mattermost Desktop ou mobile pode ser usado com o servidor https://iot.adrianoruseler.com/chat.

12. E-mail de teste (Mailpit)​

O Mailpit é um servidor de e-mail de teste: ele recebe as mensagens e mostra numa página web, mas nunca as entrega a ninguém. Os grupos podem testar alertas por e-mail (nó e-mail do Node-RED, já instalado) sem risco de enviar spam e sem precisar de uma conta de e-mail real.

Um único Mailpit não separa caixas por usuário (quem entra vê tudo). Por isso o laboratório usa uma instância por grupo e uma caixa central do professor:

CaixaEndereçoQuem entraO que mostra
Do grupo/mail/lab05-a/o grupo e o professorsó os e-mails daquele grupo
Central/mail/lab05-p e lab05-ntodos, cada um com a tag do grupo

Como a tag é aplicada: cada caixa de grupo encaminha uma cópia para a central autenticando com o usuário do grupo, e a central marca a mensagem com esse usuário. A tag não depende do aluno: ele não precisa colocar nada no e-mail, e um grupo não consegue se passar por outro.

Na caixa central, filtre por grupo digitando na busca:

tag:lab05-a

O portal tem um cartão E-mail (Mailpit), que leva à caixa central, e uma linha "Caixa de e-mail de cada grupo" com os links /mail/lab05-a/, /mail/lab05-b/, …

Cada caixa de grupo guarda até 500 mensagens, e a central até 5.000; as mais antigas são apagadas automaticamente. Cada instância usa cerca de 20 MB de RAM.

13. Painel de notas (lab05-n)​

O Node-RED de notas monta a pasta data de todos os grupos, só para leitura, em /data_grupos:

/data_grupos/lab05-a/flows.json
/data_grupos/lab05-a/projects/nodered/flows.json # se o grupo usa Projects

Use read file (ou fs num nó function) para analisar os fluxos. O usuário lab05-n também tem leitura em todas as organizações do Gitea.

14. Segurança com o laboratório na internet​

ItemSituação
Editores Node-REDexigem login (usuário do grupo ou -view)
Gitea e chatexigem login; sem cadastro público
Dashboards e endpoints HTTP do Node-REDabertos por padrão. Use --proteger-http para pedir a senha do grupo. Nesse caso, um ESP32 que chame endpoints HTTP também precisa enviá-la.
E-mail (Mailpit)cada caixa exige login; um grupo não vê nem usa a caixa de outro; nenhum e-mail sai do laboratório
Broker MQTT e MQTT Explorernão são publicados; só na rede do lab
Chave do túnelsó abre 127.0.0.1:8080 no VPS; não tem shell nem outros redirecionamentos
Buscadores e robôs de IArobots.txt com Disallow: / e o Apache envia X-Robots-Tag: noindex, nofollow. Robôs bem-comportados respeitam; os outros só encontram telas de login.

As senhas dos grupos têm 8 caracteres. Com o laboratório exposto, evite reutilizá-las em outros lugares e, ao final do semestre, desligue a publicação (seção 15.3).

15. Operação do dia a dia​

No PowerShell, dentro de C:\lab\lab05:

TarefaComando
Ver statusdocker compose ps -a
Logs do túneldocker compose logs -f tunel
Reiniciar o túneldocker compose restart tunel
Tirar o lab da internet (continua local)docker compose stop tunel
Logs de um grupodocker compose logs -f lab05-a-nodered
Reiniciar um grupodocker compose restart lab05-a-nodered
Parar tudo (mantém dados)docker compose down
Subir de novodocker compose up -d
Ver mensagens MQTTdocker exec -it lab05-mosquitto mosquitto_sub -t '#' -v
Recriar usuários do Gitea / chatdocker compose run --rm gitea-init / docker compose run --rm mattermost-init
Logs do e-mail de um grupodocker compose logs -f lab05-a-mailpit
Recarregar o nginx (após regerar)docker compose restart nginx

No VPS:

TarefaComando
O túnel está conectado?sudo ss -ltnp e procure 127.0.0.1:8080
Erros do Apachesudo tail -f /var/log/apache2/error.log
Tentativas de login do túnelsudo journalctl -u ssh -f

15.1 Backup​

cd C:\lab\lab05
New-Item -ItemType Directory -Force backup | Out-Null
$d = Get-Date -Format yyyy-MM-dd

# Bancos (Gitea + chat): gerado dentro do container e copiado (evita UTF-16 do PowerShell)
docker exec lab05-postgres pg_dumpall -U postgres -f /tmp/dump.sql
docker cp lab05-postgres:/tmp/dump.sql ".\backup\postgres_$d.sql"

# Pastas locais e segredos
tar -czf ".\backup\pastas_$d.tgz" data settings credenciais.txt .segredos.json tunel\chave

# Repositórios Git e anexos do chat
docker run --rm -v lab05_gitea_data:/v -v "${PWD}\backup:/b" alpine tar czf /b/gitea_$d.tgz -C /v .
docker run --rm -v lab05_mm_data:/v -v "${PWD}\backup:/b" alpine tar czf /b/mm_data_$d.tgz -C /v .
docker run --rm -v lab05_mailpit_data:/v -v "${PWD}\backup:/b" alpine tar czf /b/mailpit_$d.tgz -C /v .

O prefixo lab05_ dos volumes vem do nome da pasta. Confira com docker volume ls.

15.2 Zerar o Node-RED de um grupo​

docker compose stop lab05-a-nodered
Rename-Item data\lab05-a lab05-a.old
New-Item -ItemType Directory data\lab05-a | Out-Null
docker compose start lab05-a-nodered

15.3 Fim do semestre​

docker compose down # para tudo e mantém dados e volumes
docker compose down -v # ⚠️ APAGA também os volumes (bancos, repositórios, chat, e-mails)

Para revogar o acesso do túnel ao VPS, no VPS:

sudo truncate -s 0 /home/tunel/.ssh/authorized_keys

16. Regerar o ambiente​

ItemAo rodar o script de novo na mesma pasta
Senhas dos gruposmantidas (use --novas-senhas para trocar)
Senhas internas, chaves do Node-RED e do Giteamantidas (.segredos.json)
Chave do túnel (tunel\chave)mantida
data\ e volumespreservados
docker-compose.yml, nginx\, settings\, scriptssobrescritos

Depois de regerar com a turma em andamento:

docker compose up -d --build
docker compose restart nginx # o nginx só relê o nginx.conf ao reiniciar
docker compose run --rm gitea-init # só necessário com --novas-senhas
docker compose run --rm mattermost-init # idem
Por que reiniciar o nginx?

O nginx.conf é um arquivo montado no container. Quando só ele muda, o docker compose up -d não recria o nginx, e a configuração nova só vale depois do restart. As senhas do Mailpit ficam no docker-compose.yml, então os containers de e-mail são recriados sozinhos pelo up -d.

Se você mudou --publico-url ou --vps-porta-tunel, envie a pasta vps\ de novo e rode o setup-vps.sh outra vez.

17. Problemas comuns​

O domínio mostra "O laboratório está desligado no momento"

O túnel não está conectado. No lab, rode docker compose ps e docker compose logs tunel. O servidor precisa estar ligado, com o Docker Desktop aberto e com acesso à internet.

tunel: "Permission denied (publickey)"

O VPS não reconhece a chave. Gere de novo a pública com docker compose run --rm --no-deps tunel chave, envie o id_ed25519.pub e rode o setup-vps.sh outra vez. Se o sshd do VPS usa AllowUsers, inclua tunel nessa lista (o setup avisa).

tunel: "remote port forwarding failed for listen port 8080"

O VPS ainda mantém a sessão anterior, que caiu sem avisar. O sshd a encerra em até cerca de 45 s e o container reconecta sozinho. Se persistir, veja se outro programa usa a porta 8080 no VPS (sudo ss -ltnp | grep 8080). Nesse caso, gere com outra --vps-porta-tunel e rode o setup de novo.

tunel: "Connection timed out" ao conectar

A rede da instituição bloqueia a saída para a porta 22. Faça o sshd do VPS escutar também em outra porta (por exemplo 2222; a 443 já é do Apache), libere-a na Security List da Oracle e gere com --vps-ssh-porta 2222.

setup-vps.sh: "não achei o VirtualHost *:443"

O Apache ainda não tem HTTPS para o domínio. Rode sudo certbot --apache -d iot.adrianoruseler.com e execute o setup de novo.

setup-vps.sh avisa sobre MPM "prefork"

O Apache está em prefork (comum com mod_php). Nesse modo, cada conexão aberta ocupa um processo inteiro, e 1 GB de RAM não aguenta a turma. Migre para PHP-FPM + mpm_event, ou não use PHP nesse VPS, e rode o setup de novo.

Funciona pelo domínio mas não pelo IP (ou o contrário)
  • Só o IP falha: confira o perfil de rede Privado e o firewall (seção 2.4), e se o lab foi gerado com o --ip correto.
  • Só o domínio falha: é o túnel ou o VPS. Veja os logs do tunel e /var/log/apache2/error.log.
Um caminho (ex.: /git/) dá 502 Bad Gateway

O nginx não alcançou o container daquele serviço. Veja se ele está no ar (docker compose ps) e os logs dele (docker compose logs gitea). Se o serviço está bem, rode docker compose logs nginx. A mensagem no resolver defined indica um nginx.conf gerado por uma versão antiga do script: gere de novo e rode docker compose restart nginx.

E-mails aparecem na caixa do grupo, mas não na central

Veja docker compose logs lab05-a-mailpit e procure linhas [forward]. A cópia para a central usa o usuário e a senha do grupo. Se as senhas foram trocadas (--novas-senhas), rode docker compose up -d para recriar os containers de e-mail com as senhas novas.

gitea-init ou mattermost-init terminou com erro

Normalmente o serviço demorou para ficar pronto. Rode de novo: docker compose run --rm mattermost-init (ou gitea-init).

Gitea ou chat: "password authentication failed"

O .segredos.json foi apagado ou trocado depois que o PostgreSQL foi criado. Restaure o arquivo e rode docker compose up -d. Sem ele, só resta recriar o volume lab05_postgres_data, perdendo os dados do Gitea e do chat.


Parte 2 — Aluno​

1. O que você recebe do professor​

  • A letra do seu grupo (ex.: a, então seu grupo é lab05-a).
  • O usuário e a senha do grupo. A mesma senha vale para o Node-RED, o Gitea, o chat e o e-mail.
  • Os dois endereços do laboratório:
Onde você estáAbra
No laboratóriohttp://192.168.0.102/ (IP do servidor)
Em casa ou em qualquer lugarhttps://iot.adrianoruseler.com/

Não é preciso configurar nada no Windows: nem DNS, nem arquivo hosts.

No laboratório, use o IP

Dentro do laboratório, o endereço pelo IP é mais rápido e funciona mesmo se a internet cair. O endereço público passa pela internet e pelo VPS.

2. Portal e Node-RED​

  1. Abra o endereço base. Aparecem cartões para cada grupo e para professor, notas, chat, Gitea, e-mail e MQTT Explorer, e logo abaixo os links das caixas de e-mail de cada grupo.
  2. Clique no cartão do seu grupo e entre com o usuário e a senha do grupo.
No laboratórioDe fora
Editor do grupo Ahttp://192.168.0.102/lab05-a/https://iot.adrianoruseler.com/lab05-a/
Dashboard do grupo Ahttp://192.168.0.102/lab05-a/dashboardhttps://iot.adrianoruseler.com/lab05-a/dashboard

O usuário lab05-a-view abre o editor sem poder alterar nada. Use-o para apresentar no projetor.

Página "O laboratório está desligado no momento"

Se ela aparecer no endereço público, o servidor do laboratório está desligado ou sem internet. Isso é normal fora do horário das aulas. Tente mais tarde ou avise o professor no chat.

3. Chat do lab​

Abra o cartão Chat (/chat/) e entre com o usuário e a senha do grupo.

CanalQuem vêPara quê
avisostodo o labrecados do professor
🔒 lab05-a (o do seu grupo)só o seu grupo e o professordúvidas e orientação
mensagens diretasas duas pontasconversa direta

Todos do grupo usam a mesma conta: comece com o seu nome quando importar ("Ana: o sensor parou…"). Para mostrar código, use três crases antes e depois do trecho. No celular, o app Mattermost funciona com o servidor https://iot.adrianoruseler.com/chat.

4. E-mail de teste (Mailpit)​

Seu grupo tem uma caixa de e-mail de teste: tudo o que o Node-RED do grupo enviar por e-mail aparece em /mail/lab05-a/, e nada é entregue de verdade. Use para testar alertas ("temperatura acima do limite") sem precisar de uma conta de e-mail. Só o seu grupo e o professor veem essa caixa.

Enviar pelo Node-RED com o nó e-mail (saída, da categoria social):

Campo do nóValor
Toqualquer endereço, até inventado (ex.: dono@exemplo.com)
Serverlab05-a-mailpit (troque a letra pela do seu grupo)
Port1025
Use secure connectiondesmarcado
Auth typeBasic
Userid / Passwordusuário e senha do grupo

O assunto vem de msg.topic, e o texto, de msg.payload. Exemplo de nó function antes do nó e-mail:

msg.topic = "Alerta: temperatura alta";
msg.payload = `A temperatura chegou a ${msg.payload} °C às ${new Date().toLocaleTimeString("pt-BR")}.`;
return msg;

Abra /mail/lab05-a/, entre com o usuário e a senha do grupo e veja a mensagem chegar na hora. O professor recebe uma cópia na caixa central, marcada com a tag do seu grupo.

Use o servidor do seu grupo

O servidor lab05-a-mailpit só aceita o login do grupo A. Se o nó mostrar erro de autenticação, confira se a letra do servidor é a do seu grupo e se a senha está certa.

5. MQTT​

O broker MQTT só existe na rede do laboratório.

ClienteServidor (host)Porta
Node-RED do grupo (no servidor)mosquitto1883
ESP32, celular, MQTTX, Python (rede do lab)IP do servidor (192.168.0.102)1883

O broker não pede usuário nem senha. No Node-RED:

  1. Arraste um nó mqtt in ou mqtt out.
  2. Em Server, crie o broker com Server mosquitto e Port 1883.
  3. Em Topic, use o prefixo do grupo (ex.: lab05-a/sensor/#).
  4. Clique em Deploy. O nó deve mostrar connected.

Mesmo editando o Node-RED de casa, os nós MQTT continuam funcionando, porque eles rodam no servidor do laboratório. O que só funciona no laboratório é ligar dispositivos e clientes seus ao broker.

const char* MQTT_HOST = "192.168.0.102"; // IP do servidor do laboratório
const int MQTT_PORT = 1883;

client.setServer(MQTT_HOST, MQTT_PORT);
client.connect("lab05-a-esp32"); // client id único por dispositivo
client.publish("lab05-a/sensor/temperatura", "23.5");
client.subscribe("lab05-a/led/cmd");
Respeite os tópicos dos outros grupos

O broker é compartilhado e não bloqueia tópicos. Publicar fora do seu prefixo atrapalha os outros grupos e a avaliação.

6. MQTT Explorer​

Na rede do laboratório, abra o cartão MQTT Explorer (http://192.168.0.102:3001/). Ele já vem conectado ao broker. Expanda lab05-a para ver as mensagens do grupo. Se pedir login, use as credenciais do MQTT Explorer informadas pelo professor.

7. Banco de dados SQLite​

O nó sqlite está instalado. Grave o banco dentro da pasta de dados do Node-RED:

Database: /data/meu_banco.db

8. Gitea: versionar o projeto​

Seu grupo tem a organização privada lab05-grupo-a com o repositório nodered.

8.1 Entrar no Gitea​

Abra o cartão Gitea (/git/) e entre com o mesmo usuário e senha do grupo.

8.2 Ligar o Node-RED ao repositório (Projects)​

  1. No primeiro acesso, o Node-RED abre o assistente de projetos. Informe nome e e-mail para os commits (ex.: Grupo A, lab05-a@iot.lab).

  2. Escolha Clone Repository:

    CampoValor
    Repository URLhttp://gitea:3000/lab05-grupo-a/nodered.git
    Usernamelab05-a
    Passwordsenha do grupo

    Use gitea:3000, o nome interno do Docker. O Node-RED roda dentro do servidor, e esse endereço funciona tanto no laboratório quanto de casa.

  3. Defina uma chave de criptografia das credenciais e anote-a.

  4. Se o Node-RED avisar que faltam arquivos do projeto (package.json ou o arquivo de fluxos), aceite criá-los.

No dia a dia, use a aba Project history:

  • commit: em Local changes, marque os arquivos, clique em commit e escreva a mensagem;
  • push: clique na seta ↑ para enviar ao Gitea.
Commits pequenos e frequentes

Faça um commit a cada funcionalidade que funcionar ("leitura do sensor ok", "dashboard com gráfico"). O histórico ajuda o grupo a voltar atrás e mostra ao professor a evolução do trabalho.

8.3 Clonar no seu PC (opcional)​

Instale o Git for Windows (winget install -e --id Git.Git) e, no PowerShell:

git clone http://192.168.0.102/git/lab05-grupo-a/nodered.git

O Git Credential Manager pede o usuário (lab05-a) e a senha do grupo. Em computador compartilhado, remova a credencial ao final em Painel de Controle → Gerenciador de Credenciais → Credenciais do Windows.

9. Boas práticas​

  • Dê Deploy com frequência e teste com nós debug.
  • Faça commit e push no Gitea ao fim de cada aula.
  • Não guarde senhas reais em nós function ou template. Lembre que o dashboard pode estar acessível pela internet.
  • Se o seu Node-RED ficar fora do ar, avise no canal privado do grupo.

10. Problemas comuns​

SintomaCausa provávelO que fazer
"O laboratório está desligado no momento"servidor do lab desligado ou sem internettente mais tarde; no lab, use o IP
O IP não abre, no laboratóriorede diferente (ex.: Wi-Fi de visitantes)conecte-se à rede do laboratório
Login recusadousuário ou senha erradoso usuário é lab05-a (sem -view); diferencia maiúsculas
Nó MQTT em disconnectedservidor errado no nóuse mosquitto e porta 1883
ESP32 não conectafora da rede do lab ou IP erradoo broker só existe na rede do laboratório
MQTT Explorer não abre de casaele é só localuse-o no laboratório
Clone no Node-RED falhaURL externause http://gitea:3000/... dentro do Node-RED
"Repository not found"organização de outro grupocada grupo só acessa a sua
Nó e-mail: erro de autenticaçãoservidor de outro grupo ou senha erradause lab05-<sua letra>-mailpit e a senha do grupo
Nó e-mail: erro de TLS/conexãoconexão segura marcadadesmarque Use secure connection; porta 1025
A caixa /mail/lab05-a/ pede senha de novologin de outro grupocada caixa só aceita o próprio grupo

Referência rápida​

# no servidor do laboratório (uma vez)
py -m pip install bcrypt
cd C:\lab
py .\gen_iot_vps_mail_portal.py --lab lab05 --grupos 10 --ip 192.168.0.102
cd .\lab05
docker compose run --rm --no-deps --build tunel chave
ssh ubuntu@iot.adrianoruseler.com mkdir -p iot-lab
scp -r vps tunel\chave\id_ed25519.pub ubuntu@iot.adrianoruseler.com:iot-lab/
ssh -t ubuntu@iot.adrianoruseler.com sudo bash iot-lab/vps/setup-vps.sh iot-lab/id_ed25519.pub
docker compose up -d --build
docker compose logs -f tunel
notepad credenciais.txt