Please use this README if you want to deploy Huly on your server with docker compose. I'm using a Basic Droplet on Digital Ocean with Ubuntu 24.04, but these instructions can be easily adapted for any Linux distribution.
If you prefer Kubernetes deployment, there is a sample Kubernetes configuration under kube directory.
Huly is resource-heavy. Use a server that meets or exceeds the following:
[!WARNING] Servers below the minimum may stop responding or fail.
The Huly platform source code is available on GitHub: hcengineering/platform
[!NOTE] For self-hosted deployments, use production versions (
v*tags). For example:v0.7.310,v0.7.307,v0.6.501See all available versions on GitHub Releases.
Before updating, always review MIGRATION.md in this repository:
MIGRATION.md and find the section for your target version (for example v0.7.426).v0.7 section of MIGRATION.md (especially v0.7.204) instead of doing a direct in-place upgrade.To update an existing self-hosted deployment to a new Huly version:
cd huly-selfhost
docker compose down
huly-selfhost repository:
git pull
.env:
.env file in the project root and update:
HULY_VERSION to the desired platform version tag (for example v0.7.426)DESKTOP_CHANNEL to the same version without the leading v (for example 0.7.426) if you use the desktop app.docker compose pull
docker compose up -d
By default, Huly can initialize new workspaces with predefined content. To disable that behavior, set INIT_REPO_DIR in the workspace service to a non-existing path:
workspace:
image: hardcoreeng/workspace:${HULY_VERSION}
environment:
# ...
- INIT_REPO_DIR=/no-init-scripts
For detailed information about the Huly self-hosted architecture, services, and their interactions, see ARCHITECTURE_OVERVIEW.md.
For fast local verification without going through the full setup process:
git clone https://github.com/hcengineering/huly-selfhost.git
cd huly-selfhost
./setup.sh --quick
This will:
localhost:8087 as the host addressAccess Huly at http://localhost:8087 (wait ~60 seconds for services to initialize). To stop all services, run docker compose down from the huly-selfhost folder.
[!NOTE] Quick start is intended for local testing only. For production deployments, follow the full setup instructions below.
nginx and dockerFirst, update repositories cache:
sudo apt update
Now, install nginx:
sudo apt install nginx
Install docker using the recommended method from docker website.
Afterwards perform post-installation steps. Pay attention to 3rd step with newgrp docker command, it needed for correct execution in setup script.
huly-selfhost repository and configure nginxNext, let's clone the huly-selfhost repository and configure Huly.
git clone https://github.com/hcengineering/huly-selfhost.git
cd huly-selfhost
./setup.sh
This will generate a huly_v7.conf file with your chosen values and create your nginx config.
To add the generated configuration to your Nginx setup, run the following:
sudo ln -s $(pwd)/nginx.conf /etc/nginx/sites-enabled/huly.conf
[!NOTE] If you change
HOST_ADDRESS,SECURE,HTTP_PORTorHTTP_BINDbe sure to update your nginx.conf by running:./nginx.shYou can safely execute this script after adding your custom configurations like ssl. It will only overwrite the necessary settings.
Finally, let's reload nginx and start Huly with docker compose.
sudo nginx -s reload
sudo docker compose up -d
Now, launch your web browser and enjoy Huly! To stop all services, run docker compose down from the huly-selfhost project directory.
[!IMPORTANT] Provided configrations include deployments of CockroachDB and Redpanda which might not be production-ready. Please inspect them carefully before using in production. For more information on the recommended deployment configurations, please refer to the CockroachDB and Redpanda documentation.
If the UI loads but sign-up fails, check logs for the account service first:
docker compose logs -f account
This usually reveals issues with account callbacks, URL configuration, or connectivity to dependent services.
SSL wrong version number)This usually means HTTPS/WSS is enabled in configuration, but the endpoint is serving plain HTTP/WS or has invalid TLS setup.
ssl_certificate, ssl_certificate_key).443 is reachable.SECURE= in huly_v7.conf, then regenerate/reload config and restart containers.By default, Huly uses Docker named volumes to store persistent data (database, Elasticsearch indices, and uploaded files). You can optionally configure custom host paths for these volumes during the setup process.
When running ./setup.sh, you'll be prompted to specify custom paths for:
You can either:
/var/huly/db)default to clear an existing custom path and revert to Docker named volumes[!NOTE] When using custom paths, pay attention to the permissions of the directory. each folder needs to be owned by the user defined in the setup script for example:
chown -R 1000:1000 /var/huly/db(this is the user most services uses) but for example redpanda uses user 101
To quickly reset all volumes back to default Docker named volumes without prompts:
./setup.sh --reset-volumes
You can also manually configure volume paths by editing the huly_v7.conf file:
# Docker volume paths - specify custom paths for persistent data storage
# Leave empty to use default Docker named volumes
VOLUME_ELASTIC_PATH=/path/to/elasticsearch
VOLUME_FILES_PATH=/path/to/files
VOLUME_CR_DATA_PATH=/path/to/cockroachdb/data
VOLUME_CR_CERTS_PATH=/path/to/cockroachdb/certs
VOLUME_REDPANDA_PATH=/path/to/redpanda/data
To revert to default volumes, simply leave the paths empty:
VOLUME_ELASTIC_PATH=
VOLUME_FILES_PATH=
VOLUME_CR_DATA_PATH=
VOLUME_CR_CERTS_PATH=
VOLUME_REDPANDA_PATH=
After modifying the configuration, restart the services:
docker compose down
docker compose up -d
[!WARNING] When changing from named volumes to host paths (or vice versa), make sure to migrate your data appropriately to avoid data loss.
When using a production deployment of Redpanda with topics auto-creation turned off, you'll need to manually create the following topics:
You'll need Node.js installed on your machine. Installing npm on Debian based distro:
sudo apt-get install npm
Install web-push using npm
sudo npm install -g web-push
Generate VAPID Keys. Run the following command to generate a VAPID key pair:
web-push generate-vapid-keys
It will generate both keys that looks like this:
=======================================
Public Key:
sdfgsdgsdfgsdfggsdf
Private Key:
asdfsadfasdfsfd
=======================================
Keep these keys secure, as you will need them to set up your push notification service on the server.
Add these keys into compose.yaml in section services:ses:environment:
- PUSH_PUBLIC_KEY=your public key
- PUSH_PRIVATE_KEY=your private key
As the browser must access the public key for web push notifications setup, you also need to provide it to the front-end service.
Add the public key into compose.yaml in section services:front:environment:
- PUSH_PUBLIC_KEY=your public key
[!NOTE] In version 0.7.x and later, the legacy
sesservice has been replaced with thenotificationservice for web push notifications and thenotificationservice.
To enable web push notifications in Huly, you need to configure the notification service with the VAPID keys and point transactor to it.
Add WEB_PUSH_URL to the transactor container:
transactor:
...
environment:
- WEB_PUSH_URL=http://notification:8091
...
Add the notification container to your docker-compose.yaml file with the generated VAPID keys:
notification:
image: hardcoreeng/notification:${HULY_VERSION}
environment:
- PORT=8091
- SOURCE=mail@example.com
- STATS_URL=http://stats:4900
- PUSH_PUBLIC_KEY=${PUSH_PUBLIC_KEY}
- PUSH_PRIVATE_KEY=${PUSH_PRIVATE_KEY}
restart: unless-stopped
networks:
- huly_net
The Mail Service is responsible for sending email notifications and confirmation emails during user login or signup processes. It can be configured to send emails through either an SMTP server or Amazon SES (Simple Email Service), but not both at the same time.
Add the mail container to the docker-compose.yaml file. Specify the email address you will use to send emails as "SOURCE":
mail:
image: hardcoreeng/mail:${HULY_VERSION}
container_name: mail
ports:
- 8097:8097
environment:
- PORT=8097
- SOURCE=<EMAIL_FROM>
restart: unless-stopped
networks:
- huly_net
Add the mail container URL to the transactor and account containers:
account:
...
environment:
- MAIL_URL=http://mail:8097
...
transactor:
...
environment:
- MAIL_URL=http://mail:8097
...
In Settings -> Notifications, set up email notifications for the events you want to be notified about. Note that this is a user-specific setting, not company-wide; each user must set up their own notification preferences.
To integrate with an external SMTP server, update the docker-compose.yaml file with the following environment variables:
Add SMTP configuration to the environment section:
mail:
...
environment:
...
- SMTP_HOST=<SMTP_SERVER_URL>
- SMTP_PORT=<SMTP_SERVER_PORT>
- SMTP_USERNAME=<SMTP_USER>
- SMTP_PASSWORD=<SMTP_PASSWORD>
Replace <SMTP_SERVER_URL> and <SMTP_SERVER_PORT> with your SMTP server's hostname and port. It's recommended to use a secure port, such as 587.
Replace <SMTP_USER> and <SMTP_PASSWORD> with credentials for an account that can send emails via your SMTP server. If your service provider supports it, consider using an application API key as <SMTP_USER> and a token as <SMTP_PASSWORD> for enhanced security.
Set up Amazon Simple Email Service in AWS: AWS SES Setup Guide
Create a new IAM policy with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}
Create a separate IAM user for SES API access, assigning the newly created policy to this user.
Configure SES environment variables in the mail container:
mail:
...
environment:
...
- SES_ACCESS_KEY=<SES_ACCESS_KEY>
- SES_SECRET_KEY=<SES_SECRET_KEY>
- SES_REGION=<SES_REGION>
To verify that the mail service is running correctly:
# Check if the mail container is running
sudo docker ps | grep mail
# View mail service logs
sudo docker logs mail
# Follow mail service logs in real-time
sudo docker logs -f mail
If you're experiencing issues with email delivery, see the SMTP Troubleshooting Guide for comprehensive debugging steps and solutions.
SES_URL is not supported in version v0.6.470 and later, please use MAIL_URL instead.Huly supports Gmail integration allowing users to connect their Gmail accounts and manage emails directly within the platform.
For detailed setup instructions, see the Gmail Configuration Guide.
Huly audio and video calls are created on top of LiveKit insfrastructure. In order to use Love service in your self-hosted Huly, perform the following steps:
Set up LiveKit Cloud account
Add love container to the docker-compose.yaml
love:
image: hardcoreeng/love:${HULY_VERSION}
container_name: love
ports:
- 8096:8096
environment:
- PORT=8096
- SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- DB_URL=${CR_DB_URL}
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- STORAGE_PROVIDER_NAME=minio
- LIVEKIT_HOST=<LIVEKIT_HOST>
- LIVEKIT_API_KEY=<LIVEKIT_API_KEY>
- LIVEKIT_API_SECRET=<LIVEKIT_API_SECRET>
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
- LIVEKIT_WS=<LIVEKIT_HOST>
...
Uncomment love section in .huly.nginx file and reload nginx
Note that the LIVEKIT_HOST should include the protocol (wss:// by default if using livekit cloud).
HulyPulse provides WebSocket push notifications and real-time updates. It will allow the following functions to work:
Since Huly platform version v0.7.375, HulyPulse supports an in-memory backend.
By default, templates in this repository use:
HULY_BACKEND=memoryThis mode does not require Redis and is suitable for single-node or small self-hosted deployments.
Enable HulyPulse in compose.yml:
hulypulse service.Configure the transactor service:
transactor:
...
environment:
- PULSE_URL=http://hulypulse:8099
...
Configure the front service:
front:
...
environment:
- PULSE_URL=http${SECURE:+s}://${HOST_ADDRESS}/_pulse
...
Uncomment the /_pulse location in .huly.nginx and reload nginx:
sudo nginx -s reload
Recreate and start the stack from the huly-selfhost folder:
docker compose up -d --force-recreate
Redis can be used as an alternative backend for HulyPulse – for example, in multi-node or higher-availability setups.
Enable Redis and HulyPulse in compose.yml:
Uncomment the redis service.
Uncomment the hulypulse service.
In the hulypulse environment, switch to Redis:
- HULY_BACKEND=redis
- HULY_REDIS_MODE=direct
- HULY_REDIS_URLS=redis://redis:6379
# or with password:
# - HULY_REDIS_URLS=redis://:YOUR_PASSWORD@redis:6379
Redis is configured with a 512 MB memory limit by default in the provided compose.yml. Adjust limits, password, and URLs as needed for your production setup. The image tag uses HULY_PULSE_VERSION if set (default 0.1.29).
Add print container to the docker-compose.yaml
print:
image: hardcoreeng/print:${HULY_VERSION}
container_name: print
ports:
- 4005:4005
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- STATS_URL=http://stats:4900
- SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- FRONT_URL=http${SECURE:+s}://${HOST_ADDRESS}
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
- PRINT_URL=http${SECURE:+s}://${HOST_ADDRESS}/_print
...
Uncomment print section in .huly.nginx file and reload nginx
exports container to compose.ymlexports:
image: hardcoreeng/export:${HULY_VERSION}
ports:
- 4009:4009
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SECRET=${SECRET}
- DB_URL=${CR_DB_URL}
- ACCOUNTS_URL=http://account:3000
- SERVICE_ID=export-service
- PORT=4009
restart: unless-stopped
networks:
- huly_net
front servicefront:
...
environment:
...
- EXPORT_URL=https://${HOST_ADDRESS}/_export
_export route in .huly.nginxHuly provides AI-powered chatbot that provides several services:
Set up OpenAI account
Enable MongoDB service (required by aibot):
mongodb service in compose.ymlmongodb volume entry in the volumes section of compose.ymlAdd aibot container to the docker-compose.yaml
aibot:
image: hardcoreeng/ai-bot:${HULY_VERSION}
ports:
- 4010:4010
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SERVER_SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- DB_URL=${CR_DB_URL}
- MONGO_URL=mongodb://mongodb:27017
- STATS_URL=http://stats:4900
- FIRST_NAME=Bot
- LAST_NAME=Huly AI
- PASSWORD=<PASSWORD>
- OPENAI_API_KEY=<OPENAI_API_KEY>
- OPENAI_BASE_URL=<OPENAI_BASE_URL>
# optional if you use love service
- LOVE_ENDPOINT=http://love:8096
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
# this should be available outside of the cluster
- AI_URL=http${SECURE:+s}://${HOST_ADDRESS}/_aibot
...
Configure transactor service:
transactor:
...
environment:
# this should be available inside of the cluster
- AI_BOT_URL=http://aibot:4010
...
Uncomment aibot section in .huly.nginx file and reload nginx
[!NOTE] You can also add the
AI_OPENAI_MODEL,AI_OPENAI_TRANSLATE_MODEL,AI_OPENAI_SUMMARY_MODELenvironment variables to the aibot service to use a different model, by default it usesgpt-4o-minifor all of them
To integrate Google Calendar with Huly, follow these steps:
Web application as the application type and https://${HOST_ADDRESS}/_calendar/signin/code (SET REAL VALUE INSTEAD OF ${HOST_ADDRESS}, https is required!!!) as Authorised redirect URIs. Save your credentials!./auth/calendar.calendarlist.readonly ./auth/userinfo.email ./auth/calendar.calendars.readonly ./auth/calendar.eventsAdd calendar container to the docker-compose.yaml
calendar:
image: hardcoreeng/calendar:${HULY_VERSION}
ports:
- 8095:8095
environment:
- MONGO_URI=mongodb://mongodb:27017
- MONGO_DB=%calendar-service
- Credentials=<JSON_STRING_CREDENTIALS_FROM_GOOGLE_CONSOLE>
- WATCH_URL=https://${HOST_ADDRESS}/_calendar/push
- ACCOUNTS_URL=http://account:3000
- STATS_URL=http://stats:4900
- SECRET=${SECRET}
- KVS_URL=http://kvs:8094
restart: unless-stopped
networks:
- huly_net
You can configure a Huly instance to authorize users (sign-in/sign-up) using an OpenID Connect identity provider (IdP).
Create a new OpenID application.
{huly_account_svc}/auth/openid/callback as the sign-in redirect URI. The huly_account_svc is the hostname for the account service of the deployment, which should be accessible externally from the client/browser side. In the provided example setup, the account service runs on port 3000.URI Example:
http://huly.mydomain.com:3000/auth/openid/callbackConfigure user access to the application as needed.
For the account service, set the following environment variables as provided by the IdP:
Ensure you have configured or add the following environment variable to the front service:
You will need to expose your account service port (e.g. 3000) in your nginx.conf.
Note: Once all the required environment variables are configured, you will see an additional button on the sign-in/sign-up pages.
You can also configure a Huly instance to use GitHub OAuth for user authorization (sign-in/sign-up).
Create a new GitHub OAuth application.
{huly_account_svc}/_accounts/auth/github/callback as the sign-in redirect URI. The huly_account_svc is the hostname for the account service of the deployment, which should be accessible externally from the client/browser side.URI Example:
http://huly.mydomain.com/_accounts/auth/github/callbackSpecify the following environment variables for the account service:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETEnsure you have configured or add the following environment variable to the front service:
ACCOUNTS_URL (The URL of the account service, accessible from the client side.)Notes:
ISSUER environment variable is not required for GitHub OAuth.You can disable public sign-ups for a deployment. When configured, sign-ups will only be permitted through an invite link to a specific workspace.
To implement this, set the following environment variable for both the front and account services:
account:
# ...
environment:
- DISABLE_SIGNUP=true
# ...
front:
# ...
environment:
- DISABLE_SIGNUP=true
# ...
Note: When setting up a new deployment, either create the initial account before disabling sign-ups or use the development tool to create the first account.
Huly provides GitHub integration for bi-directional synchronization of issues, pull requests, comments, and reviews.
Set up a GitHub Application for your deployment. Please refer to GitHub Apps documentation for full instructions on how to register your app.
During registration of the GitHub app, the following secrets should be obtained:
GITHUB_APPID - The application ID number (e.g., 123456), found under General → About in the GitHub App settings.GITHUB_APP_SLUG - The app slug from its public URL: github.com/apps/<slug>. For example, if the URL is github.com/apps/my-huly-dev, the slug is my-huly-dev.GITHUB_CLIENTID - The client ID shown on the same page (e.g., Iv1.11a1aaa11aa11111).GITHUB_CLIENT_SECRET - A client secret generated in the Client secrets section of the General page.GITHUB_PRIVATE_KEY - A private key for authentication. GitHub will generate and download a .pem file. This is an RSA key containing multiple lines — copy the entire content into the environment variable as-is.GITHUB_WEBHOOK_SECRET - The webhook secret you set when configuring the webhook URL (see step 5 below).Set the following permissions for the app:
Enable the following event subscriptions:
github container to the compose.yml:github:
image: hardcoreeng/github:${HULY_VERSION}
ports:
- 3500:3500
environment:
- PORT=3500
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SERVER_SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- STATS_URL=http://stats:4900
- APP_ID=${GITHUB_APPID}
- CLIENT_ID=${GITHUB_CLIENTID}
- CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
- PRIVATE_KEY=${GITHUB_PRIVATE_KEY}
- COLLABORATOR_URL=ws${SECURE:+s}://${HOST_ADDRESS}/_collaborator
- WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}
- FRONT_URL=http${SECURE:+s}://${HOST_ADDRESS}
- BOT_NAME=${GITHUB_APP_SLUG}[bot]
restart: unless-stopped
networks:
- huly_net
front service: front:
...
environment:
# this should be available outside of the cluster
- GITHUB_URL=http${SECURE:+s}://${HOST_ADDRESS}/_github
- GITHUB_APP=${GITHUB_APP_SLUG}
- GITHUB_CLIENTID=${GITHUB_CLIENTID}
...
Uncomment the github section in .huly.nginx file and reload nginx
Configure Callback URL and Setup URL (with redirect on update set) to your host: http${SECURE:+s}://${HOST_ADDRESS}/github
Configure Webhook URL to http${SECURE:+s}://${HOST_ADDRESS}/_github/api/webhook and set a webhook secret (use the same value as GITHUB_WEBHOOK_SECRET above)
Telegram Bot Service is responsible for sending notifications from Huly to Telegram (private chats or groups). The service works as an external notification channel and does not provide interactive control or command execution for Huly.
chat_id using the getUpdates methodchat_id (usually a negative value)telegram-bot service to compose.yml: telegram-bot:
image: hardcoreeng/telegram-bot:${HULY_VERSION}
container_name: telegram-bot
restart: unless-stopped
environment:
- PORT=4020
- DB_URL=${CR_DB_URL}
- BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- ACCOUNTS_URL=http://account:3000
- SECRET=${SECRET}
- SERVICE_ID=telegram-bot-service
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- QUEUE_CONFIG=redpanda:9092
- QUEUE_REGION=
networks:
- huly_net
front service:front:
...
environment:
- TELEGRAM_BOT_URL=http${SECURE:+s}://${HOST_ADDRESS}/_telegram
...
After the service is running:
CHAT_ID where notifications should be delivered.Note
Notification settings are user-specific. Each user must configure Telegram notifications individually.
6,147 followers · starred Jun 2024
224 followers · starred Sep 2026
71 followers · starred Oct 2025
179 followers · starred Apr 2025
Please use this README if you want to deploy Huly on your server with docker compose. I'm using a Basic Droplet on Digital Ocean with Ubuntu 24.04, but these instructions can be easily adapted for any Linux distribution.
If you prefer Kubernetes deployment, there is a sample Kubernetes configuration under kube directory.
Huly is resource-heavy. Use a server that meets or exceeds the following:
[!WARNING] Servers below the minimum may stop responding or fail.
The Huly platform source code is available on GitHub: hcengineering/platform
[!NOTE] For self-hosted deployments, use production versions (
v*tags). For example:v0.7.310,v0.7.307,v0.6.501See all available versions on GitHub Releases.
Before updating, always review MIGRATION.md in this repository:
MIGRATION.md and find the section for your target version (for example v0.7.426).v0.7 section of MIGRATION.md (especially v0.7.204) instead of doing a direct in-place upgrade.To update an existing self-hosted deployment to a new Huly version:
cd huly-selfhost
docker compose down
huly-selfhost repository:
git pull
.env:
.env file in the project root and update:
HULY_VERSION to the desired platform version tag (for example v0.7.426)DESKTOP_CHANNEL to the same version without the leading v (for example 0.7.426) if you use the desktop app.docker compose pull
docker compose up -d
By default, Huly can initialize new workspaces with predefined content. To disable that behavior, set INIT_REPO_DIR in the workspace service to a non-existing path:
workspace:
image: hardcoreeng/workspace:${HULY_VERSION}
environment:
# ...
- INIT_REPO_DIR=/no-init-scripts
For detailed information about the Huly self-hosted architecture, services, and their interactions, see ARCHITECTURE_OVERVIEW.md.
For fast local verification without going through the full setup process:
git clone https://github.com/hcengineering/huly-selfhost.git
cd huly-selfhost
./setup.sh --quick
This will:
localhost:8087 as the host addressAccess Huly at http://localhost:8087 (wait ~60 seconds for services to initialize). To stop all services, run docker compose down from the huly-selfhost folder.
[!NOTE] Quick start is intended for local testing only. For production deployments, follow the full setup instructions below.
nginx and dockerFirst, update repositories cache:
sudo apt update
Now, install nginx:
sudo apt install nginx
Install docker using the recommended method from docker website.
Afterwards perform post-installation steps. Pay attention to 3rd step with newgrp docker command, it needed for correct execution in setup script.
huly-selfhost repository and configure nginxNext, let's clone the huly-selfhost repository and configure Huly.
git clone https://github.com/hcengineering/huly-selfhost.git
cd huly-selfhost
./setup.sh
This will generate a huly_v7.conf file with your chosen values and create your nginx config.
To add the generated configuration to your Nginx setup, run the following:
sudo ln -s $(pwd)/nginx.conf /etc/nginx/sites-enabled/huly.conf
[!NOTE] If you change
HOST_ADDRESS,SECURE,HTTP_PORTorHTTP_BINDbe sure to update your nginx.conf by running:./nginx.shYou can safely execute this script after adding your custom configurations like ssl. It will only overwrite the necessary settings.
Finally, let's reload nginx and start Huly with docker compose.
sudo nginx -s reload
sudo docker compose up -d
Now, launch your web browser and enjoy Huly! To stop all services, run docker compose down from the huly-selfhost project directory.
[!IMPORTANT] Provided configrations include deployments of CockroachDB and Redpanda which might not be production-ready. Please inspect them carefully before using in production. For more information on the recommended deployment configurations, please refer to the CockroachDB and Redpanda documentation.
If the UI loads but sign-up fails, check logs for the account service first:
docker compose logs -f account
This usually reveals issues with account callbacks, URL configuration, or connectivity to dependent services.
SSL wrong version number)This usually means HTTPS/WSS is enabled in configuration, but the endpoint is serving plain HTTP/WS or has invalid TLS setup.
ssl_certificate, ssl_certificate_key).443 is reachable.SECURE= in huly_v7.conf, then regenerate/reload config and restart containers.By default, Huly uses Docker named volumes to store persistent data (database, Elasticsearch indices, and uploaded files). You can optionally configure custom host paths for these volumes during the setup process.
When running ./setup.sh, you'll be prompted to specify custom paths for:
You can either:
/var/huly/db)default to clear an existing custom path and revert to Docker named volumes[!NOTE] When using custom paths, pay attention to the permissions of the directory. each folder needs to be owned by the user defined in the setup script for example:
chown -R 1000:1000 /var/huly/db(this is the user most services uses) but for example redpanda uses user 101
To quickly reset all volumes back to default Docker named volumes without prompts:
./setup.sh --reset-volumes
You can also manually configure volume paths by editing the huly_v7.conf file:
# Docker volume paths - specify custom paths for persistent data storage
# Leave empty to use default Docker named volumes
VOLUME_ELASTIC_PATH=/path/to/elasticsearch
VOLUME_FILES_PATH=/path/to/files
VOLUME_CR_DATA_PATH=/path/to/cockroachdb/data
VOLUME_CR_CERTS_PATH=/path/to/cockroachdb/certs
VOLUME_REDPANDA_PATH=/path/to/redpanda/data
To revert to default volumes, simply leave the paths empty:
VOLUME_ELASTIC_PATH=
VOLUME_FILES_PATH=
VOLUME_CR_DATA_PATH=
VOLUME_CR_CERTS_PATH=
VOLUME_REDPANDA_PATH=
After modifying the configuration, restart the services:
docker compose down
docker compose up -d
[!WARNING] When changing from named volumes to host paths (or vice versa), make sure to migrate your data appropriately to avoid data loss.
When using a production deployment of Redpanda with topics auto-creation turned off, you'll need to manually create the following topics:
You'll need Node.js installed on your machine. Installing npm on Debian based distro:
sudo apt-get install npm
Install web-push using npm
sudo npm install -g web-push
Generate VAPID Keys. Run the following command to generate a VAPID key pair:
web-push generate-vapid-keys
It will generate both keys that looks like this:
=======================================
Public Key:
sdfgsdgsdfgsdfggsdf
Private Key:
asdfsadfasdfsfd
=======================================
Keep these keys secure, as you will need them to set up your push notification service on the server.
Add these keys into compose.yaml in section services:ses:environment:
- PUSH_PUBLIC_KEY=your public key
- PUSH_PRIVATE_KEY=your private key
As the browser must access the public key for web push notifications setup, you also need to provide it to the front-end service.
Add the public key into compose.yaml in section services:front:environment:
- PUSH_PUBLIC_KEY=your public key
[!NOTE] In version 0.7.x and later, the legacy
sesservice has been replaced with thenotificationservice for web push notifications and thenotificationservice.
To enable web push notifications in Huly, you need to configure the notification service with the VAPID keys and point transactor to it.
Add WEB_PUSH_URL to the transactor container:
transactor:
...
environment:
- WEB_PUSH_URL=http://notification:8091
...
Add the notification container to your docker-compose.yaml file with the generated VAPID keys:
notification:
image: hardcoreeng/notification:${HULY_VERSION}
environment:
- PORT=8091
- SOURCE=mail@example.com
- STATS_URL=http://stats:4900
- PUSH_PUBLIC_KEY=${PUSH_PUBLIC_KEY}
- PUSH_PRIVATE_KEY=${PUSH_PRIVATE_KEY}
restart: unless-stopped
networks:
- huly_net
The Mail Service is responsible for sending email notifications and confirmation emails during user login or signup processes. It can be configured to send emails through either an SMTP server or Amazon SES (Simple Email Service), but not both at the same time.
Add the mail container to the docker-compose.yaml file. Specify the email address you will use to send emails as "SOURCE":
mail:
image: hardcoreeng/mail:${HULY_VERSION}
container_name: mail
ports:
- 8097:8097
environment:
- PORT=8097
- SOURCE=<EMAIL_FROM>
restart: unless-stopped
networks:
- huly_net
Add the mail container URL to the transactor and account containers:
account:
...
environment:
- MAIL_URL=http://mail:8097
...
transactor:
...
environment:
- MAIL_URL=http://mail:8097
...
In Settings -> Notifications, set up email notifications for the events you want to be notified about. Note that this is a user-specific setting, not company-wide; each user must set up their own notification preferences.
To integrate with an external SMTP server, update the docker-compose.yaml file with the following environment variables:
Add SMTP configuration to the environment section:
mail:
...
environment:
...
- SMTP_HOST=<SMTP_SERVER_URL>
- SMTP_PORT=<SMTP_SERVER_PORT>
- SMTP_USERNAME=<SMTP_USER>
- SMTP_PASSWORD=<SMTP_PASSWORD>
Replace <SMTP_SERVER_URL> and <SMTP_SERVER_PORT> with your SMTP server's hostname and port. It's recommended to use a secure port, such as 587.
Replace <SMTP_USER> and <SMTP_PASSWORD> with credentials for an account that can send emails via your SMTP server. If your service provider supports it, consider using an application API key as <SMTP_USER> and a token as <SMTP_PASSWORD> for enhanced security.
Set up Amazon Simple Email Service in AWS: AWS SES Setup Guide
Create a new IAM policy with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}
Create a separate IAM user for SES API access, assigning the newly created policy to this user.
Configure SES environment variables in the mail container:
mail:
...
environment:
...
- SES_ACCESS_KEY=<SES_ACCESS_KEY>
- SES_SECRET_KEY=<SES_SECRET_KEY>
- SES_REGION=<SES_REGION>
To verify that the mail service is running correctly:
# Check if the mail container is running
sudo docker ps | grep mail
# View mail service logs
sudo docker logs mail
# Follow mail service logs in real-time
sudo docker logs -f mail
If you're experiencing issues with email delivery, see the SMTP Troubleshooting Guide for comprehensive debugging steps and solutions.
SES_URL is not supported in version v0.6.470 and later, please use MAIL_URL instead.Huly supports Gmail integration allowing users to connect their Gmail accounts and manage emails directly within the platform.
For detailed setup instructions, see the Gmail Configuration Guide.
Huly audio and video calls are created on top of LiveKit insfrastructure. In order to use Love service in your self-hosted Huly, perform the following steps:
Set up LiveKit Cloud account
Add love container to the docker-compose.yaml
love:
image: hardcoreeng/love:${HULY_VERSION}
container_name: love
ports:
- 8096:8096
environment:
- PORT=8096
- SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- DB_URL=${CR_DB_URL}
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- STORAGE_PROVIDER_NAME=minio
- LIVEKIT_HOST=<LIVEKIT_HOST>
- LIVEKIT_API_KEY=<LIVEKIT_API_KEY>
- LIVEKIT_API_SECRET=<LIVEKIT_API_SECRET>
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
- LIVEKIT_WS=<LIVEKIT_HOST>
...
Uncomment love section in .huly.nginx file and reload nginx
Note that the LIVEKIT_HOST should include the protocol (wss:// by default if using livekit cloud).
HulyPulse provides WebSocket push notifications and real-time updates. It will allow the following functions to work:
Since Huly platform version v0.7.375, HulyPulse supports an in-memory backend.
By default, templates in this repository use:
HULY_BACKEND=memoryThis mode does not require Redis and is suitable for single-node or small self-hosted deployments.
Enable HulyPulse in compose.yml:
hulypulse service.Configure the transactor service:
transactor:
...
environment:
- PULSE_URL=http://hulypulse:8099
...
Configure the front service:
front:
...
environment:
- PULSE_URL=http${SECURE:+s}://${HOST_ADDRESS}/_pulse
...
Uncomment the /_pulse location in .huly.nginx and reload nginx:
sudo nginx -s reload
Recreate and start the stack from the huly-selfhost folder:
docker compose up -d --force-recreate
Redis can be used as an alternative backend for HulyPulse – for example, in multi-node or higher-availability setups.
Enable Redis and HulyPulse in compose.yml:
Uncomment the redis service.
Uncomment the hulypulse service.
In the hulypulse environment, switch to Redis:
- HULY_BACKEND=redis
- HULY_REDIS_MODE=direct
- HULY_REDIS_URLS=redis://redis:6379
# or with password:
# - HULY_REDIS_URLS=redis://:YOUR_PASSWORD@redis:6379
Redis is configured with a 512 MB memory limit by default in the provided compose.yml. Adjust limits, password, and URLs as needed for your production setup. The image tag uses HULY_PULSE_VERSION if set (default 0.1.29).
Add print container to the docker-compose.yaml
print:
image: hardcoreeng/print:${HULY_VERSION}
container_name: print
ports:
- 4005:4005
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- STATS_URL=http://stats:4900
- SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- FRONT_URL=http${SECURE:+s}://${HOST_ADDRESS}
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
- PRINT_URL=http${SECURE:+s}://${HOST_ADDRESS}/_print
...
Uncomment print section in .huly.nginx file and reload nginx
exports container to compose.ymlexports:
image: hardcoreeng/export:${HULY_VERSION}
ports:
- 4009:4009
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SECRET=${SECRET}
- DB_URL=${CR_DB_URL}
- ACCOUNTS_URL=http://account:3000
- SERVICE_ID=export-service
- PORT=4009
restart: unless-stopped
networks:
- huly_net
front servicefront:
...
environment:
...
- EXPORT_URL=https://${HOST_ADDRESS}/_export
_export route in .huly.nginxHuly provides AI-powered chatbot that provides several services:
Set up OpenAI account
Enable MongoDB service (required by aibot):
mongodb service in compose.ymlmongodb volume entry in the volumes section of compose.ymlAdd aibot container to the docker-compose.yaml
aibot:
image: hardcoreeng/ai-bot:${HULY_VERSION}
ports:
- 4010:4010
environment:
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SERVER_SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- DB_URL=${CR_DB_URL}
- MONGO_URL=mongodb://mongodb:27017
- STATS_URL=http://stats:4900
- FIRST_NAME=Bot
- LAST_NAME=Huly AI
- PASSWORD=<PASSWORD>
- OPENAI_API_KEY=<OPENAI_API_KEY>
- OPENAI_BASE_URL=<OPENAI_BASE_URL>
# optional if you use love service
- LOVE_ENDPOINT=http://love:8096
restart: unless-stopped
networks:
- huly_net
Configure front service:
front:
...
environment:
# this should be available outside of the cluster
- AI_URL=http${SECURE:+s}://${HOST_ADDRESS}/_aibot
...
Configure transactor service:
transactor:
...
environment:
# this should be available inside of the cluster
- AI_BOT_URL=http://aibot:4010
...
Uncomment aibot section in .huly.nginx file and reload nginx
[!NOTE] You can also add the
AI_OPENAI_MODEL,AI_OPENAI_TRANSLATE_MODEL,AI_OPENAI_SUMMARY_MODELenvironment variables to the aibot service to use a different model, by default it usesgpt-4o-minifor all of them
To integrate Google Calendar with Huly, follow these steps:
Web application as the application type and https://${HOST_ADDRESS}/_calendar/signin/code (SET REAL VALUE INSTEAD OF ${HOST_ADDRESS}, https is required!!!) as Authorised redirect URIs. Save your credentials!./auth/calendar.calendarlist.readonly ./auth/userinfo.email ./auth/calendar.calendars.readonly ./auth/calendar.eventsAdd calendar container to the docker-compose.yaml
calendar:
image: hardcoreeng/calendar:${HULY_VERSION}
ports:
- 8095:8095
environment:
- MONGO_URI=mongodb://mongodb:27017
- MONGO_DB=%calendar-service
- Credentials=<JSON_STRING_CREDENTIALS_FROM_GOOGLE_CONSOLE>
- WATCH_URL=https://${HOST_ADDRESS}/_calendar/push
- ACCOUNTS_URL=http://account:3000
- STATS_URL=http://stats:4900
- SECRET=${SECRET}
- KVS_URL=http://kvs:8094
restart: unless-stopped
networks:
- huly_net
You can configure a Huly instance to authorize users (sign-in/sign-up) using an OpenID Connect identity provider (IdP).
Create a new OpenID application.
{huly_account_svc}/auth/openid/callback as the sign-in redirect URI. The huly_account_svc is the hostname for the account service of the deployment, which should be accessible externally from the client/browser side. In the provided example setup, the account service runs on port 3000.URI Example:
http://huly.mydomain.com:3000/auth/openid/callbackConfigure user access to the application as needed.
For the account service, set the following environment variables as provided by the IdP:
Ensure you have configured or add the following environment variable to the front service:
You will need to expose your account service port (e.g. 3000) in your nginx.conf.
Note: Once all the required environment variables are configured, you will see an additional button on the sign-in/sign-up pages.
You can also configure a Huly instance to use GitHub OAuth for user authorization (sign-in/sign-up).
Create a new GitHub OAuth application.
{huly_account_svc}/_accounts/auth/github/callback as the sign-in redirect URI. The huly_account_svc is the hostname for the account service of the deployment, which should be accessible externally from the client/browser side.URI Example:
http://huly.mydomain.com/_accounts/auth/github/callbackSpecify the following environment variables for the account service:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETEnsure you have configured or add the following environment variable to the front service:
ACCOUNTS_URL (The URL of the account service, accessible from the client side.)Notes:
ISSUER environment variable is not required for GitHub OAuth.You can disable public sign-ups for a deployment. When configured, sign-ups will only be permitted through an invite link to a specific workspace.
To implement this, set the following environment variable for both the front and account services:
account:
# ...
environment:
- DISABLE_SIGNUP=true
# ...
front:
# ...
environment:
- DISABLE_SIGNUP=true
# ...
Note: When setting up a new deployment, either create the initial account before disabling sign-ups or use the development tool to create the first account.
Huly provides GitHub integration for bi-directional synchronization of issues, pull requests, comments, and reviews.
Set up a GitHub Application for your deployment. Please refer to GitHub Apps documentation for full instructions on how to register your app.
During registration of the GitHub app, the following secrets should be obtained:
GITHUB_APPID - The application ID number (e.g., 123456), found under General → About in the GitHub App settings.GITHUB_APP_SLUG - The app slug from its public URL: github.com/apps/<slug>. For example, if the URL is github.com/apps/my-huly-dev, the slug is my-huly-dev.GITHUB_CLIENTID - The client ID shown on the same page (e.g., Iv1.11a1aaa11aa11111).GITHUB_CLIENT_SECRET - A client secret generated in the Client secrets section of the General page.GITHUB_PRIVATE_KEY - A private key for authentication. GitHub will generate and download a .pem file. This is an RSA key containing multiple lines — copy the entire content into the environment variable as-is.GITHUB_WEBHOOK_SECRET - The webhook secret you set when configuring the webhook URL (see step 5 below).Set the following permissions for the app:
Enable the following event subscriptions:
github container to the compose.yml:github:
image: hardcoreeng/github:${HULY_VERSION}
ports:
- 3500:3500
environment:
- PORT=3500
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- SERVER_SECRET=${SECRET}
- ACCOUNTS_URL=http://account:3000
- STATS_URL=http://stats:4900
- APP_ID=${GITHUB_APPID}
- CLIENT_ID=${GITHUB_CLIENTID}
- CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
- PRIVATE_KEY=${GITHUB_PRIVATE_KEY}
- COLLABORATOR_URL=ws${SECURE:+s}://${HOST_ADDRESS}/_collaborator
- WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}
- FRONT_URL=http${SECURE:+s}://${HOST_ADDRESS}
- BOT_NAME=${GITHUB_APP_SLUG}[bot]
restart: unless-stopped
networks:
- huly_net
front service: front:
...
environment:
# this should be available outside of the cluster
- GITHUB_URL=http${SECURE:+s}://${HOST_ADDRESS}/_github
- GITHUB_APP=${GITHUB_APP_SLUG}
- GITHUB_CLIENTID=${GITHUB_CLIENTID}
...
Uncomment the github section in .huly.nginx file and reload nginx
Configure Callback URL and Setup URL (with redirect on update set) to your host: http${SECURE:+s}://${HOST_ADDRESS}/github
Configure Webhook URL to http${SECURE:+s}://${HOST_ADDRESS}/_github/api/webhook and set a webhook secret (use the same value as GITHUB_WEBHOOK_SECRET above)
Telegram Bot Service is responsible for sending notifications from Huly to Telegram (private chats or groups). The service works as an external notification channel and does not provide interactive control or command execution for Huly.
chat_id using the getUpdates methodchat_id (usually a negative value)telegram-bot service to compose.yml: telegram-bot:
image: hardcoreeng/telegram-bot:${HULY_VERSION}
container_name: telegram-bot
restart: unless-stopped
environment:
- PORT=4020
- DB_URL=${CR_DB_URL}
- BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- ACCOUNTS_URL=http://account:3000
- SECRET=${SECRET}
- SERVICE_ID=telegram-bot-service
- STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin
- QUEUE_CONFIG=redpanda:9092
- QUEUE_REGION=
networks:
- huly_net
front service:front:
...
environment:
- TELEGRAM_BOT_URL=http${SECURE:+s}://${HOST_ADDRESS}/_telegram
...
After the service is running:
CHAT_ID where notifications should be delivered.Note
Notification settings are user-specific. Each user must configure Telegram notifications individually.
6,147 followers · starred Jun 2024
224 followers · starred Sep 2026
71 followers · starred Oct 2025
179 followers · starred Apr 2025