آموزش نصب Vaultwarden روی VPS با داکر
راهنمای کامل راهاندازی مدیریت رمز عبور Vaultwarden روی سرور مجازی با Docker. یاد بگیرید چگونه با تنظیم HTTPS، توکن ادمین و Fail2ban امنیت دادهها را تضمین کنید.
آنچه میسازید
یک مدیریتکننده رمز عبور که مالکیت کامل آن با شماست: Vaultwarden که در یک کانتینر کوچک پشت یک reverse proxy اجرا میشود؛ پروکسیای که HTTPS را مدیریت (terminate) میکند. اپلیکیشنهای رسمی Bitwarden روی گوشی، لپتاپ و مرورگر شما به این سرور متصل میشوند. Vaultwarden پیادهسازی مجدد API سرور Bitwarden با زبان Rust است و از همان پروتکلی استفاده میکند که bitwarden.com به کار میبرد. بنابراین کلاینتهای رسمی بدون تغییر با آن کار میکنند، به شرطی که سرور را بهروز نگه دارید (نسخههای جدید کلاینت گاهی به نسخه هماهنگ Vaultwarden نیاز دارند: برای کلاینتهای 2026.8.0 و جدیدتر، نسخه 1.37.2 الزامی است). با این حال، این سرویس بهجای پشته رسمی که چندین کانتینر دارد، تنها به حدود 100 MB رم نیاز دارد.
نصب آن در واقع شامل دوازده خط کد Compose است. سه موردی که واقعاً اهمیت دارند و در صورت عدم رعایت باعث خرابی میشوند عبارتند از: TLS باید پیش از بارگذاری web vault وجود داشته باشد، ثبتنام عمومی باید بلافاصله پس از ایجاد حساب کاربری خودتان بسته شود، و از volume دادهها باید نسخه پشتیبان تهیه شده و بازیابی آن تست شود، زیرا همان یک دایرکتوری تمام رمزهای عبور شما را در خود جای داده است.
پیشنیازها و نکات مهم
- یک سرور مجازی (VPS) با Docker Engine و افزونه Compose، روی یک سیستمعامل تازه Ubuntu 24.04 KVM با دسترسی root یا sudo. مقدار 512 MB رم واقعاً کافی است؛ 1 GB رم شرایط راحتی را فراهم میکند. این یکی از سبکترین سرویسهایی است که میتوانید اجرا کنید و در صدر فهرست سرویسهای مناسب برای self-hosting قرار دارد. با این حال، منابع سرور را بر اساس سایر سرویسهای همنشین تنظیم کنید: قرار دادن یک کتابخانه عکس self-hosted مانند PhotoPrism یا Immich روی همان VPS، حداقل رم مورد نیاز را به چند گیگابایت افزایش میدهد، در حالی که Vaultwarden تأثیر ناچیزی بر مصرف رم دارد. همین محاسبات برای رابطهای کاربری رسانهای که بعداً اضافه میکنید نیز صادق است، چرا که تبدیل کتابخانه Jellyfin به یک فروشگاه کرایه فیلم دهه 90 به معنای یک کانتینر همیشه روشن دیگر به همراه فضای مورد نیاز برای transcoding در همان بودجه منابع است.
- یک دامنه با رکورد A (و AAAA اگر IPv6 دارید) که
vault.example.comبه VPS اشاره میکند. گواهی TLS برای همین نام دقیق صادر میشود، بنابراین DNS باید پیش از شروع کار، آدرس را به درستی resolve کند. - پورتهای 80 و 443 باید برای اینترنت باز باشند و توسط reverse proxy شما مدیریت شوند؛ هرگز نباید Vaultwarden مستقیماً به این پورتها متصل باشد. پورت 80 فقط برای چالش گواهی ACME و تغییر مسیر (redirect) از HTTP به HTTPS استفاده میشود.
- مهمترین نکته از همان ابتدا: کلاینتهای Bitwarden از برقراری ارتباط با سروری که HTTPS نیست، خودداری میکنند. هیچ گزینهای برای "ابتدا تست با http" وجود ندارد؛ این مسیر به دلیلی که در ادامه توضیح داده میشود، کار نمیکند.
چرا Vaultwarden و نه stack رسمی Bitwarden
کلاینتهای یکسان، با کسری از حجم مصرفی. استقرار رسمی و خودمیزبانیشده (self-hosted) Bitwarden بهصورت مجموعهای از کانتینرها (MSSQL Express، Identity، Api، Admin و موارد دیگر) عرضه میشود و حداقل به 2 GB رم نیاز دارد. Bitwarden همچنین نسخه Bitwarden lite را ارائه میدهد که یک image داکر واحد است و حداقل به 200 MB رم نیاز دارد، اما این نسخه برای استفاده شخصی و آزمایشگاههای خانگی طراحی شده است، نه برای کسبوکار، و مسئولیت دیتابیس و بکآپهای آن کاملاً بر عهده شماست. Vaultwarden یک باینری واحد است که بهصورت پیشفرض همه چیز را در یک دیتابیس SQLite ذخیره میکند و در حالت idle تنها چند ده مگابایت رم مصرف میکند. برای یک نفر، یک خانواده یا یک تیم کوچک، این انتخاب منطقی است و از آنجا که API مربوط به Bitwarden را بهدقت پیادهسازی میکند، دادههای شما بین آن و bitwarden.com قابل انتقال باقی میماند.
آنچه از دست میدهید، بخش بزرگی از قابلیتهای سازمانی است: خبری از SCIM provisioning نیست (اگرچه پشتیبانی از OpenID Connect SSO در نسخه 1.35.0 اضافه شده است) و از آنجا که شما اپراتور هستید، وظیفه اعمال وصلههای امنیتی (patching)، تنظیم HTTPS و تهیه بکآپ بر عهده خودتان است. این راهنما به همین سه وظیفه میپردازد.
چرا HTTPS اختیاری نیست
وبولت و افزونههای مرورگر Bitwarden کلیدهای رمزنگاری شما را در مرورگر و با استفاده از Web Crypto API (window.crypto.subtle) مشتق میکنند. مرورگرها تنها در یک بستر امن (Secure Context)، یعنی HTTPS یا موارد خاصی از آدرسهای loopback مانند http://localhost و http://127.0.0.1، اجازه دسترسی به crypto.subtle را میدهند. استفاده از http://vault.example.com ساده باعث میشود که undefined رخ دهد؛ بنابراین به محض اینکه برنامه سعی در مشتق کردن کلید داشته باشد، متوقف شده و کنسول پیام زیر را نمایش میدهد:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'importKey')صفحه متوقف میشود یا یک خطای عمومی رمزنگاری نمایش میدهد و هیچ عملیات ورود به سیستم انجام نمیشود. کلاینتهای دسکتاپ، موبایل و مرورگر، آدرس URL خود-میزبانیشده (self-hosted) را بررسی میکنند و در مواجهه با یک endpoint از نوع http (یا غیرقابل دسترس)، با خطای زیر از اتصال امتناع میکنند:
This is not a recognized Bitwarden server. You may need to check with your provider or update your server.هر دو مورد دلیل یکسانی دارند: نبود HTTPS معتبر. بنابراین ما ابتدا TLS را راهاندازی میکنیم و هرگز ولت را از طریق http باز نمیکنیم، حتی برای یک بررسی سریع.
گام 1، DNS و reverse proxy (ابتدا TLS)
رکورد را به سمت VPS خود هدایت کنید و مطمئن شوید که به آدرس صحیح resolve میشود:
dig +short vault.example.comخروجی این دستور باید IP سرور VPS شما باشد. اگر خروجی خالی است یا آدرس اشتباهی را نشان میدهد، تنظیمات DNS را اصلاح کنید و منتظر بمانید تا TTL منقضی شود؛ صدور گواهی برای دامنهای که resolve نمیشود، با شکست مواجه خواهد شد.
برای بخش HTTPS front end، این راهنما از Traefik استفاده میکند که گواهیهای Let's Encrypt را بهطور خودکار صادر و تمدید کرده و مستقیماً در Compose جای میگیرد. اگر هنوز آن را اجرا نکردهاید، ابتدا راهنمای راهاندازی Traefik reverse proxy و TLS خودکار را دنبال کنید؛ این کار یک شبکه Docker خارجی (proxy در ادامه) و یک ACME resolver (letsencrypt) ایجاد میکند که سرویس Vaultwarden به آن متصل میشود. استفاده از nginx ساده با گواهی دستی نیز از سمت Vaultwarden دقیقاً به همین شکل عمل میکند.
آیا nginx و Certbot را به Traefik ترجیح میدهید؟ Vaultwarden را روی 127.0.0.1:8080 قرار دهید (ports: ["127.0.0.1:8080:80"] را به سرویس اضافه کرده و برچسبهای Traefik را حذف کنید)، سپس یک گواهی صادر کرده و آن را proxy کنید. بخش مربوط به گواهی در صدور گواهیهای Let's Encrypt با Certbot و nginx پوشش داده شده است. نکته حیاتی اضافی، ارتقای WebSocket در مسیر notifications است:
server {
listen 443 ssl;
server_name vault.example.com;
client_max_body_size 525M;
location / {
proxy_pass http://127.0.0.1:8080;
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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}به خط X-Real-IP توجه کنید؛ این همان چیزی است که به Fail2ban اجازه میدهد بعداً مهاجم واقعی را به جای 127.0.0.1 مشاهده کند. تمام موارد دیگر در این راهنما، فارغ از اینکه Traefik یا nginx در مقابل قرار گرفته باشد، یکسان است.
گام 2، فایل Compose
ابتدا دایرکتوری پروژه را ایجاد کنید. این راهنما از /opt/vaultwarden استفاده میکند که باعث میشود نام پروژه Compose و در نتیجه volume دادهها یعنی vaultwarden_vw-data، قابل پیشبینی باشد؛ مراحل Fail2ban و پشتیبانگیری در ادامه، به همین نام دقیق وابسته هستند.
sudo mkdir -p /opt/vaultwarden
cd /opt/vaultwardenیک .env برای secret مدیریت و فایل Compose در آن دایرکتوری ایجاد کنید.
# .env
ADMIN_TOKEN=paste-a-strong-token-hereآن توکن را با openssl rand -base64 48 تولید کرده و در فایل قرار دهید. (یک فرم هششده قویتر در مرحله بعد بررسی میشود؛ یک رشته تصادفی طولانی برای شروع کافی است.)
# docker-compose.yml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: "https://vault.example.com"
SIGNUPS_ALLOWED: "true" # closed in Step 4, keep true just to register
ADMIN_TOKEN: "${ADMIN_TOKEN}"
IP_HEADER: "X-Forwarded-For" # X-Real-IP if your proxy sends that instead
LOG_FILE: "/data/vaultwarden.log"
LOG_LEVEL: "warn"
volumes:
- vw-data:/data
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.vw.rule=Host(`vault.example.com`)"
- "traefik.http.routers.vw.entrypoints=websecure"
- "traefik.http.routers.vw.tls.certresolver=letsencrypt"
- "traefik.http.services.vw.loadbalancer.server.port=80"
volumes:
vw-data:
networks:
proxy:
external: trueدو نکته در مورد این فایل، کل طراحی را در بر میگیرد. هیچ mapping برای ports: وجود ندارد، بنابراین Vaultwarden فقط از طریق Traefik و TLS آن در دسترس است؛ انتشار پورت آن روی host همان روشی است که باعث میشود کاربران بهطور تصادفی vault را از طریق http ارائه دهند. و DOMAIN باید آدرس کامل و عمومی HTTPS باشد: این مقدار در لینکهای پیوست، WebAuthn 2FA و endpoint اعلانها گنجانده میشود، بنابراین یک مقدار اشتباه یا http باعث از کار افتادن آنها میشود، حتی اگر سایت بارگذاری شود. تگ latest یک استثنای عمدی نسبت به قانون معمولِ هرگز-latest است؛ Vaultwarden نسخههای پایدار خود را به عنوان یک image واحد و در حال تغییر (rolling) عرضه میکند و :testing کانال جداگانه برای نسخههای پیشانتشار (pre-release) است، بنابراین بهصورت آگاهانه بهروزرسانی کنید و پیش از pull کردن، یادداشتهای انتشار را مرور کنید. البته این استثنا محدود است: اکثر کانتینرهای با عمر طولانی بهتر است به یک تگ دقیق متصل (pin) شوند، که همان چیزی است که یک agent همیشه روشن که روی همان VPS میزبانی میشود را در طول rebootها و pullها قابل پیشبینی نگه میدارد.
سرویس را بالا بیاورید و لاگ را مشاهده کنید:
docker compose up -d
docker compose logs -f vaultwardenیک شروع صحیح با خطی مانند Rocket has launched from http://0.0.0.0:80 پایان مییابد. چند ثانیه به Traefik فرصت دهید تا گواهی را دریافت کند، سپس https://vault.example.com را بارگذاری کنید؛ باید web vault مربوط به Bitwarden را با یک قفل معتبر و بدون هشدار گواهی مشاهده کنید.
گام 3، یک ADMIN_TOKEN قوی و تلهی $$
ADMIN_TOKEN از /admin محافظت میکند؛ پنلی که میتواند تمام کاربران و تنظیمات نمونهٔ شما را بخواند، بنابراین با آن مانند رمز عبور root رفتار کنید. دو روش برای این کار وجود دارد.
روش ساده، همان رشتهٔ تصادفی است که قبلاً با openssl rand -base64 48 تولید کردهاید. از آنجا که base64 هرگز شامل $ نمیشود، بدون نیاز به escaping مستقیماً در .env قرار میگیرد.
روش سختگیرانهتر، استفاده از هش Argon2 PHC است تا توکن متنی (plaintext) هرگز روی دیسک ذخیره نشود. یک هش با همان image تولید کنید:
docker run --rm -it vaultwarden/server /vaultwarden hash --preset owaspاین دستور دو بار از شما ورودی میگیرد و رشتهای که با $argon2id$v=19$... شروع میشود را چاپ میکند. این همان تلهای است که وقت بسیاری از کاربران را میگیرد: Docker Compose کاراکتر $ را به عنوان متغیر در نظر میگیرد، بنابراین اگر هش را مستقیماً زیر environment: در فایل Compose قرار میدهید، باید تمام $ها را به $$ تبدیل کنید. قرار دادن مقدار داخل کوتیشن مشکلی ندارد؛ مهم همان escaping است:
environment:
ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$c29tZXNhbHQ$$RdescudvJCsgt3ub+b+dWRWJTmaaJObGاگر ترجیح میدهید هش را در .env نگه دارید، قاعده تغییر میکند: علامتهای $ را به صورت تکی باقی بگذارید، کل مقدار را داخل کوتیشن تکی (ADMIN_TOKEN='$argon2id$v=19$...') قرار دهید و خط ${ADMIN_TOKEN} موجود در فایل Compose آن را فراخوانی میکند. هرگز $ را در .env دوبرابر نکنید. اگر علامتهای $ را به صورت تکی در خود فایل Compose رها کنید، Compose هشدار The "argon2id" variable is not set را نمایش داده و توکن را خالی میکند، سپس /admin رمز عبور صحیح شما را رد میکند. دستور docker compose up -d را اجرا کنید و متن اصلی که در اعلان وارد کردهاید را در مدیریت رمز عبور خود نگه دارید.
گام 4، ثبتنام حساب کاربری و سپس بستن دسترسی
با استفاده از SIGNUPS_ALLOWED: "true"، فایل https://vault.example.com را باز کنید، روی Create account کلیک کنید و با ایمیل و یک رمز عبور اصلی (master password) قوی ثبتنام کنید. این رمز عبور اصلی هرگز قابل بازیابی نیست و امکان بازنشانی (reset) وجود ندارد، بنابراین ابتدا آن را در جای امن و پایداری ذخیره کنید.
اکنون دسترسی را ببندید. فایل Compose را ویرایش کنید تا ثبتنام غیرفعال شود:
SIGNUPS_ALLOWED: "false"تغییرات را با docker compose up -d اعمال کنید. این یک اقدام امنیتی است که نباید به تعویق بیفتد. اگر ثبتنام باز بماند، هر کسی که URL را پیدا کند (و خزندههای وب حتماً آن را پیدا میکنند) میتواند در سرور شما یک حساب کاربری بسازد. آنها نمیتوانند به vault شما دسترسی داشته باشند، اما منابع سرور را مصرف کرده و نمونهٔ خصوصی شما را به یک سرویس عمومی تبدیل میکنند. نشانهٔ باز ماندن ثبتنام این است که /admin حسابهایی را فهرست میکند که شما هرگز ایجاد نکردهاید.
برای افزودن اعضای خانواده یا همکاران در آینده بدون بازگشایی ثبتنام عمومی، از دکمهٔ Invite User در /admin استفاده کنید؛ این مسیر نیازمند پیکربندی SMTP است تا دعوتشونده بتواند لینک خود را دریافت کند.
گام 5، دسترسی به /admin
به https://vault.example.com/admin بروید و توکن ادمین متنی (رشته تصادفی یا رمز عبوری که هش کردهاید، نه خودِ هش) را وارد کنید. در این بخش میتوانید کاربران را لیست کنید، تنظیمات را تغییر دهید، ایمیل تست بفرستید و از دیتابیس snapshot بگیرید.
اگر صفحه به جای آن The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it را نشان میدهد، یعنی ADMIN_TOKEN خالی یا تنظیمنشده است که باعث غیرفعال شدن کامل پنل میشود؛ اگر هرگز به آن نیاز ندارید، این خود یک انتخاب معتبر است. اگر صفحه بارگذاری میشود اما توکن شما را رد میکند، به تلهٔ escaping در $$ در لیست خطاهای زیر مراجعه کنید. توکن را فراموش کردهاید؟ هیچ گزینه بازیابی وجود ندارد؛ .env یا فایل Compose را ویرایش کنید، یک توکن جدید قرار دهید و docker compose up -d را اجرا کنید.
گام 6، اتصال کلاینتهای Bitwarden
تمام کلاینتهای رسمی میتوانند به یک سرور self-hosted متصل شوند؛ بنابراین کلاینت دسکتاپ، موبایل یا مرورگر Bitwarden را از فروشگاههای استاندارد نصب کنید. شما به هیچ نسخهٔ خاصی از Vaultwarden نیاز ندارید.
پیش از ورود، روی آیکون چرخدنده در صفحهٔ ورود کلیک کنید (که با عنوان Self-hosted یا Region → Self-hosted مشخص شده است)، مقدار Server URL را روی https://vault.example.com تنظیم کرده و ذخیره کنید. سپس با ایمیل و رمز عبور اصلی (master password) که ثبت کردهاید وارد شوید؛ کلاینت باید بلافاصله متصل شده و پیشنهاد پر کردن و ذخیرهٔ اطلاعات کاربری را ارائه دهد.
اگر کلاینت خطای This is not a recognized Bitwarden server. You may need to check with your provider or update your server. را نشان داد، یعنی آدرس URL اشتباه است، از پروتکل http استفاده شده یا گواهی امنیتی معتبر نیست. ابتدا بررسی کنید که https://vault.example.com در مرورگر بدون مشکل بارگذاری میشود. تأخیر در بهروزرسانی سایر دستگاهها مربوط به WebSocket push است که در ادامه به آن پرداخته میشود.
گام 7، ایجاد یک jail در Fail2ban برای endpoint ورود
Vaultwarden تمام تلاشهای ناموفق برای ورود را در فایلی که توسط LOG_FILE تعیین شده است ثبت میکند؛ این دقیقاً همان چیزی است که برای مقابله با حملات brute-force نیاز داریم. اگر در حال حاضر از Fail2ban استفاده نمیکنید، مراحل نصب و تنظیمات پایه آن در راهنمای ایمنسازی SSH با Fail2ban آمده است؛ در اینجا یک jail اختصاصی برای vault اضافه میکنیم.
ابتدا مسیر volume نامگذاریشده را روی میزبان پیدا کنید تا Fail2ban بتواند لاگ را بخواند:
docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}'این دستور خروجی مشابه /var/lib/docker/volumes/vaultwarden_vw-data/_data چاپ میکند؛ فایل لاگ در مسیر vaultwarden.log قرار دارد. فیلتر را ایجاد کنید:
# /etc/fail2ban/filter.d/vaultwarden.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =و سپس jail را بسازید:
# /etc/fail2ban/jail.d/vaultwarden.local
[vaultwarden]
enabled = true
filter = vaultwarden
logpath = /var/lib/docker/volumes/vaultwarden_vw-data/_data/vaultwarden.log
banaction = iptables-allports
chain = DOCKER-USER
maxretry = 5
findtime = 600
bantime = 3600با دستور sudo systemctl restart fail2ban تنظیمات را reload کرده و با sudo fail2ban-client status vaultwarden وضعیت را تأیید کنید.
سه نکته در Docker تعیین میکند که آیا این محافظت کارآمد است یا خیر. اول، اگر لاگها در هر تلاش ناموفق، آدرس IP: 127.0.0.1 یا آدرس proxy شما را نشان میدهند، یعنی Vaultwarden در حال مسدود کردن proxy است. در این صورت IP_HEADER را روی هِدری تنظیم کنید که proxy شما واقعاً ارسال میکند (X-Forwarded-For برای Traefik، X-Real-IP برای بلاک nginx در بالا، و CF-Connecting-IP اگر پشت Cloudflare هستید). از نسخه 1.37.4 به بعد، با استفاده از X-Forwarded-For، برنامه Vaultwarden آخرین آدرسی را که در IP_HEADER_TRUSTED_PROXIES (پیشفرض local که شامل proxy روی همان میزبان یا شبکه Docker است) نباشد، به عنوان آدرس واقعی میپذیرد. بنابراین اگر یک CDN جلوی proxy شما قرار دارد، آدرسهای آن را نیز در این لیست بگنجانید. دوم، زنجیره (chain) مناسب در iptables به proxy شما بستگی دارد: اگر Traefik به عنوان یک container با پورتهای منتشرشده اجرا میشود، ترافیک از مسیر FORWARD در Docker عبور میکند، بنابراین ban باید طبق دستور بالا در DOCKER-USER قرار گیرد. اما اگر گزینه host-nginx را از گام 1 انتخاب کردهاید، اتصالات در زنجیره INPUT روی میزبان خاتمه مییابند و یک ban در DOCKER-USER آنها را نمیبیند؛ در این حالت خط chain = DOCKER-USER را حذف کنید تا Fail2ban از زنجیره پیشفرض INPUT استفاده کند. سوم، به جای پیشفرضِ مبتنی بر پورت، از banaction = iptables-allports استفاده کنید. این jail هیچ پورتی را تعریف نمیکند و یک ban برای تمام پورتها در DOCKER-USER، مهاجم را به طور کامل از تمام سرویسهای منتشرشده روی آن ماشین مسدود میکند.
گام 8، تهیه نسخه پشتیبان از vault و سپس بازیابی واقعی آن
حجم vw-data همان مدیریت رمز عبور شماست. این حجم شامل db.sqlite3 (تمام ورودیها)، دایرکتوریهای attachments/ و sends/، فایلهای rsa_key.* که نشستهای ورود را امضا میکنند و config.json از پنل مدیریت است. نسخهای که هر یک از این موارد را نادیده بگیرد، در زمان نیاز کارایی نخواهد داشت.
کپی کردن db.sqlite3 در حالی که Vaultwarden در حال نوشتن است، ممکن است منجر به ثبت یک فایل ناقص و خراب شود؛ بنابراین یک snapshot سرد بگیرید، زمان از دسترس خارج شدن سرویس تنها چند ثانیه است:
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F)
DEST=/root/vw-backups
VOL=$(docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}')
mkdir -p "$DEST"
docker compose -f /opt/vaultwarden/docker-compose.yml stop vaultwarden
tar czf "$DEST/vw-$STAMP.tgz" -C "$VOL" .
docker compose -f /opt/vaultwarden/docker-compose.yml start vaultwardenاین دستور را شبانه از طریق cron اجرا کنید و .tgz را به خارج از سرور منتقل کنید؛ نسخهای که فقط روی همان سروری باشد که از آن محافظت میکنید، نسخه پشتیبان محسوب نمیشود. روش تمیز برای انتقال آن، استفاده از restic برای پشتیبانگیری شبانه به سرور دیگر یا فضای ذخیرهسازی ابری است که آرشیو را رمزنگاری کرده و snapshotهای تکراری را برای شما deduplicate میکند. دکمه Backup Database در پنل مدیریت، یک snapshot سریع و کاربردی تنها از فایل SQLite است، اما فایلهای پیوست و کلیدها را شامل نمیشود.
اکنون مراسمی که یک نسخه پشتیبان واقعی را از یک نسخه امیدوارانه جدا میکند انجام دهید؛ آن را یک بار بازیابی کنید و ثابت کنید که کار میکند:
mkdir -p /tmp/vw-restore
tar xzf /root/vw-backups/vw-2026-07-15.tgz -C /tmp/vw-restore
docker run --rm -p 127.0.0.1:8888:80 -v /tmp/vw-restore:/data vaultwarden/serverاز لپتاپ خود، با استفاده از ssh -L 8888:127.0.0.1:8888 you@your-vps یک تونل به آن بزنید و http://localhost:8888 (یا http://127.0.0.1:8888) را باز کنید. از آنجا که آدرسهای loopback به عنوان یک بستر امن در نظر گرفته میشوند، crypto.subtle در دسترس است و vault در اینجا روی http ساده رمزگشایی میشود؛ این تنها نوع آدرسی است که چنین اجازهای در آن داده شده است. با رمز عبور اصلی (master password) خود وارد شوید و تأیید کنید که ورودیهای شما موجود هستند: اگر چنین است، دیتابیس، کلیدهای RSA و رمز عبور اصلی شما همگی به درستی کار میکنند و میتوانید در عرض چند دقیقه آن را روی یک VPS تازه بازسازی کنید. کانتینر را با Ctrl-C متوقف کرده و /tmp/vw-restore را حذف کنید. این عادت استفاده از تونل را برای هر رابط کاربری مدیریتی دیگری روی سرور که نباید هرگز در معرض اینترنت باشد حفظ کنید؛ این همان روشی است که برای دسترسی به یک اسکنر امنیتی open-kritt خودمیزبان روی پورت 5173 نیز استفاده خواهید کرد.
حالتهای شکست و پیامهای مربوطه
Cannot read properties of undefined (reading 'importKey') در کنسول مرورگر. والت از طریق http بارگذاری شده است، بنابراین crypto.subtle تعریفنشده است؛ فقط از طریق https:// به آن دسترسی پیدا کنید و تغییر مسیر HTTP به HTTPS را در پروکسی تنظیم کنید.
This is not a recognized Bitwarden server... در کلاینت. آدرس Server URL از نوع http است، اشتباه تایپ شده یا گواهی مورد اعتماد نیست؛ تأیید کنید که https://vault.example.com یک قفل معتبر نشان میدهد، سپس آن را مجدداً در تنظیمات self-hosted کلاینت وارد کنید.
/admin رمز عبور صحیح را رد میکند. هش Argon2 اسکیپ (escaping) خود را از دست داده است، هر $ در فایل Compose باید به صورت $$ باشد (اما در داخل کوتیشنهای تکی در .env باید به صورت $ باشد)، یا اینکه شما به جای متن اصلی (plaintext)، هش را وارد کردهاید.
همگامسازی کند بین دستگاهها؛ کنسول WebSocket connection to 'wss://vault.example.com/notifications/hub' failed را نشان میدهد. پروکسی هدرهای Upgrade/Connection را فوروارد نمیکند؛ Traefik این کار را بهطور خودکار انجام میدهد، اما nginx به دو خط upgrade از مرحله 1 نیاز دارد. والت همچنان کار میکند، اما همگامسازی فقط هنگام باز کردن برنامه انجام میشود. پورت اختصاصی قدیمی 3012 از نسخه v1.31.0 حذف شده است، بنابراین نیازی به مسیر WebSocket جداگانه نیست.
Fail2ban گزارش مسدودسازی میدهد اما مهاجم همچنان متصل میشود. این ابزار در حال مسدود کردن 127.0.0.1 است زیرا IP_HEADER اشتباه است، یا مسدودسازی در زنجیره (chain) نادرستی از iptables قرار دارد؛ chain = DOCKER-USER و banaction = iptables-allports را تنظیم کنید.
ارتقا
ایمیج جدید را دریافت کرده و کانتینر را دوباره ایجاد کنید؛ volume نامگذاریشده و تمام دادههای شما باقی میمانند:
docker compose pull
docker compose up -dنرمافزار Vaultwarden نسخههای جدید را بهطور مکرر منتشر میکند. بهجای ثابت نگهداشتن نسخه (pinning)، یادداشتهای انتشار پروژه را دنبال کنید، زیرا برخی نسخهها شامل نکات مربوط به مهاجرت دادهها هستند. پیش از هر ارتقای عمده، یک نسخه پشتیبان جدید تهیه کنید؛ در صورت بروز مشکل، میتوانید با بازگردانی فایل tarball به یک volume جدید، به نسخه قبل بازگردید.
FAQ
آیا Vaultwarden همان Bitwarden است؟
این یک سرور مستقل و سازگار است، نه سرور رسمی. Vaultwarden پیادهسازی مجدد API سرور Bitwarden با زبان Rust است؛ بنابراین تمامی کلاینتهای رسمی دسکتاپ، موبایل، مرورگر و CLI با آن کار میکنند، در حالی که منابع بسیار کمتری نسبت به پشته رسمی مصرف میکند. فرمت vault یکسان است، بنابراین میتوانید با export و import کردن دادهها، در هر دو جهت مهاجرت کنید.
آیا واقعاً به HTTPS نیاز دارم یا میتوانم آن را روی http در شبکه محلی (LAN) اجرا کنم؟
برای هر کاری بهجز تست loopback، به HTTPS نیاز دارید. وبولت و افزونههای Bitwarden از Web Crypto API مرورگر استفاده میکنند که فقط در بستر امن در دسترس است؛ بنابراین روی http معمولی، کلاینت خطای Cannot read properties of undefined را نمایش میدهد و هرگز وارد نمیشود. تنها آدرسهای http که کار میکنند، آدرسهای loopback مانند http://localhost یا http://127.0.0.1 هستند؛ به همین دلیل است که تست بازیابی در مرحله 8 از تونل SSH استفاده میکند.
چگونه از ثبتنام افراد غریبه در سرورم جلوگیری کنم؟
پس از ایجاد حساب کاربری خود، بلافاصله SIGNUPS_ALLOWED: "false" را در فایل Compose تنظیم کرده و docker compose up -d را اجرا کنید. از آن پس، افراد جدید را از طریق دکمه Invite User در /admin اضافه کنید که نیازمند پیکربندی SMTP است تا لینک دعوت را دریافت کنند. گهگاه لیست کاربران مدیر را بررسی کنید تا مطمئن شوید حساب غیرمنتظرهای ایجاد نشده است.
چگونه از vault مربوط به Vaultwarden نسخه پشتیبان تهیه کنم؟
کانتینر را برای مدت کوتاهی متوقف کنید و کل volume مربوط به vw-data، یعنی db.sqlite3، attachments/، sends/، config.json و فایلهای rsa_key.* را آرشیو کنید، سپس آرشیو را از سرور خارج کنید؛ ایدهآل این است که این کار را با یک cron شبانه انجام دهید. کپی کردن فایل زنده SQLite در حین اجرای سرور، ریسک خرابی snapshot را به همراه دارد، بنابراین پشتیبانگیری را در حالت سرد (cold) انجام دهید. مهمتر از همه، یکبار آن را در یک کانتینر موقت بازیابی کرده و وارد شوید تا مطمئن شوید پشتیبان واقعی است و پیش از آنکه به آن وابسته شوید، از صحت آن اطمینان حاصل کنید.
آیا میزبانی شخصی رمزهای عبور واقعاً امن است؟
بله، اگر سه موردی که در این راهنما پوشش داده شده است را رعایت کنید: HTTPS واقعی، بستن ثبتنامها به همراه یک توکن مدیریتی قوی، و پشتیبانگیریهای تستشده. vault شما در سمت کلاینت با رمز عبور اصلی (master password) رمزنگاری میشود، بنابراین حتی سرور هم رمزهای عبور شما را به صورت متن ساده نمیبیند و یک db.sqlite3 سرقتشده نیز بدون آن رمز عبور، ورودیهای شما را فاش نمیکند. با این حال، سرور همچنان ایمیلهای حساب و یک هش salted مشتقشده از هر رمز عبور اصلی را نگه میدارد که مهاجم میتواند سعی کند آن را به صورت آفلاین کرک کند؛ بنابراین از فایل دیتابیس و تمام کپیهای آن محافظت کنید. معامله این است که اکنون وصلهکردن و پشتیبانگیری بر عهده شماست، به همین دلیل است که Fail2ban و آیین بازیابی در اینجا اختیاری نیستند. هنگامی که این موارد برقرار شدند، نگاهی دقیقتر به نقاطی که یک vault میزبانیشده میتواند مورد حمله قرار گیرد گام بعدی مفید است، زیرا با رمزنگاری ورودیها در سمت کلاینت، آنچه برای دفاع باقی میماند، توکن مدیریتی و آرشیو پشتیبان است.