Operations
First-deploy onboarding
From an empty Ubuntu VPS to a running Helios platform on your domain in ~75 minutes.
Replace
your-domain.tldwith your domain and1.2.3.4with your server's public IPv4 throughout.
Prerequisites
- Ubuntu 24.04 LTS VPS, 4 vCPU / 8 GB RAM minimum.
- Docker 27+, Docker Compose v2.
- A domain with DNS control.
- A Telegram bot token from
@BotFather. - Your numeric Telegram user id from
@userinfobot.
Step 1 — DNS
Add these records:
| Type | Name | Value |
|---|---|---|
| A | @ | 1.2.3.4 |
| A | app | 1.2.3.4 |
| A | api | 1.2.3.4 |
| A | docs | 1.2.3.4 |
| CAA | @ | 0 issue "letsencrypt.org" |
Wait 5–10 minutes; verify with dig +short api.your-domain.tld @1.1.1.1.
Step 2 — clone + secrets
git clone <your-fork> /opt/helios && cd /opt/helios
cp .env.example .env
chmod 600 .env
Generate secrets — the values go straight into .env:
openssl rand -hex 32 # AES_MASTER_KEY
openssl rand -base64 24 | tr -d /=+ | cut -c1-32 # postgres owner pwd
openssl rand -base64 24 | tr -d /=+ | cut -c1-32 # postgres app pwd
openssl rand -base64 24 | tr -d /=+ | cut -c1-32 # minio root pwd
openssl rand -hex 32 # meilisearch master key
Fill in .env:
BOT_TOKEN=… # from @BotFather
OWNER_TG_USER_ID=… # from @userinfobot
BOT_USERNAME=YourBotName # without @
BRAND_NAME=YourBrand
PUBLIC_BASE_URL=https://api.your-domain.tld
PORTAL_URL=https://your-domain.tld
SUPPORT_EMAIL=[email protected]
POSTGRES_OWNER_PASSWORD=<from openssl>
POSTGRES_APP_PASSWORD=<from openssl>
POSTGRES_URL=postgresql+asyncpg://helios_app:<app-pwd>@postgres:5432/helios
POSTGRES_URL_SYNC=postgresql+psycopg2://helios:<owner-pwd>@postgres:5432/helios
AES_MASTER_KEY=<from openssl>
S3_SECRET_KEY=<minio pwd>
MINIO_ROOT_PASSWORD=<minio pwd>
MEILI_API_KEY=<meili key>
API_CORS_ALLOWED_ORIGINS=https://your-domain.tld,https://app.your-domain.tld
Step 3 — nginx + TLS
sudo cp infra/nginx/sites-available/helios.mom.conf \
/etc/nginx/sites-available/your-domain.tld.conf
# edit server_name lines to match your domain
sudo ln -sf /etc/nginx/sites-available/your-domain.tld.conf \
/etc/nginx/sites-enabled/
sudo mkdir -p /var/www/letsencrypt
sudo nginx -t && sudo systemctl reload nginx
sudo certbot certonly --webroot -w /var/www/letsencrypt \
-d your-domain.tld -d app.your-domain.tld \
-d api.your-domain.tld -d docs.your-domain.tld \
--email [email protected] --agree-tos --non-interactive --no-eff-email
Edit the vhost to add the 443 server blocks (see
/etc/nginx/sites-available/helios.mom.conf for the template), then
reload nginx.
Step 4 — build the frontends
cd apps/miniapp && pnpm install --frozen-lockfile && \
VITE_API_BASE=https://api.your-domain.tld pnpm build && cd ../..
sudo mkdir -p /var/www/your-domain.tld/{miniapp,docs}
sudo cp -r apps/miniapp/dist/. /var/www/your-domain.tld/miniapp/
sudo chown -R www-data:www-data /var/www/your-domain.tld
Step 5 — bootstrap
./bootstrap.sh
The script:
- Validates
.env. - Pulls docker images.
- Brings up postgres + redis + minio + meilisearch.
- Runs
alembic upgrade head. - Seeds the parameters registry.
- Runs preflight checks (stealth whitelist).
- Starts the application stack (api, bot, 11 workers).
- Polls
/healthzuntil it returns 200.
Total time: ~5 minutes on a fresh server.
Step 6 — first /start
Open Telegram → message your bot → /start. The owner panel button is
visible only to the OWNER_TG_USER_ID you configured.
Done
Verify:
curl https://api.your-domain.tld/healthz
# {"status":"ok"}
curl https://api.your-domain.tld/v1/public/config | jq
# { "bot_username": "...", "brand_name": "...", ... }
If anything went wrong, the runbook has the first three things to check for the common incidents.