نصب میز پشتیبانی روی زیرساخت خودتان
میز پشتیبانی روال را میشود روی سرور خود شرکت نصب کرد. گفتگوها، فایلهای تماس و ایندکس جستوجو در دیتابیس خودتان میمانند و سرور فقط با api.revaal.app در داخل ایران حرف میزند. این صفحه همهٔ مراحل را از یک سرور خالی تا میزی که کار میکند میگوید.
چه چیزی کجاست#
روی سرور شما چهار سرویس اجرا میشود: برنامهٔ وب میز، api آن، انبار دانش (برای جستوجو) و Caddy که درِ ورود وب با گواهی TLS است. اگر فایلهای تماس خوانده شوند، یک رابط هم کنارشان کار میکند. همهٔ داده در PostgreSQL خودتان است: گفتگوها، تماسها و فایل صدایشان، ایندکس جستوجو و درخت موضوعها.
کار هوش مصنوعی (رونویسی، خلاصه و دستهبندی، ساخت بردار برای جستوجو) را روال انجام میدهد. سرور شما برای همهٔ اینها فقط به api.revaal.app وصل میشود و روال چیزی از آن را نگه نمیدارد.
- از اینترنت هیچ دسترسی ورودیای به سرور لازم نیست، مگر اینکه نام عمومی و گواهی Let's Encrypt بخواهید.
- نسخههای تازه شبها خودشان نصب میشوند؛ پیش از هر بهروزرسانی از دیتابیس نسخهٔ پشتیبان گرفته میشود و اگر نسخهٔ تازه بالا نیاید، نسخهٔ قبلی برمیگردد.
- اشتراک با یک کلید لایسنس کار میکند. نصب روزی یک بار با روال تماس میگیرد و فقط جمع مصرف را گزارش میکند، نه محتوا.
پیش از شروع#
روال اینها را به شما میدهد:
| مورد | برای چه |
|---|---|
| کلید لایسنس | فعالسازی، ساخت اولین مدیر و تماس روزانه با روال. تنها کلیدی که روی سرور میگذارید. |
| حساب رجیستری registry.revaal.app (فقط دانلود) | دریافت ایمیجها و نسخههای تازه. |
و شما اینها را آماده میکنید:
- یک سرور لینوکسی با Docker (بخش بعد).
- یک دیتابیس PostgreSQL (بخش «دیتابیس»).
- یک نام برای میز، مثلاً desk.company.ir، که به این سرور اشاره کند.
- اختیاری: گواهی TLS شرکت برای همان نام. بدون آن، Caddy خودش گواهی میسازد.
سرور و شبکه#
| مورد | حداقل |
|---|---|
| سیستمعامل | Ubuntu 22.04 یا 24.04 (روی 24.04 آزمایش شده) |
| پردازنده و حافظه | ۲ هسته، ۴ گیگابایت رم |
| دیسک | ۳۰ گیگابایت آزاد برای Docker. ایمیجها حدود ۱٫۶ گیگابایتاند و نسخههای پشتیبانِ پیش از بهروزرسانی هم همینجا ذخیره میشوند. |
| نرمافزار | Docker Engine با افزونهٔ docker compose (نسخهٔ ۲)، curl و jq |
| جهت | مقصد | پورت | برای چه |
|---|---|---|---|
| خروجی | api.revaal.app (ایران) | 443 | لایسنس، رونویسی، مدلها و بردارها |
| خروجی | registry.revaal.app (ایران) | 443 | ایمیجها و نسخههای تازه |
| خروجی | api.goftino.com | 443 | فقط اگر منبع گفتینو وصل شود |
| داخل شبکه | FTP مرکز تلفن | 21 | فقط اگر فایلهای تماس خوانده شوند |
| داخل شبکه | PostgreSQL | 5432 | دادههای میز |
| ورودی | سیستمهای کارکنان | 443 (و 80) | باز کردن میز در مرورگر |
اگر میز نام عمومی دارد و گواهی Let's Encrypt میخواهید، پورتهای 80 و 443 باید از اینترنت در دسترس باشند تا گواهی صادر و تمدید شود.
دیتابیس PostgreSQL#
میز جدولها، ایندکس جستوجو و فایلهایش را در دیتابیس شما نگه میدارد؛ بکاپ آن با خود شماست.
- نسخهٔ PostgreSQL 18 (نسخهٔ 16 هم آزمایش شده).
- افزونههای vector (pgvector) و uuid-ossp، که فقط یک superuser میتواند بسازد.
- یک کاربر که مالک دیتابیس باشد؛ میز در هر بهروزرسانی جدولهایش را میسازد و تغییر میدهد.
- دسترسی از سرور میز. اگر دیتابیس TLS را اجباری میکند، در .env مقدار DB_SSLMODE=require بگذارید.
مدیر دیتابیس یک بار، با کاربر superuser، این دستورها را اجرا میکند (رمز را خودتان انتخاب کنید):
CREATE ROLE desk LOGIN PASSWORD '...';
CREATE DATABASE desk OWNER desk;
\c desk
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";نصب#
همهٔ دستورها روی سرور میز اجرا میشوند. هر جا <version> آمده، نسخهای را بنویسید که روال اعلام کرده؛ از آن به بعد خود میز نسخههای تازه را میگیرد.
ورود به رجیستری
با حسابی که روال داده:
docker login registry.revaal.appپوشهٔ نصب و فایلهای نسخه
فایلها از خود رجیستری برداشته میشوند: docker-compose.yml، Caddyfile، .env.example و ابزار بهروزرسانی revaal-desk-update.
sudo mkdir -p /opt/revaal-desk && sudo chown "$USER" /opt/revaal-desk cd /opt/revaal-desk docker create --name bundle registry.revaal.app/onprem/desk-bundle:<version> x docker cp bundle:/bundle/. . && docker rm bundle cp .env.example .env && chmod 600 .envدو رمز محلی
این دو فقط روی همین سرور میمانند و به هیچجا فرستاده نمیشوند:
for k in AUTH_JWT_SECRET ML_API_KEY; do sed -i "s/^$k=$/$k=$(openssl rand -hex 32)/" .env; doneپر کردن بقیهٔ .env
به شکل KEY=value و بدون گیومه:
متغیر مقدار DESK_DOMAIN نام میز، مثلاً desk.company.ir DESK_TLS internal برای نام داخلی (Caddy خودش گواهی میسازد)؛ برای نام عمومی یک ایمیل، تا Caddy گواهی Let's Encrypt بگیرد و تمدید کند؛ یا گواهی شرکت: /certs/fullchain.pem /certs/privkey.pem (فایلها در پوشهٔ certs کنار همین فایل) DESK_VERSION همان <version>؛ از این پس ابزار بهروزرسانی آن را جلو میبرد DB_HOST، DB_PORT، DB_DATABASE، DB_USERNAME، DB_PASSWORD دیتابیس بخش قبل DB_SSLMODE disable، یا require REVAAL_LICENSE_KEY کلید لایسنسی که روال داده DESK_UPDATE_WINDOW (اختیاری) ساعتهایی به وقت تهران که بهروزرسانی خودکار مجاز است؛ پیشفرض 2-5 دریافت ایمیجها و اجرا
در اولین اجرا جدولها در دیتابیس خالی ساخته میشوند؛ چند ثانیه طول میکشد.
docker compose pull && docker compose up -d docker compose psبررسی فعالسازی
چند ثانیه بعد از اجرا، نصب با روال تماس میگیرد و فعال میشود. تا قبل از آن همهٔ صفحهها بهجز ورود قفلاند.
D=$(grep ^DESK_DOMAIN= .env | cut -d= -f2) curl -sk --resolve "$D:443:127.0.0.1" "https://$D/api/desk/license"پاسخ درست: "mode":"open"، و در reachable هر سه مقدار true.
نصب ابزار بهروزرسانی
یک بار. از این پس نسخههای تازه شبها خودکار نصب میشوند (بخش «بهروزرسانی و بکاپ»).
cd /opt/revaal-desk sudo install -m 0755 revaal-desk-update /usr/local/bin/ sudo DESK_DIR=/opt/revaal-desk revaal-desk-update install
اولین مدیر و همکاران#
اولین مدیر یک بار و با کلید لایسنس ساخته میشود؛ وقتی کاربری وجود داشته باشد، این درخواست رد میشود. نام، ایمیل، موبایل، نام شرکت و رمز (حداقل ۸ نویسه) پرسیده میشود:
cd /opt/revaal-desk && D=$(grep ^DESK_DOMAIN= .env | cut -d= -f2)
read -rp 'Name: ' NAME; read -rp 'Email: ' EMAIL; read -rp 'Mobile (09...): ' MOBILE
read -rp 'Workspace (company name): ' WS; read -rsp 'Password (8+): ' PASS; echo
jq -n --arg name "$NAME" --arg email "$EMAIL" --arg mobile "$MOBILE" --arg password "$PASS" --arg workspaceName "$WS" \
'{name:$name,email:$email,mobile:$mobile,password:$password,workspaceName:$workspaceName}' |
curl -sk --resolve "$D:443:127.0.0.1" -H 'content-type: application/json' \
-H "x-desk-license: $(grep ^REVAAL_LICENSE_KEY= .env | cut -d= -f2-)" -d @- "https://$D/api/desk/setup"سپس https://<DESK_DOMAIN> را در مرورگر باز کنید و با همان ایمیل و رمز وارد شوید. میز از قبل فعال است.
- گواهی داخلی: با DESK_TLS=internal، مرورگرها تا وقتی ریشهٔ Caddy روی سیستمهای کارکنان معتبر نشود هشدار میدهند. فایل ریشه را بردارید و مثلاً با Group Policy پخش کنید: docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt ./desk-root.crt
- همکاران: نصب ایمیل نمیفرستد. در «کاربران» هر نفر را با ایمیل یا موبایل اضافه کنید، لینک دعوت را کپی کنید و داخل شرکت بفرستید؛ هر نفر رمز خودش را روی همان لینک میگذارد.
- رمز فراموششده: مالک فضای کاری در «کاربران»، از منوی «⋯» کنار نام همکار، «لینکِ تغییرِ رمز» را میزند و لینک را داخل شرکت میفرستد. لینک یک بار و تا ۲۴ ساعت کار میکند و همهٔ ورودهای قبلی آن شخص را میبندد.
- لینک خود مالک روی سرور ساخته میشود (بدون ایمیل، فهرست کاربران را نشان میدهد): docker compose exec api node dist/auth/desk-password-link.js <email>
- هر کس رمز خودش را در «تنظیمات»، زبانهٔ «حساب من»، عوض میکند.
تماسها و گفتینو#
اگر میز شما از سرویس ابری روال به سرور خودتان میآید، این دو را بعد از انتقال دادهها و با هماهنگی روال وصل کنید. منبع گفتینو که همزمان در دو جا خوانده شود، دو بار خوانده و دو بار هزینه میشود.
تماسها: رابط تماس فایلهای ضبط را از FTP مرکز تلفن (Asterisk، Issabel یا FreePBX) میخواند و برای میز میفرستد.
کلید ارسال
در میز: «منابع» ← «ارسال با API» ← کلید را کپی کنید.
فایل connector.env
کنار docker-compose.yml بسازید (chmod 600) و پر کنید:
متغیر مقدار REVAAL_KEY کلید مرحلهٔ قبل FTP_HOST، FTP_USER، FTP_PASSWORD نشانی FTP مرکز تلفن و کاربری با دسترسی فقط خواندن FTP_DIR پوشهای که پوشههای سال (2026/، 2025/ …) زیر آن است SINCE اولین روزی که تماسهایش فرستاده شود، YYYY-MM-DD OPERATORS نام اپراتورها بر اساس داخلی: 101=نام,102=نام اجرا
docker compose --profile calls up -d connectorتماسهای کوتاهتر از ۱۵ ثانیه و تماسهای بین دو داخلی فرستاده نمیشوند. رمز FTP فقط روی همین سرور میماند.
اگر مرکز تلفن در شبکهٔ دیگری است (مثلاً میز روی یک سرور ابری و مرکز تلفن در دفتر)، رابط را روی ماشینی داخل شبکهٔ دفتر اجرا کنید و نشانی میز را به آن بدهید: در connector.env همان متغیرها، بهاضافهٔ REVAAL_URL=https://<DESK_DOMAIN>، و کنارش این docker-compose.yml:
services:
connector:
image: registry.revaal.app/onprem/desk-connector:<version>
restart: unless-stopped
env_file: connector.env
volumes:
- connector-data:/data
volumes:
connector-data:با DESK_TLS=internal، ریشهٔ Caddy را به رابط هم بدهید: فایل desk-root.crt را در container بگذارید و NODE_EXTRA_CA_CERTS را به آن اشاره دهید. volume با نام connector-data دفتر ارسالهاست؛ پاکش نکنید، وگرنه همهٔ تماسها دوباره فرستاده و دوباره هزینه میشوند.
گفتینو: در میز، «منابع» ← گفتینو، با توکن گفتینوی شرکت.
بهروزرسانی و بکاپ#
بهروزرسانی خودکار است. ابزار revaal-desk-update هر ساعت نسخهٔ تازه را بررسی میکند و آن را شبها، بین ۲ تا ۵ بامداد به وقت تهران، نصب میکند. مالک فضای کاری در «تنظیمات» ← «نسخه» میتواند همان لحظه بهروز کند یا حالت خودکار را خاموش کند.
پیش از هر بهروزرسانی از دیتابیس نسخهٔ پشتیبان (pg_dump) در /opt/revaal-desk/backups گرفته میشود و پنج نسخهٔ آخر میماند. اگر نسخهٔ تازه تا ده دقیقه بالا نیاید، نسخهٔ قبلی خودکار برمیگردد. بکاپ منظم دیتابیس همچنان با شرکت است.
سه دستوری که لازم میشود: وضعیت و نتیجهٔ آخرین بهروزرسانی، بهروزرسانی همین حالا، و گزارش ابزار:
sudo revaal-desk-update status
sudo revaal-desk-update apply
journalctl -u revaal-desk-updateبرگشت به نسخهٔ قبل با هماهنگی روال انجام میشود: بکاپ پیش از بهروزرسانی و فایلهای نسخهٔ قبل (docker-compose.yml.<version> کنار فایل تازه) با هم برمیگردند.
بررسی سلامت و عیبیابی#
| بررسی | دستور | پاسخ درست |
|---|---|---|
| لایسنس و ارتباط با روال | curl -sk https://<DESK_DOMAIN>/api/desk/license | "mode":"open" و در reachable همه true |
| کانتینرها | docker compose ps | api، web، ml و caddy در حالت Up |
| لاگ برنامه | docker compose logs api --tail 200 | خط check-in ok |
- یکی از مقدارهای reachable برابر false: آن بخش از روال الان پاسخ نمیدهد، یا سرور به api.revaal.app نمیرسد. کار مربوط منتظر میماند و خودش ادامه میدهد؛ چیزی از دست نمیرود. دسترسی خروجی 443 به api.revaal.app را بررسی کنید.
- mode غیر از open بعد از نصب: خط lastError در همان پاسخ علت را میگوید (کلید اشتباه، نرسیدن به روال، لایسنس معلق).
- خطای دیتابیس در اولین اجرا (در لاگ api): اتصال (DB_HOST، شبکه، DB_SSLMODE)، رمز اشتباه، یا extension "vector" is not available که یعنی افزونهها ساخته نشدهاند.
- bound to another install: این لایسنس به سرور دیگری بسته است؛ روال باید آن را آزاد کند.
- بهروزرسانی انجام نشده: sudo revaal-desk-update status نتیجهٔ آخرین تلاش و علت شکستش را میگوید.
برای گزارش مشکل به روال، خروجی همین دستورها را بفرستید؛ هرگز فایل .env را نفرستید.
چه چیزی از سرور خارج میشود#
| مقصد | چه چیزی | برای چه |
|---|---|---|
| api.revaal.app | گزارش روزانه (نسخه، شناسهٔ نصب، جمع هزینه، بدون محتوا)؛ صدای تماس برای رونویسی؛ متن گفتگو برای خلاصه، دستهبندی و ایجنت؛ تکههای متن برای ساخت بردار | لایسنس، صورتحساب، پردازش هوش مصنوعی |
| registry.revaal.app | دانلود ایمیجها، و هر ساعت یک بار فهرست نسخهها | نصب و بهروزرسانی |
| api.goftino.com | خواندن گفتگوهای خود شرکت | منبع گفتینو |
- سرور میز مستقیم به خارج از ایران وصل نمیشود. روال کار را به سرویسهای خودش میدهد: متن از طریق پراکسی روال به مدلهای OpenRouter در خارج از ایران، و فقط به ارائهدهندگانی که داده را نگه نمیدارند؛ صدا به Soniox برای رونویسی؛ و تکههای متن به سرور بردار روال در ایران.
- روال متن و صدا را ذخیره نمیکند؛ نسخهٔ Soniox از صدای هر تماس بعد از گرفتن متن پاک میشود.
- ایندکس جستوجو، گفتگوها و فایلهای تماس فقط در دیتابیس شما میمانند.
- اطلاعات اتصال دیتابیس، رمزهای محلی و رمز FTP از سرور خارج نمیشوند.
- گزارش خطا (Sentry) روی نصب خاموش است.