Alternative self-hosted a Calendly a confronto
Confronta Cal.com, Easy!Appointments, Rallly e DayOtter su VPS: sincronizzazione bidirezionale dei calendari e invio email, i due limiti delle installazioni self-hosted.
La risposta breve
Un’alternativa self-hosted a Calendly deve fare una cosa che gli strumenti interni sul tuo VPS non fanno mai: rispondere al pubblico. La pagina di prenotazione è il prodotto. Fin dal primo giorno richiede un nome di dominio reale e TLS (sicurezza del livello di trasporto), e deve consegnare email a persone che non hanno mai sentito parlare del tuo server.
Quattro progetti coprono le opzioni realistiche. Cal.com è l’alternativa più simile a Calendly e la scelta predefinita per un consulente che lavora da solo. Easy!Appointments è la soluzione più leggera, basata su PHP e MySQL, e funziona bene su un VPS da 1 GB. Rallly è uno strumento per i sondaggi di gruppo e non dispone di alcuna pagina di prenotazione. DayOtter è il progetto più recente: una piattaforma di scheduling con licenza AGPLv3 e un assistente con conferma obbligatoria prima dell'azione.
Due domande determinano quale soluzione puoi realmente eseguire. Si sincronizza in entrambe le direzioni con il calendario che usi già? E può inviare email? La seconda domanda è il punto in cui la maggior parte delle configurazioni self-hosted per le prenotazioni fallisce senza segnalarlo chiaramente, quindi viene prima.
La posta in uscita è la parte che non funziona
Una conferma di prenotazione finisce nella casella di posta di uno sconosciuto. Questa è posta transazionale recapitata a Gmail o Microsoft 365, e questi destinatari valutano l'indirizzo IP di invio e i record DNS.
L'invio diretto dal VPS quasi mai funziona. La maggior parte dei provider blocca la porta TCP in uscita 25 sui nuovi account, quindi la connessione resta in attesa e poi va in timeout. Anche quando la porta 25 è aperta, un indirizzo VPS appena assegnato non ha una cronologia di invio e i grandi destinatari considerano sospetti gli indirizzi appartenenti a intervalli di hosting sconosciuti. La prenotazione viene scritta nel database, la pagina indica che è confermata e nessuno riceve un'email. Dal lato server non sembra esserci alcun problema. Per questo il guasto viene spesso scoperto settimane dopo da un cliente che non si è presentato.
Usa un relay. Va bene qualsiasi provider di posta transazionale. L'applicazione ha bisogno soltanto di un hostname, una porta, un utente e una password. Verifica che la porta sia raggiungibile prima di modificare la configurazione dell'applicazione:
nc -vz -w 5 "$SMTP_HOST" 587Una riga succeeded indica che il percorso è aperto. Un'attesa indefinita o Connection refused indica che la porta è bloccata a livello di rete. Nessuna modifica a .env potrà risolvere il problema. I relay usano la porta 587 o 465 proprio perché la 25 è spesso bloccata.
Ogni progetto usa il relay in modo diverso. Cal.com legge EMAIL_FROM, EMAIL_SERVER_HOST, EMAIL_SERVER_PORT, EMAIL_SERVER_USER e EMAIL_SERVER_PASSWORD e accetta anche un RESEND_API_KEY. Presta attenzione a questo punto: il valore .env.example fornito con l'applicazione imposta EMAIL_SERVER_HOST su localhost alla porta 1025. Si tratta di una casella di posta locale per lo sviluppo. Se lasci il valore predefinito, l'applicazione invia i messaggi a una destinazione inesistente senza mostrare errori. Rallly usa SMTP_HOST, SMTP_PORT, SMTP_USER e SMTP_PWD. DayOtter usa le impostazioni SMTP o una chiave Resend. Easy!Appointments invia le notifiche dall'applicazione. Configuralo quindi con lo stesso relay dalla relativa pagina delle impostazioni prima di accettare una prenotazione reale.
Pubblica quindi i record DNS forniti dal relay. Un record SPF (sender policy framework) indica quali server possono inviare messaggi per il tuo dominio. Una chiave DKIM (domainkeys identified mail) firma ogni messaggio, così il destinatario può verificare che non sia stato modificato. Aggiungi una policy DMARC (domain-based message authentication, reporting and conformance) dopo che entrambi i controlli hanno avuto esito positivo. Invia una prenotazione di prova a un indirizzo reale presso un grande provider, apri gli header del messaggio e verifica che le righe di autenticazione riportino pass. Una pagina di prenotazione che non riesce a inviare messaggi è peggiore di una pagina di prenotazione assente, perché il problema si verifica senza alcun avviso.
Quali backend dei calendari sincronizzano davvero in entrambe le direzioni
La sincronizzazione ha due direzioni, che possono non funzionare separatamente. La direzione di lettura riguarda la disponibilità: l'applicazione deve vedere i blocchi già occupati, altrimenti proporrà un orario in cui hai già un impegno. La direzione di scrittura riguarda la prenotazione: l'evento confermato deve comparire nel calendario che consulti realmente, non soltanto nello strumento di prenotazione.
Google Calendar e Microsoft 365 supportano entrambe le direzioni, con una condizione per un'installazione self-hosted. Devi creare autonomamente il client OAuth (autorizzazione aperta), perché il client ID del prodotto ospitato non è incluso nel codice sorgente. Per Cal.com, il client è GOOGLE_API_CREDENTIALS in .env, che contiene il JSON scaricato dalla console Google Cloud. DayOtter usa allo stesso modo le credenziali OAuth di Google e Microsoft.
In questo caso possono verificarsi due problemi, che è utile conoscere prima di iniziare. Primo, l'URI di reindirizzamento registrato deve corrispondere esattamente al tuo URL pubblico, incluso lo schema e l'eventuale percorso finale. In caso contrario, Google interrompe la connessione con redirect_uri_mismatch nella schermata del consenso. Secondo, un progetto Google lasciato nello stato di pubblicazione Testing emette token di aggiornamento che scadono dopo sette giorni. La sincronizzazione funziona per tutta la settimana, poi si interrompe e nei log dell'applicazione compare invalid_grant al successivo aggiornamento. Imposta la schermata del consenso su In production, oppure accetta di riconnetterti manualmente ogni lunedì.
CalDAV (estensioni di calendaring per WebDAV) è l'opzione aperta, ma il supporto è più limitato. Cal.com include un'app CalDAV ancora contrassegnata come beta, verificata con server tra cui Baikal, Radicale, Nextcloud e Kerio Connect. Apple iCloud funziona tramite la stessa app, ma richiede una password specifica per l'app invece della password dell'Apple ID. DayOtter elenca Apple tramite CalDAV accanto a Google e Microsoft 365.
Un feed ICS non è una sincronizzazione. Un URL .ics sottoscritto è di sola lettura per progettazione. Può quindi bloccare gli orari nella pagina di prenotazione, ma non può mai ricevere la prenotazione. Se uno strumento offre soltanto ICS per il tuo calendario, hai configurato solo metà del flusso e dovrai comunque copiare manualmente gli eventi.
Easy!Appointments sincronizza Google Calendar e nessun altro servizio. Rallly non legge affatto la disponibilità: raccoglie voti su un insieme di date candidate. È lo strumento giusto per stabilire "quando possiamo incontrarci noi sei" e quello sbagliato per "prenota 30 minuti con me".
Una pagina di prenotazione è pubblica, quindi TLS viene prima
La maggior parte dei servizi che si ospitano autonomamente è privata. Un wiki, una bacheca o una dashboard possono restare dietro una VPN o un accesso SSO senza essere esposti a Internet. Un link di prenotazione non può farlo. Chiunque lo riceva deve poterlo aprire, e questo modifica la configurazione in tre aspetti concreti.
Prima di installare qualsiasi componente, serve un nome di dominio con un record A che punti al VPS. Serve un certificato fin dal primo giorno, perché i browser indicano come non sicuro un modulo HTTP semplice e l'utente vi inserisce nome e indirizzo email. Inoltre, l'URL pubblico dell'applicazione deve essere impostato correttamente nella configurazione, perché questo valore viene incorporato nei link delle email in uscita e negli URI di reindirizzamento OAuth. Imposta NEXT_PUBLIC_WEBAPP_URL in Cal.com, DOMAIN in Rallly, BASE_URL in Easy!Appointments oppure DAYOTTER_DOMAIN durante l'installazione, usando l'indirizzo https:// che utilizzerai effettivamente.
Rallly e DayOtter gestiscono TLS automaticamente. Lo stack incluso in Rallly contiene Traefik e genera certificati Let's Encrypt usando l'indirizzo specificato in ACME_EMAIL. L'installer di DayOtter avvia Caddy con HTTPS automatico. Cal.com ed Easy!Appointments non lo fanno: devi quindi mettere nginx davanti all'applicazione e generare personalmente il certificato, come faresti per un certificato Let's Encrypt su nginx con Certbot. Collega il container dell'applicazione a 127.0.0.1, in modo che l'unico accesso possibile passi dal proxy che controlli. Se lo stesso server esegue già un'alternativa self-hosted a Trello per le tue bacheche interne, mantienila dietro l'autenticazione esistente e assegna un blocco server pubblico soltanto all'host di prenotazione.
Cal.com sul tuo VPS
La configurazione Docker risiede in un repository separato e le immagini sono precompilate su Docker Hub, quindi devi eseguire il pull invece di compilare l'immagine.
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 -dIl primo valore casuale va inserito in NEXTAUTH_SECRET e il secondo in CALENDSO_ENCRYPTION_KEY. Sono obbligatori entrambi. Imposta DATABASE_URL e fai puntare NEXT_PUBLIC_WEBAPP_URL al tuo indirizzo pubblico. Lo stack incluso comprende l'applicazione web, PostgreSQL e Prisma Studio; la documentazione indica docker compose up -d calcom per eseguire solo l'applicazione usando un database ospitato altrove. È la configurazione da usare quando l'installazione è stabile.
Esegui il pull dell'immagine invece di compilarla sul VPS. Le istruzioni del progetto indicano di esportare NODE_OPTIONS="--max-old-space-size=16384" quando si compila dai sorgenti. Si tratta di un heap da 16 GB riservato al solo Node. Sui sistemi ARM, aggiungi il suffisso -arm al tag dell'immagine. Il progetto non specifica un requisito minimo per eseguire l'immagine precompilata. Considera quindi 2 GB per l'applicazione e PostgreSQL come una stima operativa personale, non come un valore documentato, e monitora la memoria durante la prima settimana.
Verifica che il servizio sia in esecuzione:
docker compose ps
docker compose logs -f calcom
curl -sI https://cal.example.com | head -n 1Il comando curl dovrebbe stampare HTTP/2 200. Un 502 Bad Gateway restituito da nginx mentre il container risulta in esecuzione indica in genere che il primo avvio sta ancora applicando le migrazioni del database. Attendi alcuni minuti e consulta i log prima di concludere che il servizio non funziona. I webhook di Cal.com vengono attivati per ogni prenotazione confermata. Una prenotazione può quindi avviare qualsiasi automazione già in uso, ad esempio un'istanza di n8n raggiungibile via HTTPS sul tuo VPS.
Il componente principale è distribuito con licenza AGPLv3, mentre alcune funzionalità si trovano in una directory enterprise con una licenza commerciale separata. Leggi la licenza prima di creare un processo aziendale a pagamento basato sulle funzionalità per i team.
Easy!Appointments su un server da 1 GB
I requisiti sono Apache o Nginx, PHP 8.2 o versione successiva e MySQL. È disponibile un’immagine ufficiale all’indirizzo alextselegidis/easyappointments.
Prima di tutto, una precisazione. Il docker-compose.yml nel repository è un ambiente di sviluppo. Presuppone l’apertura di una shell nel container e l’esecuzione di npm install && composer install && npm start. Non è una configurazione per il deployment. Usa invece l’immagine pubblicata:
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/mysqlBASE_URL deve essere l’indirizzo HTTPS pubblico. Se lo imposti in modo errato, i link di prenotazione nelle email di conferma punteranno a un host che il cliente non può raggiungere. L’immagine espone HTTP in chiaro sulla porta 80 e non dispone di un certificato proprio. Per questo la porta è associata a 127.0.0.1 e nginx gestisce la terminazione TLS davanti all’applicazione. Se la sintassi di Compose è nuova per te, inizia da Nozioni di base su Docker Compose su un VPS e poi torna qui.
Questa è di gran lunga l’opzione più leggera. Due container, un’applicazione PHP e MySQL, funzionano senza problemi su un VPS da 1 GB. Il compromesso è il numero limitato di integrazioni: Google Calendar è l’unico backend per i calendari e l’interfaccia è un pannello di amministrazione tradizionale, non un moderno flusso di prenotazione. Se il tuo calendario è Microsoft 365, Fastmail o Nextcloud, questa soluzione non è adatta.
Rallly per i sondaggi di gruppo
Rallly risponde a una domanda diversa. Non pubblica la tua disponibilità. Presenta a un gruppo un insieme di orari candidati e raccoglie i voti. È ciò che serve per una riunione del consiglio, ma non per un link di prenotazione destinato ai clienti.
curl -fsSL https://get.rallly.co | bashLeggi sempre uno script prima di inoltrarlo a una shell. Sostituisci bash con less, verifica cosa esegue, quindi avvialo. La procedura manuale svolge lo stesso lavoro in passaggi visibili:
git clone https://github.com/lukevella/rallly-selfhosted.git
cd rallly-selfhosted
./rallly.sh setup
./rallly.sh startI requisiti documentati sono almeno 2 GB di RAM, Docker 19.03 o versione successiva con Compose v2, le porte 80 e 443 libere e un dominio che punti al server. Lo stack incluso contiene Traefik per HTTPS, l'applicazione web, PostgreSQL e Garage per l'object storage compatibile con S3. Imposta DOMAIN, un SECRET_PASSWORD di almeno 32 caratteri, SUPPORT_EMAIL e INITIAL_ADMIN_EMAIL. Se usi già un reverse proxy, imposta PROXY_MODE=external e WEB_PORT, così Traefik non interviene. Se usi già un object storage self-hosted compatibile con S3 basato su MinIO, assegna le variabili S3_* a quell'istanza e rimuovi il container Garage.
Qui SMTP è obbligatorio, perché l'accesso avviene tramite un magic link. Senza un relay funzionante nessuno può accedere, incluso l'account amministratore appena creato. Questo è l'esito meno grave di un problema email: blocca l'accesso invece di far perdere la prenotazione di un cliente tre settimane dopo.
DayOtter, il progetto più recente
DayOtter è una piattaforma di pianificazione con licenza AGPLv3 e un assistente integrato. L'installazione in produzione richiede un solo comando:
curl -fsSL https://raw.githubusercontent.com/Dayotter/dayotter/main/deploy/install.sh \
| sudo DAYOTTER_DOMAIN=cal.example.com bashLeggilo prima di eseguirlo, come indicato sopra. L'installer configura Docker, genera i secret e avvia l'intero stack: l'applicazione web Next.js, un worker in background che gestisce promemoria, sincronizzazione dei calendari e webhook, PostgreSQL, Redis e Caddy con HTTPS automatico.
Il supporto ai calendari è il più ampio dei quattro. Sono supportati Google, Microsoft 365, Apple tramite CalDAV e i feed ICS, con la limitazione relativa a ICS descritta sopra. Tutte le altre integrazioni sono opzionali e si configurano tramite variabili d'ambiente, inclusi SMTP o Resend per la posta, ANTHROPIC_API_KEY per l'assistente, Twilio per gli SMS e Stripe per i pagamenti. L'assistente richiede una conferma preventiva: propone un'azione, tu la approvi e nulla viene inserito nel calendario senza un sì esplicito. Lascia vuota la chiave API e questa parte del prodotto non viene eseguita.
La licenza è chiara per chi esegue il software in proprio. Il core è distribuito con licenza AGPLv3 e una directory ee/ contiene una licenza commerciale riservata al cloud, che resta inattiva finché non viene impostato DAYOTTER_CLOUD=1. Di conseguenza, le funzionalità per i team del piano hosted, fatturato a $9 per utente al mese ad agosto 2026, sono disponibili sul tuo server.
Questo è anche lo stack più pesante tra quelli descritti e il progetto più giovane. Eseguilo accanto al link di prenotazione esistente per due settimane, acquisisci prenotazioni reali tramite entrambi e consulta i log del worker prima di trasferire i clienti.
Il costo effettivo di ogni stack
Il numero di container è l'indicatore più affidabile del carico che uno stack imporrà a un piccolo VPS, perché ogni servizio richiede una propria quantità minima di memoria. Questi sono i conteggi pubblicati nei rispettivi stack Docker dei progetti, rilevati ad agosto 2026.
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"
}
]Easy!Appointments richiede 2 container e funziona con 1 GB. Lo stack incluso di Rallly conta 4 container e la documentazione richiede 2 GB. L'installer di DayOtter avvia 5 container; per questo richiede il server più grande tra i 4 qui elencati. Cal.com e DayOtter non pubblicano alcun requisito minimo di memoria, quindi per entrambi considero 2 GB il punto di partenza, non un valore ufficialmente supportato.
Due di questi conteggi diminuiscono se disponi già dell'infrastruttura necessaria. I container Traefik e Garage di Rallly non sono più necessari se lo colleghi al tuo proxy e al tuo object storage. Prisma Studio di Cal.com è uno strumento di sviluppo che non dovresti lasciare in esecuzione su un server pubblico.
Quale alternativa self-hosted a Calendly dovresti scegliere
Un consulente che lavora da solo dovrebbe usare Cal.com. È l'unico progetto di questo elenco che combina una pagina di prenotazione riconoscibile dagli utenti, immagini precompilate che evitano una build Node sul VPS e un'integrazione CalDAV per chi non usa un calendario Google o Microsoft. Un database PostgreSQL e un container applicativo costituiscono un carico di manutenzione sostenibile per anni. Metti in conto un pomeriggio per configurare il client OAuth e il mail relay. Tieni presente che l'app CalDAV è ancora in beta. Esegui quindi una prenotazione reale completa prima di pubblicare il link.
Un piccolo team dovrebbe valutare DayOtter. Il round robin ponderato e la prenotazione collettiva fanno parte del core AGPLv3. Con il self-hosting ottieni quindi funzioni che, in un servizio hosted, richiederebbero un abbonamento per ogni utente. Il processo worker è progettato per gestire i promemoria e i webhook che un team usa effettivamente. Il compromesso è la maturità del progetto: è il più recente di questo elenco. Eseguilo prima in parallelo e mantieni attivo il vecchio link finché non avrai osservato un mese intero di prenotazioni.
Ci sono due casi più specifici. Se ti serve soltanto un sondaggio per trovare un orario in cui il gruppo possa riunirsi, installa Rallly e fermati lì. Se hai un VPS da 1 GB, usi Google Calendar e vuoi l'applicazione più leggera possibile per ricevere prenotazioni, Easy!Appointments durerà più a lungo di qualsiasi alternativa più sofisticata che potresti installare su quel server. Per una panoramica più ampia di ciò che merita spazio sullo stesso server, consulta cosa vale la pena eseguire in self-hosting nel 2026.
FAQ
Posso eseguire una pagina di prenotazione self-hosted senza un nome di dominio?
No. Tutte queste applicazioni inseriscono l'URL pubblico nei link contenuti nelle e-mail di conferma. Inoltre, Google e Microsoft confrontano l'URI di reindirizzamento OAuth con lo stesso valore. Per questo, un semplice indirizzo IP produce redirect_uri_mismatch nella schermata di consenso. Anche Let's Encrypt non rilascia certificati per gli indirizzi IP. La pagina viene quindi caricata tramite HTTP non crittografato e il browser contrassegna il modulo come non sicuro. Acquista prima il dominio, punta un record A al VPS, quindi esegui l'installazione.
Perché le e-mail di conferma delle prenotazioni non arrivano mai?
Quasi sempre perché il server tenta di consegnare direttamente le e-mail. La maggior parte dei provider VPS blocca la porta in uscita 25 sui nuovi account. La connessione quindi resta in attesa. Inoltre, anche quando la porta è aperta, un nuovo indirizzo non ha una reputazione di invio e i grandi provider rifiutano i messaggi. Configura l'applicazione per usare un relay e-mail transazionale sulla porta 587. Verifica che la porta sia raggiungibile con nc -vz -w 5 "$SMTP_HOST" 587. Pubblica quindi i record SPF e DKIM forniti dal relay. Se esegui Cal.com, verifica di aver sostituito i valori predefiniti EMAIL_SERVER_HOST=localhost e EMAIL_SERVER_PORT=1025 inclusi nel pacchetto. Questi valori puntano a una casella e-mail locale per lo sviluppo.
Cal.com self-hosted si sincronizza con CalDAV o solo con Google?
Con entrambi, ma con livelli di maturità diversi. L'app CalDAV è contrassegnata come beta ed è verificata con server tra cui Baikal, Radicale, Nextcloud e Kerio Connect. Anche Apple iCloud funziona tramite questa app usando una password specifica per l'applicazione. Google Calendar e Microsoft 365 sincronizzano i dati in entrambe le direzioni. In un'installazione self-hosted devi però creare il tuo client OAuth e fornirlo tramite GOOGLE_API_CREDENTIALS, perché le credenziali del servizio hosted non sono incluse nel codice sorgente.
Perché la sincronizzazione con Google Calendar smette di funzionare dopo una settimana?
Perché il progetto Google Cloud è ancora nello stato di pubblicazione Testing. Google rilascia token di aggiornamento alle applicazioni in questo stato, ma questi token scadono dopo sette giorni. La connessione funziona inizialmente, quindi si interrompe al successivo aggiornamento del token e il log dell'applicazione mostra invalid_grant. Imposta la schermata di consenso OAuth su In production e riconnetti il calendario una volta. Riconnettere il calendario senza modificare lo stato consente di ottenere altri sette giorni, ma non oltre.
Quali di queste applicazioni funzionano su un VPS da 1 GB?
Easy!Appointments funziona, perché è un'applicazione PHP con MySQL. Rallly documenta un requisito minimo di 2 GB e il relativo stack incluso esegue quattro servizi. Cal.com e DayOtter non pubblicano requisiti minimi. Tuttavia, un'applicazione Next.js con PostgreSQL e, nel caso di DayOtter, anche Redis e un processo worker, richiede di pianificare almeno 2 GB. Non compilare mai Cal.com dal codice sorgente su un server con poche risorse. Le istruzioni di build del progetto richiedono un heap Node da 16 GB. Usa invece l'immagine precompilata.