> ## Content Index
> Fetch the complete content index at: https://ghost.tryviewsai.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Build a 100% Free Self-Hosted Booking System — No Calendly, No Subscription
- URL: https://ghost.tryviewsai.com/build-a-100-free-self-hosted-booking-system-no-calendly-no-subscription/
- Published: 2026-08-21T14:38:19.000Z
- Updated: 2026-08-21T14:38:18.000Z
- Author: Brendan O'Brien
- Tags: DIY, Bookings, Self-Hosted, Cloudflare, ViewsAI, #Import 2026-09-03 11:28

# Build a 100% Free Self-Hosted Booking System — No Calendly, No Subscription

If you sell a system that runs on free software, your calendar shouldn't be the thing that costs you money. Calendly Business is \~$15/user/month. Cal.com self-hosted *looks* free — until you realize recipients get a 404 because it's only reachable on your laptop.

Here's the stack that actually works, for $0 in software: **Rallly** (open-source scheduling) behind a **Cloudflare Tunnel** on your own domain. This is exactly what ViewsAI runs on, and it's the DIY playbook our customers get.

## Why self-hosted beats the SaaS calendar

- **Free forever** — no seats, no tiers, no upgrade nagging
- **Your domain** — bookings live at `booking.yourdomain.com`, which builds trust (nobody wants to book on someone's subdomain of a SaaS)
- **Private** — your data, your database
- **Ownership** — it's a component you can sell, teach, and hand over

## Part 1 — Run Rallly (the booking app)

Rallly is a free, self-hosted scheduling/poll app: create a poll with time options, share the link, participants pick a slot. Two Docker services: the app and its PostgreSQL database.

```
# ~/docker/rallly/docker-compose.yml
version: '3.8'
services:
  rallly:
    image: lukevella/rallly:latest
    ports: ["3009:3000"]
    environment:
      DATABASE_URL: "postgresql://rallly_user:rallly_pass@rallly-db:5432/rallly"
      NEXTAUTH_SECRET: "openssl rand -hex 32"
      NEXTAUTH_URL: "http://localhost:3009"
      SECRET_PASSWORD: "openssl rand -hex 24"     # required in new Rallly
      NEXT_PUBLIC_BASE_URL: "https://booking.YOURDOMAIN.com"  # required
      SUPPORT_EMAIL: "you@yourdomain.com"         # required
      NEXT_PUBLIC_SELF_HOSTED: "true"
      NODE_ENV: "production"
      DATABASE_SSL: "false"
    depends_on: [rallly-db]
  rallly-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: rallly_user
      POSTGRES_PASSWORD: rallly_pass
      POSTGRES_DB: rallly
    volumes: [rallly-db-data:/var/lib/postgresql/data]
volumes:
  rallly-db-data:
```

**Gotchas we hit:** newer Rallly crashes at boot with "Invalid environment variables" if you're missing `SECRET_PASSWORD`, `NEXT_PUBLIC_BASE_URL`, or `SUPPORT_EMAIL`. And the healthcheck path `/api/health` 404s — point it at `/` instead.

## Part 2 — Expose it with a Cloudflare Tunnel

A Cloudflare Tunnel gives your localhost a public URL with zero inbound ports open. Fully scriptable via API with a token that has Tunnel:Edit.

```
# 1) create the tunnel
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel" \
  -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"viewsai-booking","config_src":"local"}'

# 2) route hostname → local app (ingress)
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel/$TUNNEL_ID/configurations" \
  -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json" \
  -d '{"config":{"ingress":[{"hostname":"booking.YOURDOMAIN.com","service":"http://localhost:3009"},{"service":"http_status:404"}]}}'

# 3) grab the tunnel token and run cloudflared with it
curl -H "Authorization: Bearer $CF_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT/cfd_tunnel/$TUNNEL_ID/token"
# → save it, run: cloudflared tunnel run --token <token>  (as a launchd service on macOS)
```

## Part 3 — The one manual step: DNS

Your tunnel token can't edit DNS, so add one CNAME in the Cloudflare dashboard:

```
Type: CNAME   Name: booking   Target: <TUNNEL_ID>.cfargotunnel.com   Proxy: Proxied (orange cloud)
```

## Part 4 — Verify and go

```
dig booking.YOURDOMAIN.com
curl https://booking.YOURDOMAIN.com   # 200 → Rallly loads
```

Then drop the link into your outbound emails. In the ViewsAI pipeline, the CTA lives in the email template — instead of "book a call" with no destination, every email can carry a real, clickable booking link.

## The money math

| Calendly Business | $15/user/mo                   |
| ----------------- | ----------------------------- |
| Cal.com cloud     | starts at $20/mo              |
| **This stack**    | **$0 software + your domain** |

The only real costs in the whole ViewsAI system are the email domain and sending mailboxes. Everything else — scheduling, CRM, automation, lead pipeline — runs on free, self-hosted, open-source software you own.

*Want this whole system? It's part of the ViewsAI stack — recruiting AI, outbound automation, and the free infrastructure that runs it all.*