Mealie num VPS com Docker Compose: guia completo
Instale o Mealie num VPS com Docker Compose, extraia receitas por URL e configure planos de refeições, listas de compras, nginx, TLS e backups.
O que faz um gestor de receitas autoalojado
Um gestor de receitas autoalojado mantém as suas receitas numa base de dados num servidor que controla, e o Mealie é a opção escolhida pela maioria das famílias. Cole o endereço de uma página de receitas e o Mealie extrai os ingredientes, os passos, o rendimento e o tempo de confeção, deixando de fora o texto e a publicidade. O que fica na sua coleção é a receita.
O resto da aplicação é simples. Existe um plano semanal de refeições para onde pode arrastar receitas e uma lista de compras criada a partir desse plano. Cada pessoa que cozinha tem o seu próprio início de sessão. Tudo é executado num único contentor e permanece inativo entre pedidos, pelo que um VPS modesto o suporta sem problemas.
Este guia usa Docker Compose. Se os termos services: e volumes: forem novos para si, leia primeiro como são estruturados os ficheiros do Docker Compose, porque tudo o que segue consiste num único ficheiro compose e em quatro comandos.
Instalar o Mealie com Docker Compose
O Mealie publica as suas imagens no GitHub Container Registry. Em julho de 2026, a tag estável atual é v3.22.0. Fixe uma versão em vez de usar latest: com latest, uma docker compose pull num dia sem relação pode fazer a atualização atravessar uma migração da base de dados para a qual ainda não está preparado.
sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.ymlservices:
mealie:
image: ghcr.io/mealie-recipes/mealie:v3.22.0
container_name: mealie
restart: always
ports:
- "127.0.0.1:9925:9000"
deploy:
resources:
limits:
memory: 1000M
volumes:
- mealie-data:/app/data/
environment:
ALLOW_SIGNUP: "false"
PUID: 1000
PGID: 1000
TZ: Europe/Amsterdam
BASE_URL: https://recipes.example.com
volumes:
mealie-data:Duas linhas merecem ser analisadas antes de iniciar o serviço.
A porta está escrita como 127.0.0.1:9925:9000 e não como 9925:9000. O contentor escuta na porta 9000 internamente, e o host encaminha a porta 9925 para essa porta. Associar esse mapeamento ao endereço de loopback permite que o nginx alcance o Mealie, mas impede o acesso a partir da Internet. O Docker escreve as suas próprias regras no filtro de pacotes. Por isso, um 9925:9000 simples fica acessível a partir do exterior mesmo quando a firewall indica que a porta está fechada. É importante compreender esta particularidade: consulte por que as portas publicadas pelo Docker ignoram o ufw.
BASE_URL tem de ser exatamente o endereço público que vai utilizar, com o esquema e sem uma barra no final. O Mealie cria a partir dele as ligações para reposição de palavras-passe e os convites. Se o definir como http://localhost:9925, o convite enviado ao seu parceiro conterá uma ligação que só funciona no próprio servidor.
Inicie o serviço e monitorize o primeiro arranque.
sudo docker compose up -d
sudo docker compose logs -f mealieO primeiro arranque cria a base de dados SQLite e executa as migrações, o que demora alguns segundos. Quando o log estabilizar e deixar de apresentar linhas de migração, teste a aplicação localmente.
curl -I http://127.0.0.1:9925Um 200 OK significa que a aplicação está em execução. Connection refused significa que o contentor não está em execução: execute sudo docker compose ps e leia o código de saída. Um contentor que terminou com o código 137 foi encerrado por exceder o limite de memória de 1000M, o que acontece nos planos mais pequenos.
Primeiro início de sessão e desativação do registo aberto
A conta predefinida é changeme@example.com e a palavra-passe é MyPassword. Inicie sessão com esses dados e altere ambos imediatamente, porque essa combinação está publicada na documentação e, por isso, consta de todos os scanners.
ALLOW_SIGNUP: "false" no ficheiro compose é intencional. Com o registo aberto, qualquer pessoa que encontre o endereço pode criar uma conta na sua coleção de receitas. Com o registo fechado, adiciona pessoas na área de administração. Esta ação gera uma ligação de convite que envia pessoalmente. Essa ligação é criada a partir de BASE_URL, razão pela qual esse valor é importante. Se acabar por executar várias aplicações no mesmo servidor e quiser uma única palavra-passe para todas, o Mealie pode delegar o início de sessão a um fornecedor de identidade externo, como uma instância auto-hospedada do Authentik.
O Mealie agrupa os utilizadores numa household. Todas as pessoas da mesma household partilham a coleção de receitas, o plano de refeições e a lista de compras, que é o que uma família precisa. Households separadas no mesmo servidor mantêm coleções distintas, o que é útil numa casa partilhada quando ninguém concorda sobre anchovas.
O importador, que é o motivo para executar isto
Abra a coleção de receitas, escolha criar uma receita a partir de um URL e cole uma ligação. O Mealie obtém a página e procura dados estruturados de receita, o bloco legível por máquina que a maioria dos sites de receitas inclui para os motores de pesquisa. Quando esse bloco está presente, a importação é limpa e imediata.
Também pode importar a partir de uma imagem ou de texto simples colado, incluindo uma fotografia de uma página de um livro de receitas. Estes métodos seguem um processo mais lento e devem ser verificados depois, porque uma fração manuscrita pode ser interpretada incorretamente.
As importações em massa são executadas a partir do mesmo ecrã: cole uma lista de endereços, um por linha, e o Mealie processa-os em segundo plano. Uma coleção com duzentos marcadores é transferida numa única sessão.
Planos de refeições e lista de compras
O planeador de refeições é um calendário. Arraste uma receita para um dia para a planear. A lista de compras recolhe os ingredientes das receitas planeadas numa única lista e combina os duplicados. Assim, duas receitas que pedem cebolas produzem uma linha em vez de duas.
A lista é uma página atualizada em tempo real no telemóvel, enquanto está na loja. Como é alojada no seu próprio servidor, todas as pessoas da casa veem a mesma lista ao mesmo tempo. Quando uma pessoa marca o leite como comprado, este desaparece do ecrã das outras pessoas.
Coloque o nginx e o TLS à frente
O Mealie utiliza HTTP simples e não gere certificados. Termine o TLS no nginx, à frente do serviço. Primeiro, aponte um registo DNS A para o servidor, porque a emissão do certificado valida esse nome.
sudo apt update && sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/mealieserver {
listen 80;
server_name recipes.example.com;
client_max_body_size 64M;
location / {
proxy_pass http://127.0.0.1:9925;
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;
}
}sudo ln -s /etc/nginx/sites-available/mealie /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxA saída de nginx -t, syntax is ok e test is successful é a verificação necessária. Só faça o reload depois de essa verificação passar, porque recarregar uma configuração inválida mantém a configuração antiga em execução e oculta o erro até ao próximo reinício.
client_max_body_size 64M é necessário porque o valor predefinido do nginx é 1 MB. O envio de uma fotografia de receita ou o restauro de uma cópia de segurança pelo navegador envia um corpo maior do que esse limite. Sem essa linha, o nginx devolve 413 Request Entity Too Large, não o Mealie, e o log da aplicação não regista nada.
Em seguida, emita o certificado. Essa etapa e o respetivo temporizador de renovação estão descritos em emitir um certificado Let's Encrypt para o nginx com o certbot.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d recipes.example.comO Certbot reescreve o bloco de servidor para escutar na porta 443 e adiciona um redirecionamento da porta 80. Abra o site através de https:// e confirme que o navegador aceita o certificado. Se o Mealie carregar, mas os próprios links enviarem para http://, então BASE_URL ainda indica http e precisa de ser corrigido. Depois, execute sudo docker compose up -d para recriar o contentor com o novo valor.
Servir o Mealie num subcaminho, como example.com/recipes, não funciona, porque o frontend não pode ser servido a partir de um subcaminho. Utilize um subdomínio.
Backups e o que uma restauração realmente faz
Tudo o que o Mealie gere fica em /app/data/ dentro do container. Esse é o volume mealie-data. Copie esse volume para copiar as receitas, as imagens e a base de dados em conjunto.
sudo docker volume ls
sudo docker compose stop mealie
sudo docker run --rm -v mealie_mealie-data:/data -v "$PWD":/backup \
alpine tar czf /backup/mealie-data.tgz -C /data .
sudo docker compose start mealieO nome do volume tem o nome do projeto como prefixo, e o nome do projeto é o diretório que contém o ficheiro compose. A partir de /srv/mealie, o volume é mealie_mealie-data. Por isso, o primeiro comando é docker volume ls: use o nome apresentado pelo comando, não o nome deste guia. É importante parar primeiro o container, porque o SQLite está frequentemente a escrever. Uma cópia feita com o serviço ativo pode ser restaurada como um ficheiro ilegível.
O Mealie também tem uma página própria de backups na área de administração. Essa página cria um arquivo portátil que contém a base de dados em JSON juntamente com as imagens. Use-o para migrar entre servidores, porque este método suporta uma alteração de versão que uma cópia direta dos ficheiros pode não suportar. A restauração é destrutiva por definição: elimina a base de dados atual antes de carregar o arquivo e não pode ser desfeita. A sessão termina quando o processo é concluído.
Nenhuma das cópias é um backup enquanto permanecer no mesmo servidor. Envie o arquivo para outro local segundo um agendamento. É isso que os backups cifrados fora do servidor com restic fazem.
Atualizar o Mealie
cd /srv/mealie
sudo nano docker-compose.yml
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs -f mealieAumente a versão fixada no ficheiro e, em seguida, faça pull e recrie o contentor. As migrações são executadas no primeiro arranque da nova imagem. Faça uma cópia do volume antes de alterar a versão principal, porque uma migração que falhe a meio pode deixar uma base de dados que a imagem anterior já não consegue abrir. Leia as notas de versão de todas as versões entre a sua versão atual e a nova versão.
Quando o importador falha
Alguns sites não publicam dados estruturados de receitas. Nesse caso, o Mealie importa o título com uma lista de ingredientes vazia. Não é possível corrigir isso através da configuração. Cole o texto da receita manualmente.
Outras falhas são causadas pela proteção contra bots existente à frente do site da receita. Em vez da receita, essa proteção envia ao Mealie uma página de desafio. O Mealie já se identifica como um navegador e alterna o user agent para reduzir esse problema. Quando um site continua a recusar o acesso, as opções documentadas são enviar o scraper através de um proxy com melhor reputação de endereço ou executar uma instância do FlareSolverr, que resolve o desafio num navegador real. Ambas as opções são facultativas e ambas são configuradas através de variáveis de ambiente no contentor.
Um import que falha porque o servidor não consegue alcançar o site é um problema diferente. Teste o acesso a partir do servidor com curl -I https://the-site.example/recipe e leia a linha de estado antes de atribuir o problema ao scraper.
Onde se enquadra
O Mealie é uma boa primeira aplicação self-hosted para uma casa, porque as pessoas com quem vive vão utilizá-lo sem ser necessário pedir-lhes. É o mesmo tipo de tarefa que a sua própria biblioteca de fotografias com o Immich, embora muito mais leve, e faz parte da lista mais ampla de coisas que vale a pena alojar por conta própria este ano. Um pequeno servidor pode alojar ambos. O Immich não é o único candidato para essa segunda tarefa e, se ainda estiver a decidir, os requisitos mínimos de memória e os comandos de backup do PhotoPrism e do Immich são suficientemente diferentes para justificar a leitura antes de ocupar o espaço restante do disco. Se a casa também mantiver os seus planos e notas no mesmo local que as suas receitas, um espaço de trabalho AFFiNE self-hosted é novamente o mesmo exercício com um ficheiro Compose, mas requer quatro contentores e muito mais memória do que o Mealie, por isso confirme primeiro os recursos disponíveis no servidor. E, se a casa quiser acompanhar os seus treinos além das receitas, o openGym mantém os treinos e requer a mesma tag fixa, ficheiro Compose e certificado que acabou de configurar. A noite depois do jantar tem a sua própria versão deste cenário, porque o Halcyon transforma uma biblioteca Jellyfin existente numa videolocadora dos anos 1990 que pode percorrer, acrescentando mais um pequeno contentor à frente de algo que já executa, em vez de outra base de dados para manter em backup. Nem tudo nesta família é uma aplicação doméstica e, se o mesmo hábito tiver de suportar alguma atividade profissional, uma central de suporte Chatwoot self-hosted requer novamente a mesma tag fixa e o mesmo certificado, com Postgres, Redis e o envio de correio de saída a funcionar por trás, sendo um serviço muito mais pesado do que uma caixa de receitas e merecendo um servidor próprio.
FAQ
Por que a importação de um URL de receita falha?
Há duas causas comuns. A página pode não publicar dados estruturados de receita, pelo que o scraper não encontra nada e obtém um título sem ingredientes. Em alternativa, uma camada de proteção contra bots à frente do site pode devolver uma página de desafio em vez da receita. Neste segundo caso, o Mealie pode ser configurado para usar um proxy com melhor reputação de endereço ou uma instância autoalojada do FlareSolverr, que resolve o desafio num navegador real. Confirme primeiro se o servidor consegue sequer aceder à página com curl -I antes de alterar qualquer configuração.
Preciso do PostgreSQL ou o SQLite é suficiente?
O SQLite é suficiente para uma família e é a opção predefinida. Mude para PostgreSQL quando o diretório de dados estiver num armazenamento ligado à rede, porque o SQLite sobre um sistema de ficheiros de rede produz erros de base de dados bloqueada e pode corromper o ficheiro. As restaurações com PostgreSQL exigem que o utilizador da base de dados seja superuser, porque a restauração elimina tudo antes de carregar o arquivo.
Posso executar o Mealie sem um nome de domínio?
Sim, na sua própria rede. Defina BASE_URL para o endereço que irá realmente introduzir, como http://192.168.1.20:9925, e não use nginx. Os links de convite e de reposição da palavra-passe são construídos a partir de BASE_URL, pelo que um valor incorreto produz links que mais ninguém consegue abrir. Não o exponha à internet através de HTTP simples, porque nesse caso o início de sessão é enviado sem encriptação.
Como atribuo aos meus familiares os seus próprios logins?
Mantenha ALLOW_SIGNUP definido como "false" e adicione as pessoas na área de administração. Isso gera um link de convite que pode enviar-lhes. Coloque no mesmo household todas as pessoas que partilham uma cozinha, para que partilhem as receitas, o plano de refeições e a lista de compras. Os households separados no mesmo servidor mantêm coleções distintas.
O que acontece às minhas receitas se eu deixar de executar o Mealie?
Pode retirá-las. A cópia de segurança da área de administração grava os seus dados em JSON. O Mealie também pode exportar receitas como ficheiros markdown simples, que continuam legíveis em qualquer editor de texto sem software adicional. Faça uma exportação antes de precisar dela e confirme que consegue abri-la.