SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-28

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.yml
services:
  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 mealie

O 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:9925

Um 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/mealie
server {
    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 nginx

A 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.com

O 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 mealie

O 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 mealie

Aumente 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.