DEV Community

Cover image for Manage your meetings like a boss with self-hosted calender

Posted on


Manage your meetings like a boss with self-hosted calender

Calendly and other scheduling tools are awesome. It made our lives massively easier. We're using it for business meetings, side projects and anything else where we need some flexible coordination. However, most tools are very limited in terms of control, customization, data protection, and most important - they are not free! That's where Calendso & Synpse come in. Self-hosted, all your data sitting on your own machines. API-driven and ready to be deployed on your own domain. Full control of your events and data.

In this tutorial we will be deploying a self-hosted Calendso instance that lives under your own DNS domain. You will be able to share meeting links such as with your colleagues, clients and friends:


You will also be able to:

  • Integrate it with your Google calendar
  • Create multiple users for your organization
  • Create teams

The setup

Deployment will be handled in a declarative way through Synpse. Incoming traffic will be handled by Caddy server which will terminate HTTPS (it will also automatically retrieve TLS certificates for you) and route traffic to Calendso.

You will also be able to access Prisma Studio locally to create your and your team's users.


If you don't have your own DNS domain, just jump in our Discord channel and I will help you out with some alternatives (you can either use Webhook Relay's subdomains or use services like DuckDNS).

Configure DNS

If you are using Cloudflare, creating an A record looks like this:


You can consult your DNS provider's documentation on managing A records.

Configure port forwarding on your router (optional)

If you server where you are setting this up is within your local network, you will need to expose it to the internet. The easy way to do it is just using your own router to forward the ports:


If you don't have a static IP or your network is behind a CGNAT, you can use instead. We will be providing a tutorial on that setup as well.

Integrating with Google calendar

Bookings are great but it would be tedious to check your Calendso instance every day. To allow Calendso to read from and write to our Google calendar, we need to create API credentials and provide them to Calendso.

Enable the API

To do that, head to the Google API console and create a new project. It might take a little bit for Google to set up your project but once that's done, head over to the project and click the Enable APIs and Services button.

Once you click the button, you'll be taken to the API library. In the search box, look for calendar and select the Google Calendar API result and then enable it.

Retrieve credentials

Next, let's head to our credentials page in the Google API console so we can create the Calendso OAuth ID and add our production origin and redirect URI.


Your key will be created and you'll be redirected back to the Credentials page where you will see your newly generated OAuth 2.0 Client ID. Select the download option and save this file to your computer. Copy all the contents of the file and add that as the value for the GOOGLE_API_CREDENTIALS environment variable:


Deploy through Synpse

With Synpse we will be deploying multiple containers to provide us with admin capabilities, database, tunneling (to expose it to the internet) and the Calendso itself.

Preparing the secrets

First, go to your secrets page and create:

  • calendsoPostgres with your database password
  • calendsoPostgresConnString with postgresql://calendso:PASSWORD@postgres:5432/calendso (just replace PASSWORD with your database password)
  • calendsoEncKey with a random key that you generate yourself. You can generate one in your terminal with command openssl rand -base64 32


Creating the application

The full spec looks like this:

# Name of your app
name: synpse-calendso
  type: Conditional
  # Need to match your labels
  # Ref:
    type: controller
    - name: calendso
      image: ctadeu/calendso:0.0.17-1
        - name: BASE_URL
        - name: NEXTAUTH_URL
        - name: DATABASE_URL
          fromSecret: calendsoPostgresConnString
          fromSecret: calendsoEncKey
          fromSecret: calendsoGoogleApiCredentials
      restartPolicy: {}
    - name: prisma
      image: codejamninja/prisma-studio:latest
        - 5555:5555
        - name: POSTGRES_URL
          fromSecret: calendsoPostgresConnString
      restartPolicy: {}
    - name: postgres
      image: postgres:latest
        - /data/calendso-postgres:/var/lib/postgresql/data
        - name: PGDATA
          value: /var/lib/postgresql/data/pgdata
        - name: POSTGRES_USER
          value: calendso
        - name: POSTGRES_DB
          value: calendso
        - name: POSTGRES_PASSWORD
          fromSecret: calendsoPostgres
      restartPolicy: {}
    # Caddy provides HTTPS
    - name: caddy
      image: caddy:latest
        - caddy
        - reverse-proxy
        - --from
        - # This should be your domain and port, same as in your router
        - --to
        - calendso:3000
        - 7300:7300
        - /data/calendso-caddy:/data
        - /data/calendso-caddy-cfg:/config
      restartPolicy: {}

Enter fullscreen mode Exit fullscreen mode

Now, if you click on Allocations, you should see all containers running and in device details you can see the ports:


If you click on Prisma and if your device is locally reachable, you will be able to access the admin dashboard.

Please note, that if your device is exposed to the internet, you should not leave the Prisma container with the port exposed.

Once in Prisma, follow the official guide from self-hosting section and:

  1. Click on the User model to add a new user record.
  2. Fill out the fields (remembering to encrypt your password with BCrypt) and click Save 1 Record to create your first user.

Once you have logged in, go to the integrations section and connect it with the Google's calendar.


Originally published on

Top comments (0)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.