I use scheduling links for consulting calls and demo bookings. The workflow is useful: send someone a link, they pick a slot, it goes into my calendar. The per-user cost for the hosted tools adds up, and for something this workflow-critical I'd rather control the infrastructure.
Cal.com is the open-source alternative to managed scheduling services. Same workflow — share a link, people book slots based on your availability — but running on your own server. Calendar integrations, Zoom link generation, booking forms, email reminders — all there.
Fair warning upfront: Cal.com is a large Next.js application. The build process is memory-hungry, and there's a specific Node.js memory flag you need to set or the build will fail. I'll cover that explicitly so you don't spend time debugging it.
I switched my consulting bookings to a self-hosted Cal.com instance after realizing I was paying for Calendly features I wasn't using while missing Cal.com features that would be useful. The setup is more involved than simpler apps, but once it's running, it's solid.
I run Cal.com on Tencent Cloud Lighthouse. Cal.com needs at least 2 GB RAM (PostgreSQL + Next.js); the 2 vCPU / 2 GB RAM plan is the starting point. For scheduling software specifically, uptime and reliable availability matter — your booking page needs to be accessible when someone follows a scheduling link. Lighthouse's stable infrastructure and the ability to upgrade specs from the control panel mean you can start lean and scale as your booking volume grows, without migrating to a new server. The snapshot feature is useful before Cal.com version upgrades, which can have database migration steps.
- Key Takeaways
| Requirement | Details |
|---|---|
| Server | Ubuntu 22.04, 2 GB+ RAM |
| Node.js | v18+ |
| PostgreSQL | 13+ |
| Domain | Required — Cal.com needs a domain for OAuth and email |
| SMTP credentials for booking confirmations |
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo bash -
sudo apt install -y nodejs
node --version # Should be v18.x
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable postgresql
sudo systemctl start postgresql
npm install -g yarn
cd /opt
sudo git clone https://github.com/calcom/cal.com.git
sudo chown -R ubuntu:ubuntu cal.com
cd cal.com
git fetch --tags
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
yarn install
This takes 3–5 minutes.
cp .env.example .env
nano .env
Key settings to configure:
# Database
DATABASE_URL=postgresql://calcom:your-db-password@localhost:5432/calcom
# NextAuth
NEXTAUTH_SECRET=generate-with-openssl-rand-base64-32
NEXTAUTH_URL=https://cal.yourdomain.com
# Calendso URL
NEXT_PUBLIC_WEBAPP_URL=https://cal.yourdomain.com
# Email configuration (required for booking confirmations)
EMAIL_FROM=noreply@yourdomain.com
EMAIL_SERVER_HOST=smtp.sendgrid.net
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER=apikey
EMAIL_SERVER_PASSWORD=your-sendgrid-api-key
# Optional: Google Calendar OAuth
GOOGLE_API_CREDENTIALS={"installed":{"client_id":"...","client_secret":"..."}}
Generate NEXTAUTH_SECRET:
openssl rand -base64 32
sudo -u postgres psql
CREATE USER calcom WITH ENCRYPTED PASSWORD 'your-db-password';
CREATE DATABASE calcom OWNER calcom;
GRANT ALL PRIVILEGES ON DATABASE calcom TO calcom;
\q
cd /opt/cal.com
yarn db:migrate
This creates all Cal.com tables. Takes about 1–2 minutes.
yarn db:seed
cd /opt/cal.com
yarn build
The build takes 5–10 minutes — Cal.com is a large Next.js application.
yarn start
Access via SSH tunnel: ssh -L 3000:localhost:3000 ubuntu@YOUR_SERVER_IP
Open http://localhost:3000 and create the first admin account.
Press Ctrl+C to stop.
sudo nano /etc/systemd/system/calcom.service
[Unit]
Description=Cal.com
After=network.target postgresql.service
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/cal.com
EnvironmentFile=/opt/cal.com/.env
ExecStart=/usr/bin/yarn start
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable calcom
sudo systemctl start calcom
sudo systemctl status calcom
sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/calcom
server {
listen 80;
server_name cal.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Cal.com needs longer timeouts for some operations
proxy_read_timeout 120s;
}
}
sudo ln -s /etc/nginx/sites-available/calcom /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d cal.yourdomain.com
Access Cal.com at https://cal.yourdomain.com and complete the admin setup.
https://cal.yourdomain.com/api/integrations/googlecalendar/callback as a redirect URI.env:GOOGLE_API_CREDENTIALS={"installed":{"client_id":"YOUR_CLIENT_ID","project_id":"project","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","client_secret":"YOUR_CLIENT_SECRET","redirect_uris":["https://cal.yourdomain.com/api/integrations/googlecalendar/callback"]}}
.env:ZOOM_CLIENT_ID=your-zoom-client-id
ZOOM_CLIENT_SECRET=your-zoom-client-secret
During the build step, I kept getting JavaScript heap out of memory errors:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Cal.com is a large monorepo and the build process is memory-intensive. On a 2 GB RAM server, the default Node.js heap limit (1.5 GB) wasn't enough.
The fix: Increase Node.js memory during the build:
export NODE_OPTIONS="--max-old-space-size=1536"
yarn build
Or add it to the build command in package.json temporarily:
NODE_OPTIONS='--max-old-space-size=1536' yarn build
After this, the build completed successfully. The startup memory footprint is smaller than the build memory requirement, so the service runs fine on 2 GB once built.
| Issue | Likely Cause | Fix |
|---|---|---|
| Build fails with OOM | Insufficient memory | Set NODE_OPTIONS="--max-old-space-size=1536" |
| Database connection error | Wrong DATABASE_URL | Check postgres user/password/database name |
| Email not sending | SMTP config error | Test SMTP credentials separately |
| OAuth redirect mismatch | Wrong callback URL | Add exact URL to Google/Zoom OAuth settings |
| "Invalid environment variable" | Missing required env vars | Check all required vars in .env.example |
| Slow load times | First request compiles pages | Normal for Next.js; subsequent requests are faster |
| Calendar not syncing | OAuth token expired | Re-connect calendar in Cal.com settings |
✅ What you built:
cal.yourdomain.com/yournameSelf-hosted Cal.com removes per-user fees while giving you full control over your scheduling data and branding.
What data does self-hosted Cal.com protect compared to cloud services?
Your content — notes, documents, calendar events, tasks — is stored on your server and never sent to a third party's infrastructure. This matters for sensitive personal or professional information.
Can I collaborate with others on a self-hosted Cal.com instance?
Most productivity tools support multiple users. The number of users depends on the tool and your server resources. Check the guide's prerequisites for per-user resource estimates.
How do I access self-hosted Cal.com from mobile devices?
Install the official mobile app and configure it to connect to your server URL instead of the default cloud service. The setup is typically done in the app's server settings.
What happens to my data if the server goes down?
Data on the server is preserved. You won't have access until the server is restored, but data isn't lost. Lighthouse snapshots provide backup and quick recovery.
docker compose pull) are typically straightforward. The guide includes update instructions specific to the application.👉 Get started with Tencent Cloud Lighthouse
👉 View current pricing and launch promotions
👉 Explore all active deals and offers