3X-UI is an advanced, open-source web control panel for managing Xray-core
servers. It provides a clean, multi-language interface for deploying,
configuring, and monitoring a wide range of proxy and VPN protocols —
from a single VPS to multi-node deployments.
Built as an enhanced fork of the original X-UI project,
3X-UI adds broader protocol support, improved stability, per-client
traffic accounting, and many quality-of-life features.
Important
This project is intended for personal use only. Please do not use it for illegal purposes or in a production environment.
During installation a random username, password, and access path are generated. After installation, run x-ui
to open the management menu, where you can start/stop the service, view
or reset your login credentials, manage SSL certificates, and more.
For full documentation, please visit the project Wiki.
Unattended install
The installer also runs non-interactively for cloud-init.
Set XUI_NONINTERACTIVE=1 (or pipe with no TTY) and it installs end-to-end with
zero prompts, generating random credentials and writing them to
/etc/x-ui/install-result.env. See deploy/ for:
Cloud-init user-data — unattended install on any cloud (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
3X-UI supports two backends, chosen during the install:
SQLite (default) — a single file at /etc/x-ui/x-ui.db. Zero setup, ideal for small and medium deployments.
PostgreSQL — recommended for high client counts or
multi-node setups. The installer can install PostgreSQL locally for you,
or accept a DSN to an existing server.
At runtime the backend is selected via environment variables (the installer writes these to /etc/default/x-ui for you):
Migrating an existing SQLite install to PostgreSQL
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"# then set XUI_DB_TYPE and XUI_DB_DSN in /etc/default/x-ui and restart:
systemctl restart x-ui
The source SQLite file is left untouched; remove it manually once you have verified the new backend.
Docker
The default docker compose up -d keeps using SQLite. To run with the bundled PostgreSQL service, uncomment the two XUI_DB_* env lines in docker-compose.yml and start with the profile:
docker compose --profile postgres up -d
The image bundles Fail2ban (enabled by default) to enforce per-client IP limits. Fail2ban bans offenders with iptables, which requires the NET_ADMIN capability. docker-compose.yml already grants it via cap_add; if you start the container with docker run instead, add the capabilities yourself, otherwise bans are logged but never applied:
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
Enable the tunnel health monitor (probes a URL and restarts xray after repeated failures; a restart drops all clients)
false
XUI_TUNNEL_HEALTH_PROXY
Proxy the probe is sent through; point it at a local xray inbound so the probe tests the tunnel (e.g. socks5://127.0.0.1:1080). Empty means the probe only checks host connectivity
—
XUI_TUNNEL_HEALTH_URL
URL probed for tunnel health
https://www.cloudflare.com/cdn-cgi/trace
XUI_TUNNEL_HEALTH_INTERVAL
Interval between probes
30s
XUI_TUNNEL_HEALTH_TIMEOUT
Per-probe timeout
10s
XUI_TUNNEL_HEALTH_FAILURES
Consecutive failures before a restart is triggered
Cal.diy is the community-driven, fully open-source scheduling platform — a fork of Cal.com with all enterprise/commercial code removed.
Cal.diy is 100% MIT-licensed with no
proprietary "Enterprise Edition" features. It's designed for individuals
and self-hosters who want full control over their scheduling
infrastructure without any commercial dependencies.
What's different from Cal.com?
No enterprise features — Teams, Organizations, Insights, Workflows, SSO/SAML, and other EE-only features have been removed
No license key required — Everything works out of the box, no Cal.com account or license needed
100% open source — The entire codebase is licensed under MIT, no "Open Core" split
Community-maintained — Contributions are welcome and go directly into this project (see CONTRIBUTING.md)
Note: Cal.diy is a self-hosted project. There is no managed version. You run it on your own infrastructure.
To get a local copy up and running, please follow these simple steps.
Prerequisites
Here’s what you need to run Cal.diy.
Node.js (Version: >=18.x)
PostgreSQL (Version: >=13.x)
Yarn (recommended)
If you want to enable any of the available integrations,
you may want to obtain additional credentials for each one. More details
on this can be found below under the integrations section.
If you are on Windows, run the following command in Git Bash with admin privileges:
git clone -c core.symlinks=true https://github.com/calcom/cal.diy.git
Go to the project folder
cd cal.diy
Install packages with yarn
yarn
Set up your .env file
Duplicate .env.example to .env
Use openssl rand -base64 32 to generate a key and add it under NEXTAUTH_SECRET in the .env file.
Use openssl rand -base64 24 to generate a key and add it under CALENDSO_ENCRYPTION_KEY in the .env file.
Windows users: Replace the packages/prisma/.env symlink with a real copy to avoid a Prisma error (unexpected character / in variable name):
Set up Node
If your Node version does not meet the project's requirements as
instructed by the docs, "nvm" (Node Version Manager) allows using Node
at the version required by the project:
nvm use
You first might need to install the specific version and then use it:
Tip: To view the full list of seeded users and their details, run yarn db-studio and visit http://localhost:5555
Development tip
Add export NODE_OPTIONS="--max-old-space-size=16384"
to your shell script to increase the memory limit for the node process.
Alternatively, you can run this in your terminal before running the
app. Replace 16384 with the amount of RAM you want to allocate to the
node process.
Add NEXT_PUBLIC_LOGGER_LEVEL={level} to your .env file to control the logging verbosity for all tRPC queries and mutations.
Where {level} can be one of the following:
0 for silly 1 for trace 2 for debug 3 for info 4 for warn 5 for error 6 for fatal
When you set NEXT_PUBLIC_LOGGER_LEVEL={level} in your .env file, it enables logging at that level and higher. Here's how it works:
The logger will include all logs that are at the specified level or higher. For example: \
If you set NEXT_PUBLIC_LOGGER_LEVEL=2, it will log from
level 2 (debug) upwards, meaning levels 2 (debug), 3 (info), 4 (warn), 5
(error), and 6 (fatal) will be logged. \
If you set NEXT_PUBLIC_LOGGER_LEVEL=3, it will log from
level 3 (info) upwards, meaning levels 3 (info), 4 (warn), 5 (error),
and 6 (fatal) will be logged, but level 2 (debug) and level 1 (trace)
will be ignored. \
echo'NEXT_PUBLIC_LOGGER_LEVEL=3'>> .env
for Logger level to be set at info, for example.
Gitpod Setup
Click the button below to open this project in Gitpod.
This will open a fully configured workspace in your browser with all the necessary dependencies already installed.
Manual setup
Configure environment variables in the .env file. Replace <user>, <pass>, <db-host>, and <db-port> with their applicable values
Copy and paste your DATABASE_URL from .env to .env.appStore.
Set up the database using the Prisma schema (found in packages/prisma/schema.prisma)
In a development environment, run:
yarn workspace @calcom/prisma db-migrate
In a production environment, run:
yarn workspace @calcom/prisma db-deploy
Note for Windows/PowerShell users: If running the database deployment scripts fails with an error stating Environment variable not found: DATABASE_DIRECT_URL, Turbo might be failing to inject the root .env variables. You can bypass this by executing the commands directly from the prisma package directory in PowerShell:
cd packages/prisma
$env:DATABASE_URL="postgresql://postgres:YOUR_PASSWORD@localhost:5432/postgres"; $env:DATABASE_DIRECT_URL="postgresql://postgres:YOUR_PASSWORD@localhost:5432/postgres"
npx prisma db push
cd ../..
Run mailhog to view emails sent during development
NOTE: Required when E2E_TEST_MAILHOG_ENABLED is "1"
Open Prisma Studio to look at or modify the database content:
yarn db-studio
Click on the User model to add a new user record.
Fill out the fields email, username, password, and set metadata to empty {} (remembering to encrypt your password with BCrypt) and click Save 1 Record to create your first user.
New users are set on a TRIAL plan by default. You might want to adjust this behavior to your needs in the packages/prisma/schema.prisma file.
Open a browser to http://localhost:3000 and login with your just created, first user.
Approach 2
Seed the local db by running
cd packages/prisma
yarn db-seed
The above command will populate the local db with dummy users.
E2E-Testing
Be sure to set the environment variable NEXTAUTH_URL to the correct value. If you are running locally, as the documentation within .env.example mentions, the value should be http://localhost:3000.
# In a terminal just run:
yarn test-e2e
# To open the last HTML report run:
yarn playwright show-report test-results/reports/playwright-html-report
Resolving issues
E2E test browsers not installed
Run npx playwright install to download test browsers and resolve the error below when running yarn test-e2e:
Executable doesn't exist at /Users/alice/Library/Caches/ms-playwright/chromium-1048/chrome-mac/Chromium.app/Contents/MacOS/Chromium
Upgrading from earlier versions
Pull the current version:
git pull
Check if dependencies got added/updated/removed
yarn
Apply database migrations by running one of the following commands:
In a development environment, run:
yarn workspace @calcom/prisma db-migrate
(This can clear your development database in some cases)
In a production environment, run:
yarn workspace @calcom/prisma db-deploy
Check for .env variables changes
yarn predev
Start the server. In a development environment, just do:
Note for ARM Users: Use the {version}-arm suffix for pulling images. Example: docker pull calcom/cal.diy:v5.6.19-arm.
Requirements
Make sure you have docker & docker compose installed on the server / system. Both are installed by most docker utilities, including Docker Desktop and Rancher Desktop.
Note: docker compose without the hyphen is now the primary method of using docker-compose, per the Docker documentation.
Before starting, you must generate secure values for NEXTAUTH_SECRET and CALENDSO_ENCRYPTION_KEY. Using the default secret placeholder in production is a security risk.
Generate NEXTAUTH_SECRET (cookie encryption key):
openssl rand -base64 32
Generate CALENDSO_ENCRYPTION_KEY (must be 32 bytes for AES256):
Do not commit real keys to .env.example — only placeholders.
Update the appropriate values in your .env file, then proceed.
(optional) Pre-Pull the images by running the following command:
docker compose pull
Start Cal.diy via docker compose
To run the complete stack, which includes a local Postgres database, Cal.diy web app, and Prisma Studio:
docker compose up -d
To run Cal.diy web app and Prisma Studio against a remote
database, ensure that DATABASE_URL is configured for an available
database and run:
docker compose up -d calcom studio
To run only the Cal.diy web app, ensure that DATABASE_URL is configured for an available database and run:
docker compose up -d calcom
Note: to run in attached mode for debugging, remove -d from your desired run command.
Open a browser to http://localhost:3000,
or your defined NEXT_PUBLIC_WEBAPP_URL. The first time you run Cal.diy,
a setup wizard will initialize. Define your first user, and you're
ready to go!
Note for first-time setup (Calendar integration):
During the setup wizard, you may encounter a "Connect your Calendar"
step that appears to be required. If you do not wish to connect a
calendar at this time, you can skip this step by navigating directly to
the dashboard at <NEXT_PUBLIC_WEBAPP_URL>/event-types. Calendar integrations can be added later from the Settings > Integrations page.
Updating Cal.diy
Stop the Cal.diy stack
docker compose down
Pull the latest changes
docker compose pull
Update env vars as necessary.
Re-start the Cal.diy stack
docker compose up -d
Building from source with Docker
Clone the repository
git clone https://github.com/calcom/cal.diy.git
Change into the directory
cd cal.diy
Rename .env.example to .env and then update .env
For configuration options see Build-time variables below. Update the appropriate values in your .env file, then proceed.
Build the Cal.diy docker image:
Note: Due to application configuration requirements, an available database is currently required during the build process.
a) If hosting elsewhere, configure the DATABASE_URL in the .env file, and skip the next step
b) If a local or temporary database is required, start a local database via docker compose.
docker compose up -d database
Build Cal.diy via docker compose (DOCKER_BUILDKIT=0 must
be provided to allow a network bridge to be used at build time. This
requirement will be removed in the future)
DOCKER_BUILDKIT=0 docker compose build calcom
Start Cal.diy via docker compose
To run the complete stack, which includes a local Postgres database, Cal.diy web app, and Prisma Studio:
docker compose up -d
To run Cal.diy web app and Prisma Studio against a remote
database, ensure that DATABASE_URL is configured for an available
database and run:
docker compose up -d calcom studio
To run only the Cal.diy web app, ensure that DATABASE_URL is configured for an available database and run:
docker compose up -d calcom
Note: to run in attached mode for debugging, remove -d from your desired run command.
Open a browser to http://localhost:3000,
or your defined NEXT_PUBLIC_WEBAPP_URL. The first time you run Cal.diy,
a setup wizard will initialize. Define your first user, and you're
ready to go!
Configuration
Important Run-time variables
These variables must also be provided at runtime
Variable
Description
Required
Default
DATABASE_URL
database url with credentials - if using a connection pooler, this setting should point there
Base URL of the site. NOTE: if this value differs from the value
used at build-time, there will be a slight delay during container start
(to update the statically built files).
optional
http://localhost:3000
NEXTAUTH_URL
Location of the auth server. By default, this is the Cal.diy docker instance itself.
optional
{NEXT_PUBLIC_WEBAPP_URL}/api/auth
NEXTAUTH_SECRET
Cookie encryption key. Must match build variable. Generate with: openssl rand -base64 32
required
secret
CALENDSO_ENCRYPTION_KEY
Authentication encryption key (32 bytes for AES256). Must match build variable. Generate with: openssl rand -base64 24
required
secret
Build-time variables
If building the image yourself, these variables must be
provided at the time of the docker build, and can be provided by
updating the .env file. Currently, if you require changes to these
variables, you must follow the instructions to build and publish your
own image.
Variable
Description
Required
Default
DATABASE_URL
database url with credentials - if using a connection pooler, this setting should point there
Allow Cal.diy to collect anonymous usage data (set to 1 to disable)
optional
Troubleshooting
SSL edge termination
If running behind a load balancer which handles SSL certificates, you will need to add the environmental variable NODE_TLS_REJECT_UNAUTHORIZED=0
to prevent requests from being rejected. Only do this if you know what
you are doing and trust the services/load-balancers directing traffic to
your service.
Failed to commit changes: Invalid 'prisma.user.create()'
Certain versions may have trouble creating a user if the field metadata is empty. Using an empty json object {} as the field value should resolve this issue. Also, the id field will autoincrement, so you may also try leaving the value of id as empty.
CLIENT_FETCH_ERROR
If you experience this error, it may be the way the
default Auth callback in the server is using the WEBAPP_URL as a base
url. The container does not necessarily have access to the same DNS as
your local machine, and therefore needs to be configured to resolve to
itself. You may be able to correct this by configuring NEXTAUTH_URL=http://localhost:3000/api/auth, to help the backend loop back to itself.
You can deploy Cal.diy on Railway. The team at Railway also have a detailed blog post on deploying on their platform.
Vercel:
Currently Vercel Pro Plan is required to be able to Deploy
this application with Vercel, due to limitations on the number of
serverless functions on the free plan.
Bun is an all-in-one toolkit for JavaScript and TypeScript apps. It ships as a single executable called bun.
At its core is the Bun runtime, a fast JavaScript runtime designed as a drop-in replacement for Node.js. It's written in Rust and powered by JavaScriptCore under the hood, dramatically reducing startup times and memory usage.
bun run index.tsx # TS and JSX supported out-of-the-box
The bun command-line tool also implements a
test runner, script runner, and Node.js-compatible package manager.
Instead of 1,000 node_modules for development, you only need bun.
Bun's built-in tools are significantly faster than existing options and
usable in existing Node.js projects with little to no changes.
bun test# run tests
bun run start # run the `start` script in `package.json`
bun install <pkg># install a package
bunx cowsay 'Hello, world!'# execute a package
Install
Bun supports Linux (x64 & arm64), macOS (x64 & Apple Silicon), and Windows (x64 & arm64).
Linux users — Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1.
x64 users — if you see "illegal instruction" or similar errors, check our CPU requirements
# with install script (recommended)
curl -fsSL https://bun.com/install | bash
# on windows
powershell -c "irm bun.sh/install.ps1 | iex"# with npm
npm install -g bun
# with Homebrew
brew tap oven-sh/bun
brew install bun
# with Docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun
Upgrade
To upgrade to the latest version of Bun, run:
bun upgrade
Bun automatically releases a canary build on every commit to main. To upgrade to the latest canary build, run:
Deploy a Bun application to Railway from the CLI or dashboard, with optional PostgreSQL setup and automatic SSL
Railway
is an infrastructure platform: you provision infrastructure, develop
against it locally, then deploy to the cloud. Railway deploys from
GitHub with zero configuration, handles SSL automatically, and
provisions databases.
This guide deploys a Bun application with an optional PostgreSQL database, the same setup the following template provides.
You can either follow this guide step-by-step or deploy the pre-configured template with one click:
After initializing the project, add a new database and service.
Step 4 is only necessary if your application uses a database. If you don't need PostgreSQL, skip to Step 5.
terminal
# Add PostgreSQL database. Make sure to add this first!railway add --database postgres# Add your application service.railway add --service bun-react-db --variables DATABASE_URL=\${{Postgres.DATABASE_URL}}
Step 5
After
creating and connecting the services, deploy the application to
Railway. By default, services are only accessible within Railway's
private network, so generate a public domain to make your app publicly
accessible.
# Deploy your applicationrailway up# Generate public domainrailway domain
Your app is now live. railway up
deploys your local directory rather than a GitHub repository. To have
Railway auto-deploy on every GitHub push, connect the service to your
repository with railway service source connect --repo <owner>/<repo> --branch <branch>.
Add a PostgreSQL database, and connect this database to the serviceStep 2 is only necessary if your application uses a database. If you don't need PostgreSQL, skip to Step 3.
Click "+ New" → "Database" → "Add PostgreSQL"
After Railway creates the database, select your service (not the database)
Go to "Variables" tab
Click "+ New Variable" → "Add Reference"
Select DATABASE_URL from postgres
Step 3
Generate a public domain
Select your service
Go to "Settings" tab
Under "Networking", click "Generate Domain"
Your app is now live. Railway auto-deploys on every GitHub push.
By default, Railway uses Railpack to automatically detect and build your Bun application with zero configuration.
Railpack detects Bun from your bun.lock and installs the latest version of Bun unless you pin one with the engines.bun or packageManager field in package.json. Railway's previous builder, Nixpacks, is in maintenance mode.
If your service still builds with Nixpacks, switch it to Railpack by adding the following to your railway.json:railway.json