آموزش نصب Actual Budget روی VPS با Docker Compose
نصب Actual Budget روی سرور شخصی با Docker Compose. این راهنما نحوه تنظیم volume داده، پیکربندی HTTPS برای Web Crypto API و مدیریت فایلهای بودجه را برای همگامسازی امن آموزش میدهد.
آنچه میسازید
Actual Budget یک برنامه بودجهبندی مبتنی بر سیستم پاکت (envelope budgeting) است که میتوانید آن را روی سرور شخصی خود میزبانی کنید. این برنامه معمولترین جایگزین برای YNAB است که کاربران برای میزبانی شخصی به سراغ آن میروند. سرور این برنامه شامل یک container، یک volume داده و یک نام HTTPS است. تمام نیازهای یک بودجهبندی معمولی بهراحتی روی کوچکترین VPS قابل اجاره اجرا میشود، زیرا وظیفه اصلی سرور، ذخیرهسازی فایلها و همگامسازی آنهاست.
پیش از آنکه هر دستوری را تایپ کنید، درک معماری آن اهمیت دارد. خودِ بودجه، یک پایگاه داده SQLite است که درون مرورگر و هر یک از برنامههای موبایل شما قرار دارد. سروری که قصد نصب آن را دارید، یک نقطه پایانی (endpoint) برای همگامسازی است: این سرور لیست حسابها، فایلهای بودجه و لاگ تغییراتی را نگه میدارد که باعث میشود گوشی و لپتاپ شما با هم هماهنگ باشند. به همین دلیل است که برنامه حتی در زمان قطع بودن سرور همچنان کار میکند و به همین دلیل است که از دست رفتن سرور به معنای از دست رفتن بودجه شما نیست، تا زمانی که حداقل یک کلاینت، نسخهای از آن را در اختیار داشته باشد.
چرا سرور به HTTPS نیاز دارد
Actual برای HTTPS درخواست میفرستد و این یک تشریفات اداری نیست. مرورگرها Web Crypto API را—که رابط مورد استفادهٔ Actual برای رمزنگاری سرتاسری (end-to-end) است—فقط در چیزی که مشخصات فنی آن را «بستر امن» (secure context) مینامد، در دسترس قرار میدهند. بستر امن یعنی https:// یا http://localhost. اگر برنامه را از طریق http://203.0.113.10:5006 در مرورگر یک دستگاه دیگر بارگذاری کنید، این قابلیتها به سادگی وجود نخواهند داشت، زیرا مرورگر هرگز آنها را در اختیار صفحه قرار نمیدهد. نسخههای رسمی موبایل نیز از اتصال به آدرس سرور با پروتکل سادهٔ http:// خودداری میکنند.
بنابراین دو پیکربندی عملی وجود دارد. یا یک گواهی معتبر روی یک نام دامنهٔ واقعی در مقابل container قرار دهید که این راهنما نیز همین کار را انجام میدهد، یا با استفاده از ACTUAL_HTTPS_KEY و ACTUAL_HTTPS_CERT یک گواهی خودامضا (self-signed) به سرور اختصاص دهید (که در مستندات پروژه آمده است) و هشدار مرورگر را در هر دستگاه بپذیرید. دریافت یک گواهی رایگان از Let's Encrypt تنها 5 دقیقه زمان میبرد، پس گزینهٔ اول را انتخاب کنید.
نصب Actual Budget با Docker Compose
اگر سرور شما تازه راهاندازی شده است، ابتدا Docker را نصب کنید. اگر با سینتکس فایل Compose آشنا نیستید، راهنمای اصول Docker Compose برای VPS فیلدهای استفادهشده در زیر را پوشش میدهد.
sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/dataفایل /opt/actual/docker-compose.yml را بنویسید:
services:
actual:
image: actualbudget/actual-server:latest
container_name: actual
restart: unless-stopped
ports:
- '127.0.0.1:5006:5006'
volumes:
- ./data:/dataسه جزئیات در این فایل اهمیت دارند.
ایمیج مورد استفاده actualbudget/actual-server:latest است که توسط پروژه در Docker Hub منتشر شده و در ghcr.io/actualbudget/actual نیز آینهسازی میشود. یک تگ latest-alpine برای ماشینهای کممصرف وجود دارد.
کانتینر همه چیز را در مسیر /data مینویسد. در داخل آن، شما server-files را دارید که شامل account.sqlite برای توکنهای ورود و نشست (session) است، و همچنین user-files که فایلهای بودجه را در خود نگه میدارد. این مسیر را Mount کنید، در غیر این صورت با docker compose pull، بودجه شما از بین میرود. ACTUAL_DATA_DIR میتواند آن را جابهجا کند، اما مقدار پیشفرض مناسب است.
پورت فقط روی 127.0.0.1 منتشر میشود. یک 5006:5006 ساده، پورت را روی تمام اینترفیسها منتشر میکند و Docker قوانین خود را پیش از ufw مینویسد، بنابراین برنامه حتی با وجود فایروال deny-all، در دسترس اینترنت قرار میگیرد. این غافلگیری در چرا پورتهای منتشر شده توسط Docker از ufw عبور میکنند توضیح داده شده است. اتصال به loopback به این معنی است که فقط reverse proxy روی همان سرور میتواند به آن دسترسی داشته باشد.
آن را اجرا کنید:
cd /opt/actual
docker compose up --detach
docker compose logs -f actualپس از اینکه سرور گزارش داد که روی پورت 5006 در حال گوش دادن است، لاگها تثبیت میشوند. پیش از دست زدن به DNS، آن را بهصورت محلی بررسی کنید:
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/یک 200 به این معنی است که برنامه در حال سرویسدهی است. curl: (7) Failed to connect به این معنی است که کانتینر در حال اجرا نیست و docker compose ps نشان میدهد که کانتینر متوقف شده است. علت معمول این مشکل، خطای مجوز (permission) روی volume متصلشده است که به صورت یک خط EACCES در لاگ قابل مشاهده است.
قرار دادن گواهی و نام واقعی در مقابل
یک رکورد A را به سمت VPS خود، budget.example.com، هدایت کنید و منتظر بمانید تا resolve شود. سپس nginx را نصب کرده و گواهی را صادر کنید. راهنمای Certbot روی Ubuntu 24.04 با nginx، صدور گواهی و زمانبندی تمدید آن را بهطور کامل پوشش میدهد.
بلاک پروکسی:
server {
listen 443 ssl;
http2 on;
server_name budget.example.com;
ssl_certificate /etc/letsencrypt/live/budget.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/budget.example.com/privkey.pem;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:5006;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}client_max_body_size خطی است که افراد فراموش میکنند. فایل بودجه در یک همگامسازی کامل بهصورت یکجا آپلود میشود. مقدار پیشفرض Nginx برای بدنه درخواست 1 MB است، بنابراین وقتی حجم فایل از این مقدار فراتر رود، همگامسازی با خطای 413 Request Entity Too Large در لاگ دسترسی nginx شکست میخورد، در حالی که برنامه فقط یک خطای همگامسازی عمومی نشان میدهد. سرور محدودیتهای جداگانه خود را دارد: ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB بهصورت پیشفرض 20 و ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB بهصورت پیشفرض 50 است، بنابراین محدودیت nginx را بالاتر از هر کدام که برای شما اعمال میشود، تنظیم کنید.
بارگذاری مجدد و تست:
sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/اولین اجرا: رمز عبور و اولین فایل بودجه
https://budget.example.com را در مرورگر باز کنید. صفحه اول از شما میخواهد که یک رمز عبور برای سرور تعیین کنید. این رمز عبور واحد، از کل سرور محافظت میکند؛ بنابراین یک رمز عبور طولانی و تصادفی ایجاد کنید و آن را در جایی امن نگهداری کنید، مانند مدیریت رمز عبور Vaultwarden که خودتان میزبانی میکنید. هیچ حساب کاربری برای ایجاد وجود ندارد. سرور Actual بهگونهای طراحی شده که تنها یک رمز عبور داشته باشد، بنابراین اشتراکگذاری بودجه به معنای اشتراکگذاری همان رمز عبور است.
سپس یک فایل بودجه ایجاد کنید. Actual میپرسد که آیا میخواهید رمزنگاری سرتاسری (end-to-end encryption) را فعال کنید یا خیر. پاسخ مثبت بدهید؛ در این صورت سرور فقط دادههای رمزنگاریشده را ذخیره میکند که برای دادههای مالی روی یک ماشین اجارهای، بهترین گزینه است. هزینه این کار واقعی است: رمز عبور رمزنگاری هرگز به سرور ارسال نمیشود، بنابراین اگر آن را گم کنید، فایل برای همیشه از دست میرود و هیچ راهی برای بازیابی آن وجود ندارد. پیش از عبور از این صفحه، آن را یادداشت کنید.
موجودیهای اولیه خود را بر اساس ارقام فعلی بانکتان تنظیم کنید، نه با وارد کردن تاریخچه چندین ساله. بودجهبندی پاکتی (Envelope budgeting) از پولی که اکنون در اختیار دارید به سمت آینده حرکت میکند، بنابراین نداشتن تاریخچه قبلی هیچ خللی در کار شما ایجاد نمیکند.
وارد کردن تراکنشها
در این بخش، صداقت اهمیت بیشتری از اشتیاق دارد، زیرا فرایند وارد کردن دادهها اصلیترین دلیلی است که کاربران از سیستمهای بودجهبندی self-hosted دلسرد میشوند.
ثبت دستی، روش پایه است و همیشه کار میکند. برای روش پاکتبندی (envelope method)، میتوان گفت این دقیقاً همان هدف اصلی است، چرا که تایپ کردن یک خرید باعث میشود نسبت به آن آگاه شوید.
وارد کردن فایل (File import) حجم اصلی کار را انجام میدهد. Actual از فرمتهای CSV، QIF، OFX و QFX پشتیبانی میکند و هر بانکی حداقل یکی از این فرمتها را خروجی میدهد. وارد کردن را برای هر حساب از صفحه همان حساب انجام دهید، ستونها را یکبار نگاشت (map) کنید و Actual آن چیدمان را برای آن حساب به خاطر میسپارد.
همگامسازی خودکار بانکی نیز وجود دارد، اما به یک سرویس شخص ثالث نیاز دارد زیرا سرور نمیتواند بهتنهایی با بانکها ارتباط برقرار کند. Actual از SimpleFIN Bridge برای بانکهای آمریکای شمالی، Enable Banking برای اروپا، Akahu برای نیوزیلند و Pluggy.ai برای برزیل پشتیبانی میکند. GoCardless همچنان پشتیبانی میشود اما حساب جدید نمیپذیرد. شما باید شخصاً در این سرویسدهندهها ثبتنام کنید، اعتبارنامه (credentials) تولید کنید و آنها را به سرور اضافه نمایید. تا تاریخ July 2026، هزینه SimpleFIN Bridge برای حداکثر 25 موسسه، 15 دلار آمریکا در سال است و سایر سرویسها قیمتگذاری متفاوتی دارند.
پیش از تکیه بر این قابلیت، دو محدودیت را بپذیرید. اعتبارنامههای API روی سرور قرار میگیرند و تحت پوشش رمزنگاری سرتاسری (end-to-end encryption) نیستند، زیرا سرور باید از آنها استفاده کند. همچنین Actual عملیات polling انجام نمیدهد: همگامسازی دکمهای است که شما فشار میدهید، نه یک job پسزمینه.
پشتیبانگیری، چون فقط با فایل سروکار داریم
هر چیزی که برای شما اهمیت دارد در مسیر /opt/actual/data قرار گرفته است. هیچ مرحلهٔ خروجی گرفتن (export) یا اسکریپت دامپ دیتابیس وجود ندارد.
تنها نکتهٔ مهم، SQLite است. کپی کردن account.sqlite در حالی که سرور در حال نوشتن روی آن است، ممکن است باعث ثبت یک تراکنش ناقص شود و شما تا زمانی که قصد بازیابی (restore) نداشته باشید، متوجه آن نخواهید شد. برای چند ثانیهای که کپی انجام میشود، کانتینر را متوقف کنید:
cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose startاین کار را با استفاده از روشی که در پشتیبانگیری restic روی VPS توضیح داده شده است، زمانبندی کنید. این راهنما شامل تنظیم مخزن (repository)، سیاست نگهداری و تمرین بازیابی است. تمرین بازیابی را حتماً انجام دهید. پشتیبانی که هرگز بازیابی نشده است، فقط یک حدس و گمان است.
پشتیبانگیریهای سمت کلاینت خودِ Actual موضوعی جداگانه است که دانستن آن ارزشمند است. مرورگر نسخههای اخیر فایل بودجه را نگه میدارد که از طریق منوی فایل قابل دسترسی است. این قابلیت مشکلاتی مانند «حذف اشتباه یک دستهبندی» را بدون نیاز به دست زدن به سرور، حل میکند.
بهروزرسانی سرور
cd /opt/actual
docker compose pull
docker compose up --detachCompose کانتینر را از image جدید دوباره ایجاد میکند و همان volume را دوباره متصل میکند؛ بنابراین دادهها حفظ میشوند. کلاینتها را نیز بهروزرسانی کنید. انتظار میرود نسخههای سرور و برنامه نزدیک به هم باشند، و کلاینتی که بسیار قدیمیتر از سرور باشد ممکن است بهدلیل ناسازگاری نسخه، از همگامسازی خودداری کند. پیش از پرش به یک نسخه اصلی جدید، backup بگیرید؛ زیرا migrationها در اولین start اجرا میشوند و مسیر downgrade وجود ندارد. استفاده از tag شناور latest در Actual قابلتحمل است، زیرا state آن یک directory از فایلهاست؛ اما این روش برای برنامهای که database واقعی دارد مناسب نیست. راهنمای self-hosting چتوود tagهای ثابت و dump پیش از ارتقا را که در چنین شرایطی لازم است، توضیح میدهد.
چه چیزی دچار اختلال میشود و چه چیزی مشاهده خواهید کرد
برنامه بارگذاری میشود اما همگامسازی هرگز به پایان نمیرسد. لاگ دسترسی nginx را برای 413 بررسی کنید. این یعنی client_max_body_size بیش از حد پایین تنظیم شده است. در مقابل، یک 502 به این معنی است که nginx در دسترس است اما container بالا نیامده است.
گزینههای رمزنگاری وجود ندارند یا اپلیکیشن موبایل URL را نمیپذیرد. صفحه در یک بستر امن (secure context) قرار ندارد. در نوار آدرس، http:// با یک آدرس IP یا نام میزبانی نمایش داده میشود که localhost نیست. به جای دور زدن مشکل، گواهی (certificate) را اصلاح کنید.
پیامی مبنی بر اینکه فایل بودجه با این نسخه سازگار نیست. نسخههای کلاینت و سرور با هم اختلاف پیدا کردهاند. هر دو را به یک نسخه (release) بهروزرسانی کرده و صفحه را مجدداً بارگذاری کنید.
کانتینر در یک حلقه (loop) مدام ریاستارت میشود. docker compose logs actual را بخوانید. خطای مجوز (permission error) در /data به این معنی است که دایرکتوری mount شده برای کاربری که کانتینر را اجرا میکند، قابل نوشتن نیست. خطای address-in-use به این معنی است که سرویس دیگری در حال حاضر پورت 5006 را روی loopback اشغال کرده است.
بارگذاری اولیه کند به نظر میرسد. هنگام باز کردن فایل بودجه، کل فایل در مرورگر دانلود میشود. این یک انتقال دادهٔ حجیم است و پس از آن، خواندن اطلاعات بهصورت محلی انجام میشود. این مشکل مربوط به ابعاد سرور نیست و افزایش RAM تغییری در آن ایجاد نخواهد کرد.
FAQ
آیا Actual Budget برای کارکرد به HTTPS نیاز دارد؟
بله، در عمل چنین است. رمزنگاری سرتاسری (end-to-end) در Actual از Web Crypto API مرورگر استفاده میکند و مرورگرها این قابلیت را فقط در بستر امن، یعنی https:// یا http://localhost، در دسترس قرار میدهند. از طریق HTTP معمولی و از یک دستگاه دیگر، این ویژگیها غیرفعال هستند و اپلیکیشنهای رسمی موبایل نیز آدرس سرور HTTP ساده را نمیپذیرند. از یک گواهی Let’s Encrypt روی یک نام دامنه واقعی استفاده کنید، یا اگر فقط از مرورگر دسکتاپ استفاده میکنید، یک گواهی خود-امضا (self-signed) با ACTUAL_HTTPS_KEY و ACTUAL_HTTPS_CERT به کار ببرید.
آیا Actual میتواند تراکنشهای بانکی من را بهطور خودکار وارد کند؟
فقط از طریق سرویسهای شخص ثالثی که خودتان در آنها ثبتنام میکنید: SimpleFIN Bridge در آمریکای شمالی، Enable Banking در اروپا، Akahu در نیوزیلند یا Pluggy.ai در برزیل. GoCardless نیز پشتیبانی میشود اما حساب جدید نمیپذیرد. اعتبارنامههای این APIها روی سرور شما ذخیره میشوند و تحت پوشش رمزنگاری سرتاسری نیستند. همگامسازی نیز دستی است؛ یعنی باید دکمهای را فشار دهید و هیچ فرآیندی در پسزمینه تراکنشها را بررسی نمیکند. برای وارد کردن فایلهای CSV، QIF، OFX و QFX به هیچ شخص ثالثی نیاز ندارید.
دقیقاً از چه چیزی باید نسخه پشتیبان تهیه کنم؟
از دایرکتوری دادههای mount شده که در این راهنما /opt/actual/data نام دارد. این دایرکتوری شامل server-files/account.sqlite برای ورودها و نشستها (sessions) و user-files برای فایلهای بودجه است. پیش از کپی کردن، container را متوقف کنید، زیرا کپی کردن یک دیتابیس SQLite در حال اجرا ممکن است منجر به ثبت ناقص دادهها شود. هیچ جای دیگری در سرور وضعیت (state) برنامه را نگه نمیدارد.
اگر رمز عبور رمزنگاری را گم کنم چه میشود؟
فایل قابل بازیابی نیست. رمز عبور هرگز به سرور ارسال نمیشود و این دقیقاً هدف اصلی رمزنگاری سرتاسری است؛ بنابراین امکان بازنشانی (reset) یا مسیر پشتیبانی برای آن وجود ندارد. به محض ایجاد فایل، آن را در یک مدیریتکننده رمز عبور ذخیره کنید و نسخهای از آن را در جایی نگه دارید که به همین سرور وابسته نباشد.
Actual Budget به چه میزان منابع سرور نیاز دارد؟
بسیار کم. این container فقط داراییهای ایستا (static assets) و فایلها را ارائه میدهد و محاسبات بودجه در مرورگر انجام میشود. یک vCPU اشتراکی با 1 GB رم برای اجرای آن کافی است و دایرکتوری داده برای بودجه یک خانواده با چندین سال سابقه، تنها چند ده مگابایت فضا اشغال میکند. فشار روی دیسک ناشی از نسخههای پشتیبان و سایر containerهای شماست، نه Actual. اگر در حال انتخاب سروری هستید که باید برنامههای سنگینتری را در کنار آن اجرا کند، معمولاً سرورهای عکس تعیینکننده حداقل منابع هستند؛ بنابراین پیش از انتخاب پلن، بررسی کنید که PhotoPrism و Immich واقعاً به چه مقدار رم نیاز دارند.