SSD Nodes Learn 🎉 VPS desde $4.99/mês
Guias Matt ConnorPor Matt Connor

Alternativas self-hosted ao Calendly: comparação prática

Compare Cal.com, Easy!Appointments, Rallly e DayOtter no seu VPS, com foco em sincronização bidirecional de calendário e envio de e-mail.

A resposta curta

Uma alternativa self-hosted ao Calendly tem de fazer uma coisa que as ferramentas internas no seu VPS nunca fazem: responder ao público. A página de reserva é o produto. Precisa de um nome de domínio real e de TLS (segurança da camada de transporte) desde o primeiro dia, além de conseguir enviar e-mail para pessoas que nunca ouviram falar do seu servidor.

Quatro projetos cobrem as opções realistas. O Cal.com é a alternativa mais próxima do Calendly e a escolha padrão para um consultor independente. O Easy!Appointments é a opção leve, baseada em PHP e MySQL, e funciona bem num VPS com 1 GB. O Rallly é uma ferramenta para sondagens de grupo e não tem qualquer página de reserva. O DayOtter é o projeto mais recente, uma plataforma de agendamento com licença AGPLv3 e um assistente de confirmação antes do agendamento.

Duas perguntas determinam qual deles pode realmente executar. Sincroniza nos dois sentidos com o calendário que já utiliza? E consegue enviar e-mail? A segunda pergunta é onde a maioria das configurações de reserva self-hosted falha silenciosamente, por isso aparece primeiro.

O envio de email é a parte que falha

Uma confirmação de reserva chega à caixa de entrada de um desconhecido. Esse é um email transacional que chega ao Gmail ou ao Microsoft 365, e esses destinatários avaliam o remetente com base no endereço IP de envio e nos seus registos DNS.

Enviar diretamente a partir do VPS quase nunca funciona. A maioria dos fornecedores bloqueia a porta TCP 25 de saída em contas novas, por isso a ligação fica pendurada e acaba por atingir o tempo limite. Mesmo quando a porta 25 está aberta, um endereço de VPS novo não tem histórico de envio, e os grandes destinatários consideram suspeitos os endereços desconhecidos de intervalos de alojamento. A reserva é gravada na base de dados, a página indica que foi confirmada e ninguém recebe um email. Nada parece estar avariado no lado do servidor, por isso este problema costuma ser descoberto semanas depois por um cliente que nunca apareceu.

Use um relay. Qualquer fornecedor de email transacional funciona, e a aplicação só precisa de um hostname, uma porta, um utilizador e uma palavra-passe. Confirme se a porta está acessível antes de alterar a configuração da aplicação:

nc -vz -w 5 "$SMTP_HOST" 587

Uma linha succeeded significa que o caminho está aberto. Uma espera prolongada ou Connection refused significa que a porta está bloqueada ao nível da rede, e editar .env não resolverá o problema. Os relays escutam nas portas 587 ou 465 precisamente porque a porta 25 é bloqueada com muita frequência.

Cada projeto recebe o relay à sua maneira. O Cal.com lê EMAIL_FROM, EMAIL_SERVER_HOST, EMAIL_SERVER_PORT, EMAIL_SERVER_USER e EMAIL_SERVER_PASSWORD, e também aceita um RESEND_API_KEY. Tenha atenção a esse ponto: o .env.example incluído aponta EMAIL_SERVER_HOST para localhost na porta 1025, que corresponde a uma caixa de correio de desenvolvimento local. Se deixar o valor predefinido, a aplicação envia as mensagens para lado nenhum sem apresentar um erro. O Rallly usa SMTP_HOST, SMTP_PORT, SMTP_USER e SMTP_PWD. O DayOtter usa definições SMTP ou uma chave Resend. O Easy!Appointments envia as notificações a partir da aplicação, por isso configure o mesmo relay na respetiva página de definições antes de aceitar uma reserva real.

Depois, publique os registos DNS fornecidos pelo relay. Um registo SPF (sender policy framework) indica quais os servidores autorizados a enviar pelo seu domínio, e uma chave DKIM (domainkeys identified mail) assina cada mensagem para que o destinatário possa confirmar que não foi alterada. Adicione uma política DMARC (domain-based message authentication, reporting and conformance) depois de ambos passarem. Envie uma reserva de teste para um endereço real num grande fornecedor, abra os cabeçalhos da mensagem e confirme que as linhas de autenticação mostram pass. Uma página de reservas que não consegue enviar mensagens é pior do que não ter uma página de reservas, porque falha silenciosamente.

Quais backends de calendário sincronizam realmente nos dois sentidos

A sincronização tem dois sentidos, e eles falham separadamente. O sentido de leitura corresponde à disponibilidade: a aplicação tem de ver os seus períodos já ocupados, caso contrário pode disponibilizar um horário em que já está ocupado. O sentido de escrita corresponde à reserva: o evento confirmado tem de aparecer no calendário que consulta efetivamente, e não apenas dentro da ferramenta de reservas.

Google Calendar e Microsoft 365 funcionam nos dois sentidos, com uma condição numa instalação self-hosted. Tem de criar o cliente OAuth (autorização aberta), porque o client ID do produto alojado não está no código-fonte. No Cal.com, esse cliente é definido em GOOGLE_API_CREDENTIALS no ficheiro .env, que contém o JSON transferido da Google Cloud Console. O DayOtter utiliza credenciais OAuth do Google e da Microsoft da mesma forma.

Há duas situações que causam problemas, e convém conhecê-las antes de começar. Primeiro, o redirect URI registado tem de corresponder exatamente ao seu URL público, incluindo o esquema e qualquer caminho final. Caso contrário, o Google interrompe a ligação com redirect_uri_mismatch no ecrã de consentimento. Segundo, um projeto Google que permaneça com o estado de publicação Testing emite refresh tokens que expiram após sete dias. A sincronização funciona durante toda a semana e depois para; nos logs da aplicação aparece invalid_grant na atualização seguinte. Altere o ecrã de consentimento para In production ou aceite voltar a ligar manualmente todas as segundas-feiras.

CalDAV (extensões de calendário do WebDAV) é a opção aberta, mas o suporte é mais limitado. O Cal.com inclui uma aplicação CalDAV que ainda está marcada como beta e foi verificada com servidores como Baikal, Radicale, Nextcloud e Kerio Connect. O Apple iCloud funciona através da mesma aplicação, mas requer uma palavra-passe específica da aplicação em vez da palavra-passe do Apple ID. O DayOtter apresenta a Apple através de CalDAV juntamente com Google e Microsoft 365.

Um feed ICS não é uma sincronização. Um URL .ics subscrito é apenas de leitura por definição. Pode bloquear horários na sua página de reservas, mas nunca pode receber a reserva. Se uma ferramenta oferecer apenas ICS para o seu calendário, terá metade da integração e continuará a copiar eventos manualmente.

O Easy!Appointments sincroniza o Google Calendar e nada mais. O Rallly não lê a disponibilidade: recolhe votos sobre um conjunto de datas candidatas. É a ferramenta certa para saber "quando podemos reunir os seis" e a ferramenta errada para "marcar 30 minutos comigo".

Uma página de reservas é pública, portanto o TLS vem primeiro

A maior parte do que as pessoas alojam por conta própria é privada. Um wiki, um quadro ou um dashboard podem ficar atrás de uma VPN ou de um início de sessão SSO sem nunca ficarem acessíveis pela Internet pública. Um link de reservas não pode. Qualquer pessoa a quem o envie tem de o abrir. Isto altera a configuração de três formas concretas.

Antes de instalar qualquer componente, precisa de um nome de domínio com um registo A apontado para o VPS. Precisa de um certificado desde o primeiro dia, porque os browsers marcam um formulário HTTP simples como não seguro e o cliente vai introduzir nele o nome e o endereço de e-mail. Também precisa de definir corretamente o URL público da aplicação na configuração, porque esse valor é incorporado nos links das mensagens de e-mail enviadas e nos URIs de redirecionamento OAuth. Defina NEXT_PUBLIC_WEBAPP_URL no Cal.com, DOMAIN no Rallly, BASE_URL no Easy!Appointments ou DAYOTTER_DOMAIN durante a instalação, e atribua-lhe o endereço https:// que irá realmente utilizar.

O Rallly e o DayOtter tratam do TLS por si. A stack incluída no Rallly contém o Traefik e emite certificados Let's Encrypt usando o endereço em ACME_EMAIL. O instalador do DayOtter inicia o Caddy com HTTPS automático. O Cal.com e o Easy!Appointments não fazem isso. Por isso, coloque o nginx à frente e emita o certificado manualmente, tal como faria para um certificado Let's Encrypt no nginx com o Certbot. Faça o bind do contentor da aplicação a 127.0.0.1, para que a única forma de acesso seja através do proxy que controla. Se o mesmo servidor já executar uma alternativa self-hosted ao Trello para os seus quadros internos, mantenha-a atrás da autenticação existente e atribua apenas ao host de reservas um bloco de servidor público.

Cal.com no seu VPS

A configuração do Docker está no seu próprio repositório, e as imagens são pré-compiladas no Docker Hub. Por isso, faça pull em vez de as compilar.

git clone --recursive https://github.com/calcom/cal.diy.git
cd cal.diy
cp .env.example .env
openssl rand -base64 32
openssl rand -base64 24
docker compose pull
docker compose up -d

O primeiro valor aleatório vai em NEXTAUTH_SECRET e o segundo em CALENDSO_ENCRYPTION_KEY. Ambos são obrigatórios. Defina DATABASE_URL e aponte NEXT_PUBLIC_WEBAPP_URL para o seu endereço público. A stack incluída é composta pela aplicação web, PostgreSQL e Prisma Studio. A documentação indica docker compose up -d calcom para executar apenas a aplicação e usar uma base de dados alojada noutro local. É essa a opção a usar depois de concluir a instalação.

Faça pull da imagem. Não a compile no VPS. As instruções do projeto indicam que deve exportar NODE_OPTIONS="--max-old-space-size=16384" ao compilar a partir do código-fonte. Essa variável reserva um heap de 16 GB apenas para o Node. Em hardware ARM, adicione o sufixo -arm à tag da imagem. O projeto não publica um requisito mínimo para executar a imagem pré-compilada. Por isso, considere 2 GB para a aplicação e o PostgreSQL como uma estimativa de trabalho, não como um valor documentado, e monitorize a memória durante a primeira semana.

Confirme que iniciou:

docker compose ps
docker compose logs -f calcom
curl -sI https://cal.example.com | head -n 1

O curl deve imprimir HTTP/2 200. Um 502 Bad Gateway do nginx enquanto o contentor aparece como em execução normalmente significa que o primeiro arranque ainda está a aplicar migrações da base de dados. Aguarde alguns minutos e consulte os logs antes de concluir que há uma falha. Os webhooks do Cal.com são acionados em cada reserva confirmada. Uma reserva pode, por isso, acionar qualquer automatização que já execute, por exemplo uma instância do n8n acessível por HTTPS no seu VPS.

O núcleo é licenciado ao abrigo da AGPLv3. Algumas funcionalidades estão num diretório enterprise com uma licença comercial separada. Leia essa licença antes de criar um processo empresarial pago com as funcionalidades de equipas.

Easy!Appointments num servidor com 1 GB

Os requisitos são Apache ou Nginx, PHP 8.2 ou posterior e MySQL. Existe uma imagem oficial em alextselegidis/easyappointments.

Primeiro, um aviso. O docker-compose.yml no repositório é um ambiente de desenvolvimento. Ele espera que abra uma shell no contentor e execute npm install && composer install && npm start. Não é uma implementação para produção. Use antes a imagem publicada:

services:
  easyappointments:
    image: alextselegidis/easyappointments  # pin the current tag from Docker Hub
    environment:
      - BASE_URL=https://book.example.com
      - DB_HOST=mysql
      - DB_NAME=easyappointments
      - DB_USERNAME=easyapp
      - DB_PASSWORD=change-me
    ports:
      - '127.0.0.1:8080:80'
    depends_on:
      - mysql
  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=change-me-too
      - MYSQL_DATABASE=easyappointments
      - MYSQL_USER=easyapp
      - MYSQL_PASSWORD=change-me
    volumes:
      - ./mysql:/var/lib/mysql

BASE_URL tem de ser o endereço HTTPS público. Se o definir incorretamente, os links de marcação nas mensagens de confirmação apontam para um host que o cliente não consegue alcançar. A imagem disponibiliza HTTP simples na porta 80, sem certificado próprio. Por isso, a porta é associada a 127.0.0.1 e o nginx termina o TLS à frente. Se a sintaxe do Compose for nova para si, comece por Noções básicas de Docker Compose num VPS e depois volte.

Esta é, de longe, a opção mais leve. Dois contentores, uma aplicação PHP e o MySQL, funcionam confortavelmente num VPS com 1 GB. A limitação é a integração: o Google Calendar é o único backend de calendário, e a interface é um painel de administração tradicional, não um fluxo moderno de marcação. Se o seu calendário for Microsoft 365, Fastmail ou Nextcloud, esta opção fica excluída desde o início.

Rallly para sondagens de grupo

O Rallly responde a uma pergunta diferente. Não publica a sua disponibilidade. Apresenta um conjunto de horários candidatos a um grupo e recolhe votos. É isso que pretende para uma reunião da direção e é inútil para uma ligação de marcação por parte de um cliente.

curl -fsSL https://get.rallly.co | bash

Leia qualquer script antes de o encaminhar para uma shell. Substitua bash por less, leia o que ele faz e só depois execute-o. O procedimento manual faz o mesmo trabalho em etapas que pode verificar:

git clone https://github.com/lukevella/rallly-selfhosted.git
cd rallly-selfhosted
./rallly.sh setup
./rallly.sh start

Os requisitos documentados são, no mínimo, 2 GB de RAM, Docker 19.03 ou mais recente com Compose v2, as portas 80 e 443 livres e um domínio apontado para o servidor. A stack incluída contém Traefik para HTTPS, a aplicação Web, PostgreSQL e Garage para armazenamento de objetos compatível com S3. Defina DOMAIN, um SECRET_PASSWORD com pelo menos 32 caracteres, SUPPORT_EMAIL e INITIAL_ADMIN_EMAIL. Se já utiliza um reverse proxy, defina PROXY_MODE=external e WEB_PORT para que o Traefik não interfira. Se já utiliza um armazenamento de objetos compatível com S3 alojado localmente com MinIO, aponte as variáveis S3_* para esse serviço e remova o contentor Garage.

O SMTP não é opcional neste caso, porque o início de sessão é feito através de uma ligação mágica. Sem um relay funcional, ninguém consegue iniciar sessão, incluindo a conta de administrador que acabou de criar. Esta é a versão aceitável da falha de email: impede o acesso imediatamente, em vez de perder a marcação de um cliente três semanas mais tarde.

DayOtter, o participante mais recente

DayOtter é uma plataforma de agendamento AGPLv3 com um assistente integrado. A instalação em produção é feita com um comando:

curl -fsSL https://raw.githubusercontent.com/Dayotter/dayotter/main/deploy/install.sh \
  | sudo DAYOTTER_DOMAIN=cal.example.com bash

Leia-o antes de o executar, como indicado acima. O instalador configura o Docker, gera segredos e inicia toda a stack: a aplicação web Next.js, um worker em segundo plano que trata de lembretes, sincronização de calendários e webhooks, PostgreSQL, Redis e Caddy com HTTPS automático.

O suporte a calendários é o mais abrangente dos quatro. Google, Microsoft 365, Apple através de CalDAV e feeds ICS, com a ressalva relativa ao ICS indicada acima. Todas as outras integrações são opcionais e configuradas através de variáveis de ambiente, incluindo SMTP ou Resend para correio, ANTHROPIC_API_KEY para o assistente, Twilio para SMS e Stripe para pagamentos. O assistente pede confirmação primeiro: propõe a ação, o utilizador aprova e nada é adicionado ao calendário sem uma confirmação explícita. Deixe a chave da API vazia e essa parte do produto simplesmente não será executada.

O licenciamento é simples para quem aloja o serviço por conta própria. O núcleo está licenciado sob AGPLv3, e um diretório ee/ contém uma licença comercial exclusiva para a cloud, que permanece inativa enquanto DAYOTTER_CLOUD=1 não estiver definida. Isto significa que as funcionalidades de equipa incluídas no plano alojado, faturado a $9 por utilizador por mês em agosto de 2026, ficam disponíveis no seu próprio servidor.

Esta é também a stack mais pesada desta lista e o projeto mais recente. Execute-a junto da sua ligação de agendamento atual durante duas semanas, aceite reservas reais através de ambas e consulte os logs do worker antes de transferir os seus clientes.

O custo real de cada stack

A contagem de contentores é o indicador mais fiável do que uma stack irá exigir de um VPS pequeno, porque cada serviço tem o seu próprio consumo mínimo de memória. Estas são as contagens da stack Docker publicada pelo próprio projeto, consultadas em agosto de 2026.

ChartServices in each project's documented Docker stack
The data behind this chart
[
  {
    "tool": "Easy!Appointments",
    "containers": 2,
    "database": "MySQL"
  },
  {
    "tool": "Cal.com",
    "containers": 3,
    "database": "PostgreSQL"
  },
  {
    "tool": "Rallly",
    "containers": 4,
    "database": "PostgreSQL"
  },
  {
    "tool": "DayOtter",
    "containers": 5,
    "database": "PostgreSQL and Redis"
  }
]

O Easy!Appointments precisa de 2 contentores e funciona com 1 GB. A stack incluída do Rallly tem 4, e a documentação recomenda 2 GB. O instalador do DayOtter inicia 5, razão pela qual este requer o servidor com mais recursos entre os 4 aqui apresentados. O Cal.com e o DayOtter não publicam qualquer requisito mínimo de memória, por isso 2 GB é o ponto de partida que uso para ambos, e não um valor oficialmente suportado.

Duas destas contagens diminuem se já tiver infraestrutura em execução. Os contentores Traefik e Garage do Rallly deixam de ser necessários quando o serviço é configurado para usar o seu próprio proxy e armazenamento de objetos. O Prisma Studio do Cal.com é uma ferramenta de desenvolvimento que não deve permanecer em execução num servidor público.

Qual alternativa self-hosted ao Calendly deve escolher

Um consultor independente deve usar o Cal.com. É o único projeto desta lista que combina uma página de reservas reconhecível, imagens pré-criadas que evitam uma compilação do Node no VPS e suporte a CalDAV para quem não mantém um calendário no Google ou na Microsoft. Uma base de dados PostgreSQL e um contentor da aplicação representam uma carga de manutenção que pode gerir durante anos. Reserve uma tarde para configurar o cliente OAuth e o relay de correio, e tenha em atenção que a aplicação CalDAV ainda está em beta. Teste uma reserva real de ponta a ponta antes de publicar a ligação.

Uma equipa pequena deve considerar o DayOtter. O round robin ponderado e as reservas coletivas fazem parte do núcleo AGPLv3. Por isso, o self-hosting fornece funcionalidades que um serviço alojado cobraria por utilizador. O processo worker foi concebido para os lembretes e webhooks de que uma equipa realmente depende. A contrapartida é a maturidade: é o projeto mais recente desta lista. Execute-o primeiro em paralelo e mantenha a ligação antiga ativa até observar um mês completo de reservas.

Há dois casos mais específicos. Se apenas precisa de uma sondagem para encontrar uma hora em que o grupo possa reunir-se, instale o Rallly e fique por aí. Se tem um VPS de 1 GB, usa o Google Calendar e quer a solução mais pequena que aceite reservas, o Easy!Appointments durará mais do que qualquer opção mais complexa que possa instalar nesse servidor. Para a questão mais ampla sobre o que merece espaço no mesmo servidor, consulte o que vale a pena alojar por conta própria em 2026.

FAQ

Posso executar uma página de reservas autoalojada sem um nome de domínio?

Não. Todas estas aplicações escrevem o URL público nas ligações incluídas nos e-mails de confirmação, e tanto o Google como a Microsoft comparam o URI de redirecionamento OAuth com esse mesmo valor. Por isso, um endereço IP isolado apresenta redirect_uri_mismatch no ecrã de consentimento. O Let's Encrypt também não emite certificados para endereços IP, portanto a página é carregada por HTTP simples e o navegador marca o formulário como não seguro. Compre primeiro o domínio, aponte um registo A para o VPS e só depois faça a instalação.

Porque nunca chegam os meus e-mails de confirmação de reservas?

Quase sempre porque o servidor está a tentar entregar o e-mail diretamente. A maioria dos fornecedores de VPS bloqueia a porta de saída 25 em contas novas, por isso a ligação fica bloqueada. Mesmo quando a porta está aberta, um endereço novo não tem reputação de envio e os grandes destinatários recusam as mensagens. Configure a aplicação para usar um relay de e-mail transacional na porta 587, confirme que a porta está acessível com nc -vz -w 5 "$SMTP_HOST" 587 e publique os registos SPF e DKIM fornecidos pelo relay. Se estiver a executar o Cal.com, confirme que substituiu os valores predefinidos EMAIL_SERVER_HOST=localhost e EMAIL_SERVER_PORT=1025 incluídos no software, que apontam para uma caixa de correio de desenvolvimento local.

O Cal.com autoalojado sincroniza com CalDAV ou apenas com o Google?

Com ambos, mas com níveis de maturidade diferentes. A aplicação CalDAV está marcada como beta e foi verificada com servidores como Baikal, Radicale, Nextcloud e Kerio Connect. O Apple iCloud também funciona através dela com uma palavra-passe específica da aplicação. O Google Calendar e o Microsoft 365 sincronizam nos dois sentidos, mas numa instalação autoalojada tem de criar o seu próprio cliente OAuth e fornecê-lo através de GOOGLE_API_CREDENTIALS, porque as credenciais do serviço alojado não estão no código-fonte.

Porque a sincronização com o Google Calendar deixa de funcionar ao fim de uma semana?

Porque o projeto Google Cloud ainda está com o estado de publicação Testing. O Google emite tokens de atualização para aplicações nesse estado, mas estes expiram ao fim de sete dias. Por isso, a ligação funciona inicialmente e falha na atualização seguinte do token. O log da aplicação apresenta invalid_grant. Altere o ecrã de consentimento OAuth para In production e volte a ligar o calendário uma vez. Voltar a ligar sem alterar o estado dá-lhe mais sete dias, mas não mais do que isso.

Qual destas aplicações funciona num VPS com 1 GB?

A Easy!Appointments funciona, porque é uma aplicação PHP com MySQL. A documentação do Rallly indica um mínimo de 2 GB e a stack incluída executa quatro serviços. O Cal.com e o DayOtter não indicam um mínimo, mas uma aplicação Next.js com PostgreSQL e, no caso do DayOtter, também Redis e um processo worker, significa que deve planear 2 GB ou mais. Nunca compile o Cal.com a partir do código-fonte num servidor pequeno: as instruções de compilação do próprio projeto pedem um heap do Node de 16 GB. Em vez disso, use a imagem pré-compilada.

#scheduling#calendly#cal-com#self-hosted#booking