Skip to content

Repository files navigation

Calich

An open-source, self-hosted Google Calendar alternative with CalDAV sync.

Table of contents

Current features

  • Day, Week, Month and Year views, with drag-to-create, drag-to-move and resize.
  • Recurring events and all-day events
  • CalDAV: two-way sync with your phone and other calendar apps.
  • Workspaces: share calendars with other members, organize members into groups, and invite people by email.
  • Attendees and invitations — Invite others to events.
  • Reminders: in-app and email.
  • Attachments
  • Subscribed calendars: subscribe to any .ics URL.
  • Import and export of .ics and .zip files.
  • Light and dark themes, 12/24-hour time, and a configurable week start.

Screenshots

Dark mode

Week view — dark Month view — dark Event modal — dark

Light mode

Week view — light Month view — light Event modal — light

Deployment

Calich is a single binary serving both the API and the web app on one port (8080 by default). All persistent data live under one directory, so a deployment is the binary (or container) plus a volume.

Docker

The quickest way to get an instance running:

docker run -d \
  --name calich \
  -p 8080:8080 \
  -v /srv/calich/data:/data \

  -e INITIAL_EMAIL=you@example.com \ # Optional
  -e INITIAL_PASSWORD=change-me \ # Optional
  -e INITIAL_NAME=change-me \ # Optional
  -e COOKIE_SECURE=false \ # false by default, set to true when running behind a reverse proxy

  xiovv/calich:latest

Or with Compose:

services:
  calich:
    image: xiovv/calich:latest
    container_name: calich
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./data:/data
    environment:
      INITIAL_EMAIL: you@example.com # Optional
      INITIAL_PASSWORD: change-me # Optional
      INITIAL_NAME: change-me  # Optional
      COOKIE_SECURE: false # false by default, set to true when running behind a reverse proxy
docker compose up -d

INITIAL_EMAIL, INITIAL_PASSWORD and INITIAL_NAME create the first account on first start, and are ignored on every start afterward. They're optional: if you leave them out you will be redirected to the sign up page automatically to create your account.

To build the image yourself instead of pulling it:

make docker-build          # or: docker build -t calich-server .
make docker-run            # runs it on :8080, mounting ./data

Pre-compiled binaries

Grab the archive for your platform from the Releases page, unpack it, and run it:

tar -xzf calich_linux_amd64.tar.gz
sudo install calich-server /usr/local/bin/

sudo mkdir -p /var/lib/calich
DATA_DIR=/var/lib/calich \
INITIAL_EMAIL=you@example.com \
INITIAL_PASSWORD=change-me \
  calich-server

To run it as a service, a minimal systemd unit:

# /etc/systemd/system/calich.service
[Unit]
Description=Calich calendar server
After=network.target

[Service]
User=calich
Environment=DATA_DIR=/var/lib/calich
Environment=PORT=8080
ExecStart=/usr/local/bin/calich-server
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now calich

Building from source

You'll need Go 1.26+, Node 22+ and Yarn.

git clone https://github.com/XiovV/calich.git
cd calich

# 1. Build the web app
yarn install --frozen-lockfile
make build-frontend                       # writes ./dist

# 2. Embed it in the server and compile
cp -r dist/. server/internal/static/dist/
make build-backend VERSION=v1.0.0         # writes server/bin/calich-server

VERSION is optional. If left unset, the version badge will show dev.

Then run it:

DATA_DIR=/var/lib/calich \
INITIAL_EMAIL=you@example.com \
INITIAL_PASSWORD=change-me \
  ./server/bin/calich-server

For development, run the two halves separately instead — make dev-backend on :8080 and make dev-frontend for the Vite dev server, which proxies /api to it. make help lists every target.

CalDAV sync

Calich syncs two-way with any CalDAV-capable calendar app (iOS/macOS Calendar, Thunderbird, DAVx5, etc.).

  1. In Calich, go to Settings → App passwords.
  2. Give it a label (e.g. Phone) and click Generate.
  3. Copy the password shown — it's only displayed once.
  4. In your calendar app, add a CalDAV account using:
    • Server/URL: the domain your Calich instance runs at
    • Username: your Calich account email
    • Password: the app password you just generated

Each app password can be revoked independently without affecting your login or other devices.

Configuration

All configuration is by environment variable.

Variable Default What it does
PORT 8080 Port the server listens on.
DATA_DIR /data Directory holding all persistent state.
INITIAL_EMAIL Login identifier for the bootstrap account, created on first start if no account exists.
INITIAL_PASSWORD Password for that account. Set it and INITIAL_EMAIL together, or omit both and register through the first-run form.
INITIAL_NAME Admin Display name for that account.
ENABLE_SIGNUPS false Allow self-registration. The first account is always creatable regardless.
COOKIE_SECURE false Whether the refresh-token cookie is marked Secure. Defaults off so a plain-HTTP LAN deployment works out of the box. Set it to true whenever TLS is in front. See below.
MAX_ATTACHMENT_SIZE 26214400 (25 MiB) Largest single attachment accepted, in bytes.
MAX_ATTACHMENTS_PER_EVENT 10 How many attachments one event may carry.
SUBSCRIPTION_REFRESH_INTERVAL 1h Poll cadence for a subscribed calendar whose feed states none of its own. Go duration syntax.
INVITE_RATE_LIMIT_PER_HOUR 100 Per-user hourly ceiling on queued invitations.
AUTH_RATE_LIMIT_PER_EMAIL 10 Failed sign-in attempts per email per 15 minutes, across login and CalDAV.
AUTH_RATE_LIMIT_PER_IP 30 Failed sign-in attempts per IP per 15 minutes.
REGISTER_RATE_LIMIT_PER_IP 20 Registration attempts per IP per hour.
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM Outbound mail. Email reminders and invitations are only offered when all five are set.
IMAP_HOST / IMAP_PORT / IMAP_USER / IMAP_PASS The mailbox SMTP_FROM sends from, polled for invitation replies. Without it, invitations still send but no response ever comes back.

COOKIE_SECURE

Leave it false if you reach Calich over plain HTTP, such as a LAN address like http://192.168.1.50:8080 — browsers discard a Secure cookie sent from a non-HTTPS origin, so switching it on there makes logins silently fail to stick. Set it to true as soon as anything terminates TLS in front of Calich, otherwise the refresh token can leak over a plaintext request to your host. If Calich sees a request arrive over TLS while the setting is still off, it logs a warning telling you to flip it.

Behind a reverse proxy

Once you're terminating TLS, set COOKIE_SECURE=true alongside it:

services:
  calich:
    image: xiovv/calich:latest
    restart: unless-stopped
    volumes:
      - ./data:/data
    environment:
      COOKIE_SECURE: "true" # required once TLS is in front
    expose:
      - "8080"

A minimal Caddy site block, which handles certificates automatically:

calich.example.com {
    reverse_proxy calich:8080
}

Or nginx:

server {
    listen 443 ssl;
    server_name calich.example.com;

    ssl_certificate     /etc/letsencrypt/live/calich.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/calich.example.com/privkey.pem;

    location / {
        proxy_pass http://calich:8080;
        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;
    }
}

Data & backups

Everything this instance keeps is under DATA_DIR (default /data): calich.db (SQLite) and an attachments/ directory holding every uploaded file's bytes.

Roadmap

  • Keyboard shortcuts
  • Connect with Google Calendar
  • Agenda view and daily agenda reminders
  • Tasks integration
  • Booking pages
  • Mobile app

About

Alternative to Google Calendar with CalDAV support

Resources

Stars

42 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages