SSD Nodes Learn
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-07-24

نصب Vaultwarden روی VPS با Docker

راهنمای کامل خود-میزبانی Vaultwarden روی VPS با استفاده از Docker. تنظیمات HTTPS، مدیریت Admin Token و روش‌های تست Backup برای امنیت کامل رمزهای عبور.

آنچه در حال ساخت آن هستید

یک مدیریت رمز عبور تحت مالکیت کامل شما: Vaultwarden که در یک container کوچک و پشت یک reverse proxy (که HTTPS را مدیریت می‌کند) اجرا می‌شود، و اپلیکیشن‌های رسمی Bitwarden روی گوشی، لپ‌تاپ و مرورگر شما به آن متصل می‌شوند. Vaultwarden رابط برنامه‌نویسی (API) سرور Bitwarden را در زبان Rust بازنویسی کرده و از همان پروتکل bitwarden.com استفاده می‌کند؛ بنابراین تمام کلاینت‌های رسمی بدون تغییر با آن کار می‌کنند — اما به جای استفاده از پشته (stack) رسمی و چندین container، تنها حدود 100 MB از RAM را اشغال می‌کند.

فرآیند نصب تنها شامل حدود 12 خط دستور Compose است. سه نکته حیاتی که اهمیت دارند و باعث بروز خطا می‌شوند، این موارد هستند: پروتکل TLS باید قبل از باز کردن web vault فعال باشد، قابلیت ثبت‌نام عمومی (public signups) باید بلافاصله پس از ایجاد حساب کاربری شخصی شما بسته شود، و Volume مربوط به داده‌ها باید پشتیبان‌گیری و بازگردانی (restore) آن تست شود، زیرا تمام رمزهای عبور شما در آن یک دایرکتوری ذخیره شده است.

پیش‌نیازها و نکات چالش‌برانگیز

  • یک VPS با Docker Engine و plugin Compose، روی یک سیستم تازه نصب شده Ubuntu 24.04 KVM با دسترسی root یا sudo. مقدار 512 MB از RAM واقعاً کافی است؛ 1 GB راحت‌تر خواهد بود. این یکی از سبک‌ترین مواردی است که می‌توانید اجرا کنید — این سرویس در صدر لیست سرویس‌های ارزش‌محور برای self-hosting قرار دارد.
  • یک دامنه با یک A record (و AAAA اگر IPv6 دارید) که به vault.example.com در VPS اشاره می‌کند. گواهی TLS دقیقاً برای همین نام صادر می‌شود، بنابراین DNS باید قبل از شروع، نام را Resolve کند.
  • پورت‌های 80 و 443 برای اینترنت باز باشند و توسط reverse proxy شما مدیریت شوند — هرگز مستقیماً توسط Vaultwarden. پورت 80 فقط برای ACME certificate challenge و انتقال (redirect) از HTTP به HTTPS استفاده می‌شود.
  • بزرگترین چالش اولیه: کلاینت‌های Bitwarden از برقراری ارتباط با سروری که HTTPS نیست، خودداری می‌کنند. امکان "ابتدا تست با http" وجود ندارد — این مسیر به دلیل مشخصی که در ادامه بررسی می‌شود، کار نمی‌کند.

چرا Vaultwarden، نه پشته رسمی Bitwarden

کلاینت‌های یکسان، با حجم بسیار کمتر. نسخه self-hosted رسمی Bitwarden به صورت مجموعه‌ای از کانتینرها (MSSQL, Nginx, Identity, Api, Admin و غیره) عرضه می‌شود و به حدود 2 GB RAM نیاز دارد. Vaultwarden یک binary واحد است که به صورت پیش‌فرض همه چیز را در یک database از نوع SQLite ذخیره می‌کند و در حالت idle تنها چند ده مگابایت از حافظه را اشغال می‌کند. برای یک فرد، یک خانواده یا یک تیم کوچک، این یک انتخاب بدیهی است؛ و از آنجایی که این پروژه API مربوط به Bitwarden را با دقت پیاده‌سازی کرده است، داده‌های شما بین این نسخه و bitwarden.com قابل انتقال هستند.

آنچه از دست می‌دهید، بیشتر قابلیت‌های سطح Enterprise است: قابلیت SCIM provisioning وجود ندارد (هرچند قابلیت آزمایشی OpenID Connect SSO در نسخه 1.35.0 اضافه شد)، و از آنجایی که شما مدیر سیستم هستید، وظایف patching، HTTPS و تهیه backup بر عهده شماست. این راهنما شامل این 3 وظیفه است.

چرا HTTPS اختیاری نیست

Bitwarden web vault و افزونه‌های مرورگر، کلیدهای رمزنگاری شما را با استفاده از Web Crypto API (window.crypto.subtle) در مرورگر استخراج می‌کنند. مرورگرها crypto.subtle را فقط در یک secure context ارائه می‌دهند؛ یعنی HTTPS یا حالت خاص http://localhost. بر روی پروتکل plain http://vault.example.com، این قابلیت undefined است؛ بنابراین به محض اینکه اپلیکیشن اقدام به استخراج کلید می‌کند، با خطا مواجه می‌شود و کنسول این پیام را نمایش می‌دهد:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'importKey')

صفحه متوقف می‌شود یا یک خطای عمومی crypto نمایش داده می‌شود و هیچ کاربرانی وارد حساب نمی‌شوند. کلاینت‌های desktop، mobile و browser، بررسی‌های خود را روی 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 را راه‌اندازی کنید و هرگز vault را از طریق http باز نکنید، حتی برای یک بررسی سریع.

Step 1 — DNS and the reverse proxy (TLS first)

رکورد را به VPS خود متصل کنید و مطمئن شوید که به آدرس صحیح اشاره می‌کند:

dig +short vault.example.com

خروجی این دستور باید IP مربوط به VPS شما باشد. اگر خروجی خالی یا اشتباه بود، تنظیمات DNS را اصلاح کنید و منتظر اتمام TTL بمانید؛ صدور گواهینامه برای نامی که Resolve نمی‌شود، با شکست مواجه می‌شود.

برای بخش front end پروتکل HTTPS، این راهنما از Traefik استفاده می‌کند. Traefik گواهینامه‌های Let's Encrypt را به صورت خودکار صادر و تمدید می‌کند و مستقیماً با Compose سازگار است. اگر هنوز از آن استفاده نمی‌کنید، ابتدا راهنمای راه‌اندازی Traefik reverse proxy و TLS خودکار را دنبال کنید؛ این فرآیند یک Docker network خارجی (proxy در ادامه) و یک ACME resolver (letsencrypt) ایجاد می‌کند که سرویس Vaultwarden به آن متصل می‌شود. استفاده از nginx ساده با گواهینامه‌ای که دستی صادر شده است، از سمت Vaultwarden دقیقاً به همان صورت عمل می‌کند.

استفاده از nginx و Certbot به جای Traefik را ترجیح می‌دهید؟ Vaultwarden را روی 127.0.0.1:8080 قرار دهید (ports: ["127.0.0.1:8080:80"] را به سرویس اضافه کنید و Traefik labels را حذف کنید)، سپس یک گواهینامه صادر کرده و درخواست‌ها را به آن 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، کاملاً یکسان هستند.

Step 2 — the Compose file

ابتدا دایرکتوری پروژه را ایجاد کنید. این راهنما از /opt/vaultwarden استفاده می‌کند که باعث می‌شود نام پروژه Compose — و در نتیجه volume داده، یعنی vaultwarden_vw-data — قابل پیش‌بینی باشد؛ مراحل Fail2ban و backup که در ادامه می‌آیند به همین نام دقیق وابسته هستند.

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 باید URL کامل و عمومی HTTPS باشد: این مقدار در لینک‌های پیوست، WebAuthn 2FA و endpoint اعلان‌ها (notifications) تعبیه شده است، بنابراین مقدار اشتباه یا http باعث از کار افتادن آن‌ها می‌شود، حتی اگر سایت لود شود. تگ latest یک استثنای عمدی برای قانون معمولِ never-latest است — Vaultwarden نسخه‌های پایدار خود را به صورت یک image واحد ارائه می‌دهد و :testing کانال جداگانه برای نسخه‌های pre-release است — بنابراین آگاهانه آپدیت کنید و قبل از pull کردن، release notes را مرور کنید.

خدمات را اجرا کنید و لاگ را بررسی کنید:

docker compose up -d
docker compose logs -f vaultwarden

یک شروع صحیح با خطی شبیه به Rocket has launched from http://0.0.0.0:80 تمام می‌شود. چند ثانیه به Traefik زمان دهید تا گواهینامه (certificate) را دریافت کند، سپس https://vault.example.com را بارگذاری کنید — شما باید Bitwarden web vault را با یک قفل معتبر و بدون هشدار certificate مشاهده کنید.

Step 3 — یک ADMIN_TOKEN قوی و تله $$

ADMIN_TOKEN از /admin محافظت می‌کند؛ پنلی که می‌تواند تمام کاربران و تنظیمات instance شما را بخواند، بنابراین با آن مانند یک رمز عبور root رفتار کنید. دو روش وجود دارد.

روش ساده، همان رشته تصادفی است که قبلاً با openssl rand -base64 48 ایجاد کردید. از آنجایی که base64 هرگز شامل $ نیست، بدون نیاز به escaping مستقیماً در .env قرار می‌گیرد.

روش امن، یک Argon2 PHC hash است، بنابراین توکن به صورت متن ساده (plaintext) هرگز روی دیسک ذخیره نمی‌شود. یکی از آن‌ها را با استفاده از همان image ایجاد کنید:

docker run --rm -it vaultwarden/server /vaultwarden hash --preset owasp

این دستور دو بار از شما ورودی می‌گیرد و رشته‌ای را چاپ می‌کند که با $argon2id$v=19$... شروع می‌شود. در اینجا تله‌ای وجود دارد که باعث هدر رفتن یک ساعت زمان کاربران می‌شود: Docker Compose با $ به عنوان variable interpolation برخورد می‌کند، بنابراین هنگام چسباندن (paste) hash در فایل Compose، باید هر $ را به $$ تبدیل کنید. آن را مستقیماً زیر environment: قرار دهید، نه از طریق .env، و آن را داخل کوتیشن قرار ندهید:

    environment:
      ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$c29tZXNhbHQ$$RdescudvJCsgt3ub+b+dWRWJTmaaJObG

اگر علامت‌های تک $ را باقی بگذارید، Compose هشدار The "argon2id" variable is not set می‌دهد و توکن را خالی می‌کند، و سپس /admin رمز عبور صحیح شما را رد می‌کند. دستور docker compose up -d را اجرا کنید و متن ساده‌ای را که در هنگام prompt تایپ کردید، در مدیریت رمز عبور خود نگه دارید.

Step 4 — ثبت حساب کاربری و سپس بستن دسترسی‌ها

با استفاده از SIGNUPS_ALLOWED: "true"، فایل https://vault.example.com را باز کنید، روی Create account کلیک کنید و با استفاده از ایمیل و یک master password قوی، ثبت‌نام کنید. این master password هرگز قابل بازیابی نیست — امکان بازنشانی وجود ندارد — بنابراین ابتدا آن را در جایی امن ذخیره کنید.

حالا دسترسی‌ها را ببندید. فایل Compose را ویرایش کنید تا قابلیت signups غیرفعال شود:

      SIGNUPS_ALLOWED: "false"

با استفاده از docker compose up -d، تغییرات را اعمال کنید. این مرحله برای امنیت (hardening) ضروری است و نباید نادیده گرفته شود. اگر این قابلیت باز بماند، هر کسی که URL را پیدا کند — و botهای جستجوگر حتماً آن را پیدا می‌کنند — می‌تواند در سرور شما حساب کاربری بسازد. آن‌ها نمی‌توانند محتویات vault شما را بخوانند، اما منابع سرور را مصرف کرده و instance خصوصی شما را به یک سرویس عمومی تبدیل می‌کنند. نشانه‌ی باز ماندن این قابلیت: لیست /admin شامل حساب‌هایی است که شما هرگز نساخته‌اید.

برای اضافه کردن اعضای خانواده یا هم‌تیمی‌ها در آینده، بدون باز کردن مجدد قابلیت public signups، از دکمه Invite User در /admin استفاده کنید؛ این مسیر نیاز به تنظیمات SMTP دارد تا دعوت‌کننده لینک خود را دریافت کند.

Step 5 — reaching /admin

به مسیر https://vault.example.com/admin بروید و admin token را به صورت plaintext وارد کنید (رشته تصادفی یا پسوردی که هش کرده‌اید — نه خودِ hash را). در این بخش می‌توانید کاربران را لیست کنید، تنظیمات را تغییر دهید، یک ایمیل آزمایشی ارسال کنید و از پایگاه داده snapshot بگیرید.

اگر صفحه 404 Not Found را برگرداند، یعنی ADMIN_TOKEN خالی یا تنظیم نشده است که باعث غیرفعال شدن کامل پنل می‌شود؛ اگر هرگز به آن نیاز ندارید، این یک انتخاب منطقی است. اگر صفحه بارگذاری شد اما توکن شما را رد کرد، به بخش $$ در لیست خطاها مراجعه کنید. توکن را فراموش کرده‌اید؟ امکان بازیابی وجود ندارد؛ فایل .env یا Compose file را ویرایش کنید، یک توکن جدید تنظیم کنید و docker compose up -d.

Step 6 — اتصال به کلاینت‌های Bitwarden

تمام کلاینت‌های رسمی می‌توانند به یک سرور Self-hosted متصل شوند. بنابراین، کلاینت‌های Bitwarden برای دسکتاپ، موبایل یا مرورگر را از فروشگاه‌های معمولی نصب کنید؛ شما نیازی به نسخه خاصی از Vaultwarden ندارید.

پیش از ورود، روی آیکون تنظیمات (gear) در صفحه ورود کلیک کنید (با برچسب 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 استفاده شده، یا گواهی (certificate) مورد اعتماد نیست؛ ابتدا بررسی کنید که آیا https://vault.example.com در یک مرورگر بدون مشکل باز می‌شود یا خیر. تأخیر در به‌روزرسانی‌ها در سایر دستگاه‌ها به دلیل WebSocket push است که در ادامه بررسی می‌شود.

Step 7 — ایجاد یک jail در Fail2ban برای endpoint ورود

Vaultwarden تمام تلاش‌های ناموفق برای ورود را در فایلی که توسط LOG_FILE تعیین شده ثبت می‌کند؛ این دقیقاً همان چیزی است که یک محافظ در برابر brute-force نیاز دارد. اگر هنوز Fail2ban را نصب نکرده‌اید، مراحل نصب و اصول اولیه در راهنمای ایمن‌سازی SSH با Fail2ban آمده است؛ در اینجا ما یک jail برای vault اضافه می‌کنیم.

ابتدا محل قرارگیری named volume را در host پیدا کنید تا Fail2ban بتواند log را بخواند:

docker volume inspect vaultwarden_vw-data --format '{{ .Mountpoint }}'

خروجی چیزی شبیه به /var/lib/docker/volumes/vaultwarden_vw-data/_data خواهد بود؛ فایل log در داخل آن در مسیر 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 تنظیمات را بازنشانی و با sudo fail2ban-client status vaultwarden تایید کنید.

سه جزئیات Docker تعیین می‌کنند که آیا این تنظیمات محافظتی ایجاد می‌کند یا خیر. اول، اگر در هر تلاش ناموفق، log آدرس IP: 127.0.0.1 یا آدرس proxy شما را نشان دهد، Vaultwarden در حال ban کردن proxy است؛ مقدار IP_HEADER را برابر با header واقعی proxy خود قرار دهید (برای Traefik مقدار X-Forwarded-For، برای nginx ذکر شده در بالا مقدار X-Real-IP، و برای پشت Cloudflare مقدار CF-Connecting-IP). دوم، انتخاب iptables chain مناسب به proxy شما بستگی دارد: اگر Traefik را به صورت یک container با پورت‌های منتشر شده اجرا می‌کنید، ترافیک از مسیر FORWARD در Docker عبور می‌کند، بنابراین ban باید مطابق آنچه در بالا آمد، در DOCKER-USER قرار بگیرد؛ اما اگر در Step 1 گزینه host-nginx را انتخاب کردید، اتصالات در chain مربوط به nginx روی host در مسیر INPUT پایان می‌یابند و یک ban در DOCKER-USER هرگز آن‌ها را نمی‌بیند — در این صورت خط chain = DOCKER-USER را حذف کنید تا Fail2ban از chain پیش‌فرض INPUT استفاده کند. سوم، به جای پیش‌فرضِ مبتنی بر port، از banaction = iptables-allports استفاده کنید — این jail هیچ پورتی را تعریف نمی‌کند و یک ban برای تمام پورت‌ها در DOCKER-USER، مهاجم را به شکلی تمیز از تمام سرویس‌های منتشر شده روی سیستم مسدود می‌کند.

Step 8 — از vault نسخه پشتیبان تهیه کنید، سپس آن را بازیابی کنید

حجم vw-data همان مدیریت‌کننده رمز عبور شما است. این حجم شامل db.sqlite3 (تمام ورودی‌ها)، دایرکتوری‌های attachments/ و sends/، فایل‌های rsa_key.* برای امضای نشست‌های ورود، و config.json از پنل مدیریت است. اگر در نسخه پشتیبان از هر یک از این موارد چشم‌پوشی شود، هنگام نیاز به بازیابی، عملیات با شکست مواجه خواهد شد.

کپی کردن db.sqlite3 در حالی که Vaultwarden در حال نوشتن است، می‌تواند منجر به ذخیره یک فایل ناقص و خراب شود؛ بنابراین یک snapshot خام (cold 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 برای تهیه نسخه پشتیبان شبانه در یک سرور دیگر یا object storage است که آرشیو را رمزگذاری کرده و اسنپ‌شات‌های تکراری را برای شما deduplicate می‌کند. دکمه Backup Database در پنل مدیریت، یک اسنپ‌شات سریع و کاربردی از فایل SQLite است، اما پیوست‌ها (attachments) و کلیدها را شامل نمی‌شود.

حالا نوبت به مرحله‌ای می‌رسد که یک نسخه پشتیبان واقعی را از یک نسخه پشتیبان احتمالی متمایز می‌کند — یک بار آن را بازیابی کنید تا کارکرد آن را اثبات کنید:

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 به سرور متصل شوید (tunnel) و http://localhost:8888 را باز کنید. از آنجایی که localhost یک context امن است، crypto.subtle در دسترس است و vault در اینجا بر روی پروتکل plain http رمزگشایی می‌شود — این تنها مکانی است که اجازه این کار را دارد. با رمز عبور اصلی (master password) وارد شوید و حضور ورودی‌ها را تایید کنید: اگر ورودی‌ها موجود بودند، یعنی پایگاه داده، کلیدهای RSA و رمز عبور اصلی شما همگی با موفقیت منتقل شده‌اند و می‌توانید در عرض چند دقیقه، سیستم را روی یک VPS جدید بازسازی کنید. با فشردن Ctrl-C کانتینر را متوقف کرده و /tmp/vw-restore را حذف کنید.

حالت‌های خطا و پیام‌هایی که مشاهده خواهید کرد

Cannot read properties of undefined (reading 'importKey') در کنسول مرورگر. Vault از طریق http بارگذاری شده است، بنابراین crypto.subtle تعریف نشده (undefined) است؛ فقط از طریق https:// به آن دسترسی داشته باشید و Redirect از HTTP به HTTPS را در Proxy تنظیم کنید.

This is not a recognized Bitwarden server... در کلاینت. URL سرور با http است، اشتباه تایپ شده، یا گواهی (certificate) مورد اعتماد نیست؛ بررسی کنید که آیا https://vault.example.com آیکون قفل معتبر را نشان می‌دهد یا خیر، سپس آن را در تنظیمات self-hosted کلاینت مجدداً وارد کنید.

/admin رمز عبور صحیح را رد می‌کند. هش Argon2 کاراکترهای Escape خود را از دست داده است — هر $ باید در Compose به صورت $$ باشد — یا شما به جای متن ساده، خودِ هش را وارد کرده‌اید.

همگام‌سازی (Sync) کند بین دستگاه‌ها؛ کنسول WebSocket connection to 'wss://vault.example.com/notifications/hub' failed را نشان می‌دهد. پروکسی در حال ارسال هدرهای Upgrade/Connection نیست؛ Traefik این کار را به صورت خودکار انجام می‌دهد، اما nginx به دو خط upgrade از Step 1 نیاز دارد. Vault همچنان کار می‌کند، اما همگام‌سازی فقط هنگام باز شدن انجام می‌شود. پورت اختصاصی قدیمی 3012 از نسخه v1.31.0 حذف شده است، بنابراین نیازی به مسیر WebSocket جداگانه نیست.

Fail2ban گزارش Ban می‌دهد اما مهاجم همچنان متصل می‌شود. سیستم در حال Ban کردن 127.0.0.1 است زیرا IP_HEADER اشتباه است، یا Ban در زنجیره (chain) اشتباه iptables قرار دارد — مقادیر chain = DOCKER-USER و banaction = iptables-allports را تنظیم کنید.

Upgrades

Image جدید را Pull کرده و آن را recreate کنید؛ volume نام‌گذاری شده و تمام داده‌های شما حفظ می‌شوند:

docker compose pull
docker compose up -d

Vaultwarden نسخه‌های جدید را به طور مکرر منتشر می‌کند. به جای ثابت نگه داشتن یک patch version، release notes پروژه را دنبال کنید، زیرا برخی از نسخه‌ها شامل نکات مربوط به migration هستند. قبل از هرگونه تغییر نسخه اصلی (major bump)، یک backup تازه تهیه کنید؛ شما می‌توانید با restore کردن فایل tarball در یک volume جدید، به حالت قبل بازگردید.

FAQ

آیا Vaultwarden همان Bitwarden است؟

این یک سرور مستقل و سازگار است، نه نسخه رسمی. Vaultwarden API سرور Bitwarden را در زبان Rust بازنویسی کرده است؛ بنابراین تمام کلاینت‌های رسمی (Desktop، Mobile، Browser و CLI) با آن کار می‌کنند، در حالی که بخش بسیار کوچکی از منابع سیستم را مصرف می‌کنند. فرمت Vault یکسان است، بنابراین می‌توانید با استفاده از قابلیت Export و Import، داده‌ها را به هر دو جهت انتقال دهید.

آیا واقعاً به HTTPS نیاز دارم، یا می‌توانم آن را در شبکه LAN با پروتکل http اجرا کنم؟

به جز برای تست‌های localhost، حتماً به HTTPS نیاز دارید. Web Vault و افزونه‌های Bitwarden از Web Crypto API مرورگر استفاده می‌کنند که فقط در یک context امن در دسترس است؛ بنابراین در حالت http معمولی، کلاینت خطای Cannot read properties of undefined می‌دهد و هرگز وارد حساب نمی‌شود. تنها آدرس http که کار می‌کند http://localhost است، به همین دلیل در مرحله 8، تست بازیابی (restore) از یک SSH tunnel استفاده می‌کند.

چگونه از ثبت‌نام افراد غریبه در سرورم جلوگیری کنم؟

بلافاصله پس از ساخت حساب کاربری خود، مقدار SIGNUPS_ALLOWED: "false" را در فایل Compose تنظیم کرده و docker compose up -d را اجرا کنید. از آن زمان به بعد، افراد جدید را از طریق دکمه Invite User در /admin اضافه کنید؛ برای این کار باید SMTP تنظیم شده باشد تا کاربران لینک دعوت را دریافت کنند. لیست کاربران ادمین را هر از گاهی بررسی کنید تا مطمئن شوید حساب کاربری غیرمنتظره‌ای ایجاد نشده است.

چگونه از Vaultwarden خود بک‌آپ بگیرم؟

کانتینر را برای مدت کوتاهی متوقف کنید و کل volume مربوط به vw-data شامل فایل‌های db.sqlite3، attachments/، sends/، config.json و rsa_key.* را آرشیو کنید؛ سپس آرشیو را به خارج از سرور منتقل کنید (ترجیحاً با یک cron nightly). کپی کردن فایل زنده SQLite در حالی که سرور در حال اجراست، ریسک خراب شدن snapshot را دارد، پس حتماً در حالت آفلاین از آن کپی بگیرید. مهم‌تر از همه، یک بار آن را در یک کانتینر موقت بازیابی و وارد حساب شوید تا قبل از اعتماد به بک‌آپ، از سالم بودن آن مطمئن شوید.

آیا میزبانی شخصی (self-host) پسوردهای من واقعاً امن است؟

بله، اگر سه مورد زیر که در این راهنما آمده را رعایت کنید: HTTPS واقعی، غیرفعال کردن ثبت‌نام عمومی به همراه یک admin token قوی، و بک‌آپ‌های تست شده. Vault شما در سمت کلاینت با استفاده از رمز عبور اصلی (master password) رمزنگاری می‌شود، بنابراین حتی سرور هم هرگز پسوردهای شما را به صورت متن ساده (clear) نمی‌بیند؛ یک db.sqlite3 سرقت شده بدون آن رمز عبور بی‌ارزش است. در عوض، مسئولیت وصله کردن (patching) و بک‌آپ‌گیری بر عهده شماست، به همین دلیل استفاده از Fail2ban و انجام مراحل بازیابی در اینجا اختیاری نیست.

#vaultwarden#passwords#security#docker#self-hosting