SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor

क्या Vaultwarden सुरक्षित है? सुरक्षा जांच और सुझाव

Vaultwarden क्लाइंट-साइड एन्क्रिप्शन का उपयोग करता है लेकिन मेटाडेटा को प्लेनटेक्स्ट में रखता है। अपने एडमिन टोकन और बैकअप फ़ाइल को सुरक्षित रखकर डेटा चोरी के जोखिम को कम करें।

क्या Vaultwarden सुरक्षित है? संक्षिप्त उत्तर

Vaultwarden उस एक स्थान पर सुरक्षित है जो सबसे अधिक मायने रखता है, क्योंकि प्रत्येक vault item आपके डिवाइस पर सर्वर तक पहुँचने से पहले ही encrypt हो जाता है। सर्वर encrypted vault सामग्री को plaintext account metadata के साथ स्टोर करता है। यदि कोई पूरे database की copy भी कर ले, तो भी उसे सामग्री पढ़ने के लिए vault की encryption keys की आवश्यकता होगी, लेकिन उसे account email addresses और password hints तुरंत मिल जाएंगे।

यह उत्तर बहुत कुछ स्पष्ट करता है, और जो हिस्से विफल होते हैं वे वही हैं जिन्हें आप configure करते हैं। एक अनुमान लगाने योग्य token के पीछे छिपा admin panel। पूरी internet पर publish किया गया container port। एक plaintext config.json। उसी box पर home directory में पड़ा एक backup tarball। इनमें से कोई भी cryptography की समस्या नहीं है। ये सभी वे कारण हैं जिनकी वजह से self-hosted vaults खाली हो जाते हैं।

नीचे दी गई हर बात एक working install मानकर लिखी गई है। यदि आपके पास अभी तक यह नहीं है, तो पहले VPS के लिए Vaultwarden install guide का उपयोग करके इसे set up करें, फिर वापस आएं और इस सूची को क्रम से पूरा करें।

सर्वर वास्तव में क्या स्टोर करता है

Vaultwarden, Bitwarden के डेटा मॉडल को लागू करता है। किसी भी अनुरोध (request) को भेजने से पहले, क्लाइंट साइड पर एक रैंडम तरीके से जेनरेट की गई आइटम की (item key) का उपयोग करके वॉल्ट आइटम के नाम, यूजरनेम, पासवर्ड, नोट्स और URI को एन्क्रिप्ट किया जाता है। वह की (key) यूजर या ऑर्गनाइजेशन की सिमेट्रिक की द्वारा सुरक्षित रहती है; पासवर्ड से प्राप्त की (password-derived key) यूजर की सिमेट्रिक की को सुरक्षित रखती है। अटैचमेंट फ़ाइल की सामग्री एक अलग अटैचमेंट की का उपयोग करती है, जो आइटम की द्वारा सुरक्षित होती है। सर्वर को एक UUID (यूनिवर्सली यूनिक आइडेंटिफायर) के साथ ओपेक (opaque) डेटा प्राप्त होता है।

कुछ चीजें सिफरटेक्स्ट (ciphertext) नहीं होती हैं, और आपको पता होना चाहिए कि वे क्या हैं:

  • आपका अकाउंट ईमेल एड्रेस और मास्टर पासवर्ड हिंट, प्लेनटेक्स्ट में।
  • आपकी KDF (की डेरिवेशन फंक्शन) सेटिंग्स और साल्ट, क्योंकि अगली बार लॉगिन करते समय क्लाइंट को की को फिर से बनाने के लिए इनकी आवश्यकता होती है।
  • क्लाइंट द्वारा भेजे गए मास्टर पासवर्ड हैश का एक सर्वर-साइड हैश, जिसका उपयोग लॉगिन को प्रमाणित करने के लिए किया जाता है।
  • मेटाडेटा: ऑर्गनाइजेशन मेंबरशिप, डिवाइस के नाम, अंतिम लॉगिन का समय।
  • ऑथेंटिकेटर-आधारित टू-फैक्टर लॉगिन के लिए TOTP सीक्रेट। यह twofactor टेबल में बिना एन्क्रिप्ट किए रहता है, क्योंकि सर्वर को आपके द्वारा दिए गए कोड से तुलना करने के लिए अपेक्षित कोड की गणना करनी पड़ती है। यह उस TOTP (टाइम-बेस्ड वन-टाइम पासवर्ड) सीक्रेट से अलग है जिसे आप वॉल्ट आइटम के अंदर स्टोर करते हैं, जो अन्य सभी फील्ड्स की तरह एन्क्रिप्टेड होता है।

डेटा फोल्डर छोटा होता है। Docker इंस्टॉलेशन पर, यह वह है जिसे आपने /data पर माउंट किया है।

sudo ls -l /vw-data/

db.sqlite3 में लगभग पूरी स्टेट (state) रहती है। attachments/ में डेटाबेस टेबल के बाहर, UUID डायरेक्टरी के तहत अपलोड की गई फाइलें रहती हैं। sends/ में Send अटैचमेंट्स रहते हैं और यह अस्थायी होते हैं। icon_cache/ को हटाया जा सकता है। rsa_key.pem और इसके साथी लॉग-इन यूजर्स के JWTs (JSON वेब टोकन) को साइन करते हैं, इसलिए उस प्राइवेट की की एक कॉपी का उपयोग वॉल्ट लॉगिन सेशन को फोर्ज (forge) करने के लिए किया जा सकता है। config.json एडमिन पेज के माध्यम से सेव की गई सेटिंग्स को स्टोर करता है, जिसमें प्लेनटेक्स्ट में SMTP क्रेडेंशियल्स और कॉन्फ़िगर किया गया एडमिन टोकन वैल्यू शामिल है। नीचे दिए गए Argon2 निर्देशों का पालन करने से प्लेनटेक्स्ट पासवर्ड के बजाय एडमिन टोकन हैश स्टोर होता है।

इसलिए, व्यावहारिक थ्रेट मॉडल फाइलसिस्टम एक्सेस है, न कि नेटवर्क क्रिप्टोग्राफी। उस एक डायरेक्टरी तक रीड एक्सेस मिलने का मतलब है हर यूजर का ईमेल एड्रेस, उनके लॉगिन 2FA सीक्रेट्स, सेशन फोर्ज करने वाली की, और हर वॉल्ट की एक ऑफलाइन कॉपी, जिसे आराम से अटैक किया जा सकता है। नीचे दिया गया हर कदम उस डायरेक्टरी से लोगों को दूर रखने के लिए है।

सबसे पहले admin token को ठीक करें

/admin एक पूर्ण control panel है: इसमें user list, invitations, deletion और हर runtime setting शामिल है। यह केवल एक shared secret द्वारा सुरक्षित है, इसके अलावा कुछ नहीं। इसमें कोई username नहीं होता। न ही प्रति-user two-factor authentication होता है।

पुराने guides आपको openssl rand -base64 48 के साथ ADMIN_TOKEN generate करने के लिए कहते हैं। यह काम तो करता है, लेकिन जहाँ भी आप इसे configure करते हैं, वहां secret को plaintext में छोड़ देता है। Vaultwarden एक Argon2 PHC (password hashing competition) string भी स्वीकार करता है, इसलिए संग्रहीत मान एक hash होता है। चल रहे container के विरुद्ध एक generate करें:

docker exec -it vaultwarden /vaultwarden hash

या चल रहे container को छुए बिना:

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

यह दो बार password मांगता है, फिर $argon2id$ से शुरू होने वाली एक line print करता है। Bare-metal install पर, ./vaultwarden hash चलाएं। यदि आप सीधे argon2 CLI का उपयोग करना पसंद करते हैं, तो project OWASP के न्यूनतम parameters को document करता है:

echo -n 'MySecretPassword' | argon2 "$(openssl rand -base64 32)" -e -id -k 19456 -t 2 -p 1

अब वह जाल जिसमें लोगों का एक घंटा बर्बाद होता है। एक PHC string में $ characters होते हैं, और Docker Compose $ को variable interpolation के रूप में मानता है। इसे बिना escape किए environment: block में paste करने पर container तक पहुँचने वाला मान खराब हो जाता है, जिससे /admin आपके द्वारा सही माने गए token को reject कर देता है। दो सुरक्षित तरीके हैं। docker-compose.yml में, हर $ को double करें:

environment:
  ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$UUZxK1FZMkZoRHFQRlVrTXZvS0E3bHpNQW55c2dBN2NORzdsa0Nxd1JhND0$$cUoId+JBUsJutlG4rfDZayExfjq4TCt48aBc9qsc3UI

एक .env file में, किसी escaping की आवश्यकता नहीं है, लेकिन single quotes का उपयोग करें:

ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$MmeKRnGK5RW5mJS7h3TOL89GrpLPXJPAtTK8FTqj9HM$DqsstvoSAETl9YhnsXbf43WeaUwJC6JhViIvuPoig78'

फिर panel को rate limit करें और इसके session को छोटा करें:

ADMIN_RATELIMIT_SECONDS=300
ADMIN_RATELIMIT_MAX_BURST=3
ADMIN_SESSION_LIFETIME=20

यह प्रति client IP तीन admin login requests की अनुमति देता है, फिर हर पांच मिनट में एक request की दर से allowance को भरता है। सही और गलत दोनों passwords इसमें गिने जाते हैं, क्योंकि limiter password check से पहले चलता है। limit से अधिक requests होने पर HTTP 429 error मिलता है, साथ ही Too many requests, try again later. भी। Admin session आपके login करने के 20 मिनट बाद समाप्त हो जाता है, चाहे आप panel का उपयोग कर रहे हों या नहीं, क्योंकि activity इसे extend नहीं करती है।

इन सबसे बेहतर तरीका: page को बंद कर दें। अधिकांश instances को SMTP configure करने और पहले users को invite करने के लिए इसकी केवल एक बार आवश्यकता होती है, उसके बाद कभी नहीं। इसे disable करने के लिए, न तो ADMIN_TOKEN और न ही DISABLE_ADMIN_TOKEN set करें, config.json से कोई भी "admin_token" key हटा दें, और फिर container को recreate करें। file से key हटाना महत्वपूर्ण है क्योंकि admin page वहां settings लिखता है, और config.json में जो होता है वह environment पर हावी रहता है। केवल variable हटाने से page खुला रह जाता है।

किसी के डोमेन खोजने से पहले रजिस्ट्रेशन बंद करें

SIGNUPS_ALLOWED=false
SIGNUPS_VERIFY=true
SHOW_PASSWORD_HINT=false

SIGNUPS_ALLOWED डिफ़ॉल्ट रूप से true पर सेट होता है। यदि आप इसे ऐसे ही छोड़ देते हैं, तो आपके डोमेन पर आने वाला कोई भी व्यक्ति अकाउंट बना सकता है, और उनका डेटा आपके डेटा के साथ उसी db.sqlite3 में रहता है। इसे false पर सेट करें और एडमिन पेज से आमंत्रण (invitations) भेजकर लोगों को जोड़ें; SMTP आमंत्रण ईमेल भेजता है, जबकि इसके बिना सर्वर उस पते के लिए आमंत्रण रिकॉर्ड कर लेता है। INVITATIONS_ALLOWED भी डिफ़ॉल्ट रूप से true होता है और यह ऑर्गनाइजेशन एडमिन को दूसरों को आमंत्रित करने की अनुमति देता है। जब आप अपने उपयोगकर्ताओं पर भरोसा करते हैं तो यह ठीक है, और सिंगल-यूजर इंस्टेंस पर इसे false होना चाहिए। यदि केवल कुछ विशिष्ट डोमेन को ही रजिस्टर करने की अनुमति देनी है, तो SIGNUPS_DOMAINS_WHITELIST=example.com का उपयोग करें; यह ओपन साइनअप की तुलना में अधिक सीमित है लेकिन आमंत्रण प्रणाली की तुलना में काफी कमजोर है।

SHOW_PASSWORD_HINT डिफ़ॉल्ट रूप से false होता है और इसे वहीं रहना चाहिए। यदि यह ऑन है और SMTP कॉन्फ़िगर नहीं है, तो लॉगिन फॉर्म में एक वैध ईमेल पता टाइप करने पर उस अकाउंट का मास्टर पासवर्ड हिंट दिखाई देता है, जिससे हिंट लीक हो जाता है और यह भी पुष्टि हो जाती है कि वह ईमेल पता मौजूद है।

यदि आपका इंस्टेंस कुछ समय के लिए भी ओपन साइनअप के साथ चला है, तो एडमिन पेज खोलें और यह मानने से पहले कि आप ही एकमात्र अकाउंट हैं, यूजर लिस्ट को जरूर देखें।

वह पोर्ट जिसे आप पब्लिश नहीं करना चाहते थे

Docker इमेज कंटेनर के अंदर पोर्ट 80 पर लिसन करती है। बेयर-मेटल इंस्टॉलेशन डिफ़ॉल्ट रूप से ROCKET_PORT=8000 का उपयोग करता है। प्रलेखित रन कमांड इसे इस तरह पब्लिश करता है:

--publish 127.0.0.1:8000:80

127.0.0.1: प्रीफ़िक्स ही इसका मुख्य उद्देश्य है। इसके बजाय -p 8000:80 लिखें और Docker 0.0.0.0 को बाइंड कर देता है, और यह ऐसा nat टेबल में DNAT (डेस्टिनेशन नेटवर्क एड्रेस ट्रांसलेशन) नियम लिखकर करता है। उन नियमों का मूल्यांकन ufw द्वारा प्रबंधित filter चेन से पहले किया जाता है, इसलिए ufw status पोर्ट को डिनाइड (denied) रिपोर्ट करता है जबकि पोर्ट इंटरनेट पर खुशी-खुशी जवाब दे रहा होता है। पूरी कार्यप्रणाली को Docker पोर्ट्स द्वारा ufw को बायपास करने की गाइड में पढ़ना सार्थक है।

जाँचें कि वास्तव में क्या लिसन कर रहा है:

sudo ss -tlnp | grep 8000

एक सही परिणाम 127.0.0.1:8000 से बाइंड की गई एक सिंगल लाइन है। 0.0.0.0:8000 से बाइंड की गई लाइन का मतलब है कि वॉल्ट सीधे एक्सपोज़्ड है। मैपिंग को ठीक करें, फिर कंटेनर को फिर से बनाएँ, क्योंकि पोर्ट बाइंडिंग कंटेनर के निर्माण के समय तय हो जाती है और docker compose restart इसे नहीं बदलेगा:

docker compose up -d --force-recreate

पुरानी गाइड्स में एक और पोर्ट बचा हुआ है: 3012, जो अलग WebSocket पोर्ट है। इसके लिए सपोर्ट को Vaultwarden 1.31.0 में हटा दिया गया था, क्योंकि नोटिफिकेशन ट्रैफ़िक मुख्य HTTP पोर्ट पर चला गया है। WEBSOCKET_ENABLED और WEBSOCKET_PORT को 1.29.0 के बाद से डेप्रिकेट कर दिया गया है और उन्हें अनदेखा कर दिया जाता है। वर्तमान स्विच ENABLE_WEBSOCKET है, जो डिफ़ॉल्ट रूप से true पर सेट होता है। यदि आपका फ़ायरवॉल या compose फ़ाइल अभी भी 3012 को खोलती है, तो उसे बंद कर दें।

Reverse proxy पर TLS terminate करें, Rocket पर नहीं

Vaultwarden अपने web framework, Rocket के माध्यम से स्वयं TLS (transport layer security) प्रदान कर सकता है, लेकिन प्रोजेक्ट आपको production में ऐसा न करने की सलाह देता है। Rocket का इन-बिल्ट TLS strict SNI (server name indication) support की कमी रखता है, यही कारण है कि hardening सलाह यह है कि आप अपनी instance तक hostname के जरिए पहुँचें, न कि bare IP address के जरिए। Public IP ranges को लगातार scan किया जाता है, और जो vault IP address पर response देता है, वह vault आसानी से खोज लिया जाता है।

nginx server block के वे हिस्से जो महत्वपूर्ण हैं:

client_max_body_size 525M;

location / {
  proxy_pass http://127.0.0.1:8000;
  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_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
}

nginx defaults client_max_body_size को 1m पर रखता है, इसलिए override के बिना उस सीमा से बड़े request bodies विफल हो जाते हैं। nginx client को HTTP 413 लौटाता है और client intended to send too large body: ... bytes को log करता है; अस्वीकृत upload Vaultwarden तक नहीं पहुँचता है। Upgrade और Connection headers WebSocket handshake को /notifications/hub तक ले जाते हैं। यदि आप इन्हें हटा देते हैं, तो vault काम तो करेगा, लेकिन WebSocket notifications browser और desktop clients तक पहुँचना बंद हो जाएँगी; mobile clients अलग से configure की गई push notifications का उपयोग करते हैं।

Caddy छोटा है और स्वयं certificate प्राप्त करता है:

vw.example.com {
  reverse_proxy 127.0.0.1:8000 {
    header_up X-Real-IP {remote_host}
  }
}

फिर Vaultwarden को इसके बारे में सूचित करें:

DOMAIN=https://vw.example.com
IP_HEADER=X-Real-IP

IP_HEADER पहले से ही X-Real-IP पर default होता है, इसलिए मुख्य कार्य यह सुनिश्चित करना है कि proxy वास्तव में उस header को set करे। Vaultwarden भी header को केवल उन्हीं addresses से स्वीकार करता है जो IP_HEADER_TRUSTED_PROXIES में सूचीबद्ध हैं, जिसका default local है: कोई भी non-global address, जिसमें एक ही host या एक ही container network पर मौजूद proxy शामिल है। यदि proxy public address से connect होता है, तो उसे वहाँ जोड़ना होगा। यदि header अनुपस्थित है या किसी untrusted address से आता है, तो हर log line और हर login rate limit proxy के स्वयं के address को देखती है, जिसका अर्थ है कि एक attacker की विफलताएं instance के हर user के खिलाफ गिनी जाती हैं। यदि आप इसके बजाय IP_HEADER=X-Forwarded-For का उपयोग करते हैं, तो 1.37.4 उस rightmost address को लेता है जो trusted proxy नहीं है, इसलिए chain में मौजूद हर proxy को सूचीबद्ध करें, जिसमें nginx के सामने वाला CDN भी शामिल है। DOMAIN को भी वास्तविक https URL पर set करें, क्योंकि Vaultwarden उसी से invitation और account recovery links बनाता है, और WebAuthn security keys उसी origin से बंधी होती हैं।

एक विवरण जिसे लोग अनदेखा कर देते हैं: WebSocket connection session token को query string में /notifications/hub?access_token=[JWT] के रूप में पास करता है। वह आपके proxy access log में clear text में दिखाई देता है। log format में access_token parameter को redact करें, या सुनिश्चित करें कि वे logs ऐसी किसी जगह न भेजे जाएँ जिसे आप नियंत्रित नहीं करते हैं।

Login endpoint पर brute force को रोकें

Rate limits डिफ़ॉल्ट रूप से चालू रहती हैं (LOGIN_RATELIMIT_SECONDS=60, LOGIN_RATELIMIT_MAX_BURST=10)। ये हमलावर की गति धीमी करती हैं, लेकिन उसे पूरी तरह रोकती नहीं हैं। fail2ban ऐसा कर सकता है, लेकिन इसके लिए उसे Vaultwarden के failed logins को कहीं से पढ़ना होगा। Docker में सबसे आसान तरीका एक log file है, और Vaultwarden डिफ़ॉल्ट रूप से ऐसी कोई file नहीं बनाता है:

LOG_FILE=/data/vaultwarden.log
LOG_LEVEL=info
EXTENDED_LOGGING=true

एक विफल password login इस प्रारूप में एक line बनाता है, और यही वह string है जिसका मिलान आपके filter को करना है:

[2026-08-07 09:14:22.000][vaultwarden::api::identity][ERROR] Username or password is incorrect. Try again. IP: 203.0.113.10. Username: user@example.com.

Filter को /etc/fail2ban/filter.d/vaultwarden.local में लिखें:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

और jail को /etc/fail2ban/jail.d/vaultwarden.local में लिखें:

[vaultwarden]
enabled = true
backend = pyinotify
port = 80,443
filter = vaultwarden
banaction = %(banaction_allports)s
logpath = /vw-data/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

यदि Vaultwarden container के बजाय systemd service के रूप में चल रहा है, तो आप LOG_FILE को छोड़ सकते हैं: project का fail2ban wiki backend = systemd और logpath के स्थान पर Vaultwarden unit पर एक journalmatch का उपयोग करके journal को पढ़ता है।

यदि आपने admin page को रखा है, तो एक दूसरी jail जोड़ें जिसका failregex, ^.*Invalid admin token\. IP: <ADDR>.*$ हो, क्योंकि admin failures एक अलग message के साथ log होते हैं और login filter उन्हें कभी नहीं देख पाएगा। फिर अपने काम की जाँच करें:

sudo systemctl restart fail2ban
sudo fail2ban-client status vaultwarden

एक काम करने वाली jail आपकी log file को File list के अंतर्गत सूचीबद्ध करती है और Currently failed: 0 की रिपोर्ट देती है। किसी अलग network से तीन बार गलत password डालें और वह counter बढ़ जाएगा, फिर वह address Banned IP list के अंतर्गत दिखाई देगा। यदि counter कभी नहीं बढ़ता है, तो इसका सामान्य कारण logpath है: यह host पर file का path होना चाहिए, न कि container के अंदर का /data/... path। दूसरा सामान्य कारण एक अनुपस्थित या अविश्वसनीय X-Real-IP है, जो हर ban को आपके स्वयं के proxy पर लक्षित कर देता है। बाकी setup, जिसमें SSH jail भी शामिल है जिसे आपको पहले से ही चलाना चाहिए, Ubuntu 24.04 के लिए fail2ban guide में उपलब्ध है।

मास्टर पासवर्ड ही पूरी प्रणाली की सुरक्षा है

Client-side encryption का अर्थ है कि मास्टर पासवर्ड उपयोगकर्ता की symmetric key की सुरक्षा करता है। यदि किसी हमलावर ने डेटाबेस की कॉपी प्राप्त कर ली है, तो उस instance पर मौजूद छोटा मास्टर पासवर्ड किसी भी तरह सुरक्षित नहीं है, क्योंकि हमलावर अपने हार्डवेयर की क्षमता के अनुसार उस कॉपी पर offline हमला कर सकता है। सर्वर की कोई भी सेटिंग हमलावर की अपनी मशीन तक नहीं पहुँचती है।

PASSWORD_ITERATIONS=600000 को गलत समझना आसान है। यह क्लाइंट द्वारा भेजे गए login hash के server-side hash के लिए iterations सेट करता है, और प्रोजेक्ट का configuration template कहता है कि बदली हुई वैल्यू मौजूदा उपयोगकर्ताओं पर उनके अगले login के समय लागू होती है। यह client-side KDF को प्रभावित नहीं करता है, जो वह सेटिंग है जो यह तय करती है कि vault पर offline हमला करना कितना कठिन होगा। वह सेटिंग प्रत्येक account से संबंधित है और इसे web vault में Settings, Security, Keys के अंतर्गत बदला जाता है, जो key को फिर से encrypt करता है। Bitwarden का documentation कहता है कि 2026.2.1 के बाद के इसके clients 600,000 iterations से कम वाली PBKDF2 सेटिंग को स्वचालित रूप से बढ़ा देते हैं, जब उपयोगकर्ता मास्टर पासवर्ड के साथ login या unlock करता है। 10 October 2026 तक, इस व्यवहार की पुष्टि Vaultwarden सर्वर के साथ नहीं हुई है, और यह कभी भी Argon2id सेटिंग्स को नहीं बदलता है। इसलिए, जिस व्यक्ति ने वर्षों पहले साइन अप किया था, वह अभी भी पुरानी, कम KDF सेटिंग पर हो सकता है। इसकी जाँच करें और उन्हें सूचित करें, क्योंकि सर्वर उनके लिए ऐसा नहीं कर सकता है।

इसके बाद, प्रत्येक account के लिए two-factor authentication सक्षम करें। यह ciphertext की सुरक्षा नहीं करता है, क्योंकि यह vault encryption में भाग नहीं लेता है। यह केवल चोरी हुए पासवर्ड को login करने और कॉपी sync करने के लिए पर्याप्त होने से रोकता है। यदि email कॉन्फ़िगर किया गया है, तो REQUIRE_DEVICE_EMAIL=true नए डिवाइस के login email को अनिवार्य बना देता है: यदि email भेजने में विफलता होती है, तो login भी विफल हो जाता है। यदि mail सेवा पूरी तरह से अक्षम (disabled) है, तो यह सेटिंग नए डिवाइस के login को नहीं रोकती है।

Backups ही वह जगह है जहाँ self-hosted vaults के साथ गलतियाँ होती हैं

उसी VPS पर home directory में छोड़ा गया डेटा फोल्डर का tar czf ऊपर बताए गए हर कदम को बेकार कर देता है। उस archive में db.sqlite3 होता है जिसमें हर user का ciphertext होता है, rsa_key.pem जो login sessions को forge कर सकता है, और config.json जिसमें configured admin token value और SMTP password होता है। Argon2 के निर्देशों का पालन करने से admin password का hash तो store हो जाता है, लेकिन SMTP password plaintext में ही रहता है। उस एक file का read access मिलने पर account metadata, server secrets और encrypted vault data का खुलासा हो जाता है।

इसके लिए दो नियम हैं। Archive को server से बाहर निकालें। इसे बाहर भेजने से पहले encrypt करें।

इसमें शुद्धता (correctness) की भी एक समस्या है। service के चलते समय cp के साथ db.sqlite3 को copy करने से ऐसी file बन सकती है जो लिखते समय बीच में ही रुक गई हो और खुलेगी नहीं, और आपको इसका पता restore करते समय ही चलेगा। इसके बजाय SQLite के अपने snapshot का उपयोग करें:

sqlite3 /vw-data/db.sqlite3 ".backup '/tmp/vw-db-backup.sqlite3'"

Restore करने का पक्ष, जिसे कोई भी test नहीं करता, the Vaultwarden backup and restore guide में बताया गया है।

Hosted Bitwarden की तुलना में आप क्या खोते हैं

ईमानदार लेखा-जोखा। Bitwarden की hosted service को ऐसे लोग संचालित करते हैं जिनका पूर्णकालिक काम ही इसे चलाना है, और इसके लिए प्रकाशित third-party audits भी उपलब्ध हैं। Self-hosting में आप इसे अपनी patch cadence से बदल लेते हैं।

Vaultwarden सुरक्षा सुधारों को सामान्य releases के रूप में जारी करता है, और ये अक्सर आते हैं। 2 November 2026 को प्रोजेक्ट की release feed पर जाँच करने पर, वर्तमान release 1.37.5 है, जिसे 1 November 2026 को प्रकाशित किया गया था। इसके नोट्स में दो Medium सुरक्षा सलाह शामिल हैं और जल्द से जल्द update करने की पुरजोर सलाह दी गई है। web vault 2026.7.1 और उससे नए संस्करणों के लिए two-step login methods को चालू या बंद करने के लिए, और 2026.9.0 और उससे नए संस्करणों के लिए emergency access के माध्यम से account का नियंत्रण लेने के लिए यह आवश्यक है। पिछली release, 1.37.4, जिसे 5 October 2026 को प्रकाशित किया गया था, में सात सुरक्षा सलाह शामिल थीं, जिनमें से सबसे गंभीर को High रेटिंग दी गई थी। यह 24 July 2026 को आई 1.37.0 के बाद चौथी release थी: 1.37.1 इसके बाद 29 July को आई, 1.37.2, 22 August को (जो clients version 2026.8.0 और उससे नए के लिए आवश्यक है), और 1.37.3, 13 September को आई, जो credentials या 2FA बदलने पर 2FA remember tokens को रद्द कर देती है और prelogin तथा auth request endpoints पर rate limits लगाती है। यदि आप ऐसे organisations चलाते हैं जिनमें आप पूरी तरह से विश्वास नहीं करते, तो 1.37.4 के नोट्स update करने के बाद प्रत्येक organisation की API key को rotate करने का भी सुझाव देते हैं। 1.37.4 यह भी बदलता है कि X-Forwarded-For से कौन सा address पढ़ा जाता है, जिसे ऊपर reverse proxy अनुभाग में कवर किया गया है। एक instance जिसे आपने एक साल पहले set up किया था और भूल गए, वह एक साल पुराना code चला रहा है। latest tag अपने आप में मदद नहीं करता है: एक running container उसी image को बनाए रखता है जिसके साथ वह शुरू हुआ था, जब तक कि आप docker compose pull न चलाएं और उसे recreate न करें। host packages के लिए Ubuntu पर unattended upgrades लागू करें, और container update को एक ऐसे calendar reminder पर रखें जिसे आप वास्तव में देखेंगे।

एक ईमानदार पाठक को यह निष्कर्ष निकालना चाहिए: यहाँ cryptography Bitwarden का design है और यह सुरक्षित है, जबकि operational जोखिम पूरी तरह से आप पर आ जाता है। यदि आप इसे patch करते हैं और कहीं और backup लेते हैं, तो आपके द्वारा नियंत्रित VPS पर Vaultwarden instance आपके passwords रखने के लिए एक उचित स्थान है। यदि ये दो आदतें आप नहीं अपना सकते, तो hosted service के लिए भुगतान करें और अपना ध्यान कहीं और लगाएँ। feature-दर-feature तुलना Vaultwarden की self-hosted Bitwarden के साथ तुलना में दी गई है।

कंटेनर के नीचे होस्ट को सुरक्षित (harden) करना

Vaultwarden एक Linux बॉक्स पर चलने वाली एक प्रक्रिया है, और उस बॉक्स का root यूजर /vw-data को पढ़ सकता है, चाहे एप्लिकेशन को कैसे भी कॉन्फ़िगर किया गया हो। कंटेनर को एक unprivileged यूजर के रूप में चलाने के लिए अपने compose फ़ाइल में user: "1000:1000" का उपयोग करें, डेटा फ़ोल्डर का स्वामित्व उसी के अनुसार सेट करें, और जिसे कंटेनर को लिखने की आवश्यकता नहीं है उसे :ro के साथ read-only के रूप में माउंट करें। इसके बाद मुख्य द्वार को सुरक्षित करें: VPS पर SSH को सुरक्षित करना में केवल-की (key-only) लॉगिन और पासवर्ड प्रमाणीकरण को अक्षम करने के बारे में बताया गया है, जो उन सामान्य हमलों को रोकता है जो उपरोक्त सभी सुरक्षा उपायों को पार कर लेते हैं।

FAQ

क्या Vaultwarden database चोरी होने पर कोई मेरे passwords पढ़ सकता है?

सीधे तौर पर नहीं। हर vault item को client-side पर एक रैंडम तरीके से जनरेट की गई key से encrypt किया जाता है, जो user या organisation की symmetric key द्वारा सुरक्षित रहती है; password से बनी key user की symmetric key को सुरक्षित रखती है। db.sqlite3 में encrypted vault contents के साथ-साथ plaintext account metadata भी होता है। हमलावर को तुरंत हर account का email address, password hint, KDF settings, login और device metadata मिलता है। twofactor table में मौजूद login TOTP secrets भी unencrypted होते हैं, क्योंकि server को अपेक्षित code compute करने के लिए इनकी आवश्यकता होती है। हमलावर vault ciphertext पर offline हमला कर सकते हैं, इसलिए master password की लंबाई ही सुरक्षा का मुख्य आधार है।

क्या मुझे ADMIN_TOKEN का उपयोग करना चाहिए या admin page को पूरी तरह disable कर देना चाहिए?

यदि संभव हो तो इसे disable कर दें, क्योंकि अधिकांश instances को SMTP configure करने और users को invite करने के लिए इसकी केवल एक बार आवश्यकता होती है। इसे disable करने के लिए, न तो ADMIN_TOKEN और न ही DISABLE_ADMIN_TOKEN को set करें, config.json से कोई भी "admin_token" key हटा दें, और फिर container को recreate करें। केवल environment variable को हटाना पर्याप्त नहीं है, क्योंकि admin page द्वारा लिखी गई settings config.json में रहती हैं और उन्हें प्राथमिकता मिलती है। यदि आप page को रखते हैं, तो token को plaintext random string के बजाय vaultwarden hash द्वारा बनाए गए Argon2 hash के रूप में store करें, और ADMIN_RATELIMIT_MAX_BURST=3 को set करें।

मेरा ADMIN_TOKEN सही है लेकिन /admin इसे reject कर रहा है। क्या समस्या है?

यह लगभग हमेशा $ interpolation के कारण होता है। एक Argon2 PHC string में कई $ characters होते हैं, और Docker Compose उन्हें docker-compose.yml environment: block के अंदर variables के रूप में expand कर देता है। इस कारण container को एक गलत value मिलती है, जबकि आपकी file सही दिखती है। compose file में हर $ को $$ में बदलें (double करें), या value को single quotes में बंद करके एक .env file में ले जाएँ, जहाँ किसी escaping की आवश्यकता नहीं होती। इसके बाद container को recreate करें, क्योंकि restart करने से environment changes लागू नहीं होते।

क्या मुझे notifications के लिए अभी भी port 3012 खोलने की आवश्यकता है?

नहीं। Vaultwarden 1.31.0 में port 3012 पर WebSocket traffic का समर्थन हटा दिया गया है क्योंकि notifications अब मुख्य HTTP port पर आ गए हैं। WEBSOCKET_ENABLED और WEBSOCKET_PORT को 1.29.0 के बाद से deprecated कर दिया गया है और उन्हें अनदेखा कर दिया जाता है। वर्तमान setting ENABLE_WEBSOCKET है, जो डिफ़ॉल्ट रूप से true रहती है। firewall में 3012 को बंद करें और इसे अपनी compose file से हटा दें। इसके बाद सुनिश्चित करें कि आपका reverse proxy Upgrade और Connection headers को forward कर रहा है, क्योंकि browser और desktop WebSocket notifications इन्हीं पर निर्भर करते हैं। Mobile clients अलग से configure किए गए push notifications का उपयोग करते हैं।

क्या यह लेख उपयोगी था?