← شروع آموزش

WIUNIX ACADEMY

راه‌اندازی Vaultwarden با HTTPS، مدیریت محدود و بکاپ هماهنگ

صفحهٔ 2 از 5؛ مراحل قبلی و پیش‌نیازها را پیش از ادامه مرور کن.

آموزش متناسب با محیط تو

کجا اجرا می‌کنی؟

سیستم‌عامل و نسخه را انتخاب کن تا مراحل، دستورها و راه‌حل‌ها برای همان محیط نمایش داده شوند.

Debian13بررسی‌شده با مستندات رسمی ·

آموزش متناسب با مقادیر تو

تنظیمات این آموزش

مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر می‌کنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری می‌شوند و به سرور یا لینک اشتراک‌گذاری فرستاده نمی‌شوند. پیش از اجرا، DNS، گواهی‌ها و سیاست شبکهٔ واقعی را بررسی کن.

آی‌پی، دامنه یا پورت مثال‌ها با محیط تو فرق دارد؟ دکمهٔ زیر را باز کن، مقادیر را تغییر بده و «اعمال در آموزش» را بزن؛ سپس دستورهای به‌روز‌شده را کپی کن.

تنظیم مقادیر برای محیط من7 مقدار قابل‌تغییر
03

قدم بعدی

ساخت پوشه‌های خصوصی بدون بازنویسی

اگر مسیر اصلی از قبل وجود داشته یا والد آن symlink و ناامن باشد، کار متوقف می‌شود. داده متعلق به 23159 است؛ تنظیمات، TLS، بکاپ و فایل محرمانه در اختیار root می‌مانند. حساب ورود جدیدی روی میزبان ساخته نمی‌شود.

bash

ماشین اختصاصی Vaultwarden

sudo python3 - <<'PY'
import os,stat
from pathlib import Path
r=Path('/srv/academy-vaultwarden')
assert r.is_absolute() and '..' not in r.parts and str(r) not in ('/','/srv','/opt','/etc')
for p in reversed(r.parents):
    assert stat.S_ISDIR(p.lstat().st_mode) and not p.is_symlink(), 'Unsafe/missing parent'
    assert p.stat().st_uid==0 and not p.stat().st_mode & 0o022, 'Parent must be root-controlled'
r.mkdir(mode=0o750)
os.chown(r,0,23159);os.chmod(r,0o750)
for name in ('data','config','secrets','tls','backups'):
    p=r/name;p.mkdir(mode=0o700)
    os.chown(p,23159 if name=='data' else 0,23159)
    os.chmod(p,0o750 if name=='secrets' else 0o700)
for name in ('settings.env','nginx.conf'):
    fd=os.open(r/'config'/name,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)
    os.close(fd)
print('New private tree created; existing paths are never replaced')
PY
از کجا بدانم درست انجام شد؟

درخت تازهٔ /srv/academy-vaultwarden با مالکیت و مجوز محدود ساخته شده است.

04

قدم بعدی

ساخت هش مدیریت بدون نمایش رمز

در ترمینال خصوصی و بدون ضبط جلسه، عبارت مدیریتی یکتای حداقل ۲۴ نویسه را دو بار در ورودی مخفی وارد کنید. فقط PHC از نوع Argon2id در فایل خصوصی نوشته می‌شود؛ اصل عبارت را در محل محرمانهٔ مستقل نگه دارید. رمز و هش را در فرم مقاله، تاریخچهٔ shell، JSON، Git، تیکت یا تصویر قرار ندهید. خود هش هم برای حملهٔ آفلاین حساس است.

رمز از stdin به argon2 می‌رسد، در argv یا متغیر محیطی قرار نمی‌گیرد و خروجی چاپ نمی‌شود. فایل با منع بازنویسی و دنبال‌کردن symlink ساخته می‌شود. پارامترها ۶۴ مگابایت، سه دور و چهار lane هستند؛ این تنظیم مربوط به ورود مدیر است و KDF رمز اصلی کاربران را تعیین نمی‌کند.

bash

ماشین اختصاصی Vaultwarden

sudo python3 - <<'PY'
import getpass,os,re,secrets,subprocess
from pathlib import Path
p=Path('/srv/academy-vaultwarden/secrets/admin.phc')
assert not p.exists() and not p.is_symlink(), 'Secret already exists'
with open('/dev/tty','r+') as tty:
    password=getpass.getpass('New admin passphrase: ',stream=tty)
    again=getpass.getpass('Repeat admin passphrase: ',stream=tty)
assert password==again and len(password)>=24, 'Mismatch or too short'
result=subprocess.run(['argon2',secrets.token_hex(16),'-id','-m','16','-t','3','-p','4','-e'],input=password.encode(),stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)
phc=result.stdout.decode().strip()
assert re.fullmatch(r'\$argon2id\$v=19\$m=65536,t=3,p=4\$[A-Za-z0-9+/]+\$[A-Za-z0-9+/]+',phc), 'Unexpected hash format'
fd=os.open(p,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o640)
with os.fdopen(fd,'w') as f: f.write(phc+'\n')
os.chown(p,0,23159);os.chmod(p,0o640)
del password,again,phc,result
print('Protected Argon2id file created; no secret was printed')
PY
از کجا بدانم درست انجام شد؟

فایل PHC با مجوز 0640 ساخته شده و رمز یا هش چاپ نشده است.

05

قدم بعدی

بازکردن ویرایشگر تنظیمات خصوصی

فایل خالیِ ساخته‌شده را باز کنید، محتوای پنل بعد را در آن بگذارید و ذخیره کنید. ADMIN_TOKEN_FILE فقط به فایل PHC اشاره می‌کند؛ توکن را در تنظیمات نگذارید و DISABLE_ADMIN_TOKEN را فعال نکنید. فایل config.json بر محیط اولویت دارد و در پوشهٔ دادهٔ تازه نباید وجود داشته باشد.

bash

ماشین اختصاصی Vaultwarden

sudo env HOME=/root nano --ignorercfiles --restricted --noread -- '/srv/academy-vaultwarden/config/settings.env'
از کجا بدانم درست انجام شد؟

فایل تنظیمات شامل مقدارهای غیرمحرمانهٔ پنل بعد است.

فایل تنظیمات سرویس

ثبت‌نام عمومی بسته است. INVITATIONS_ALLOWED=false دعوت عادی سازمانی را می‌بندد، اما دعوت مدیر سرور استثناست. ساخت سازمان و Sends در این شروع محدود غیرفعال‌اند. allowlist پراکسی لایه‌ای جدا از رمز مدیریت است.

ini · /srv/academy-vaultwarden/config/settings.env
DOMAIN=https://vault.example.com
SIGNUPS_ALLOWED=false
INVITATIONS_ALLOWED=false
ORG_CREATION_USERS=none
SENDS_ALLOWED=false
ADMIN_TOKEN_FILE=/run/secrets/admin.phc
ADMIN_SESSION_LIFETIME=10
IP_HEADER=X-Real-IP
IP_HEADER_TRUSTED_PROXIES=local
ROCKET_ADDRESS=0.0.0.0
ROCKET_PORT=8000
DATA_FOLDER=/data
LOG_LEVEL=warn

حفظ دقیق علامت‌های دلار در PHC

فایل admin.phc یک خط PHC خام دارد؛ نه کوتیشن دور آن است و نه دلارها دوبرابر می‌شوند. ADMIN_TOKEN_FILE همان فایل را می‌خواند و محتوایش وارد تفسیر shell یا Compose نمی‌شود. برای عیب‌یابی فایل را چاپ یا environment را dump نکنید.

اگر بعداً PHC را داخل environment در YAML کامپوز بگذارید، هر دلارِ ثابت در همان YAML باید دوبرابر شود. فایل .env کامپوز قواعد کوتیشن خودش را دارد و با --env-file در Docker یکسان نیست. خروجی escape‌شده یا کوتیشن‌دار را در فایل خام این راهنما نگذارید؛ طراحی مبتنی بر فایل را حفظ و مستند رسمی را برای تغییر روش بررسی کنید.

06

قدم بعدی

اجرای بک‌اند ثابت‌شده روی لوپ‌بک

پس از ذخیرهٔ تنظیمات اجرا کنید. کانتینر با 23159، ریشهٔ فقط‌خواندنی و دادهٔ پایدار خصوصی بالا می‌آید. دسترسی مدیر Docker همچنان پرامتیاز است و فایل محرمانه را پنهان نمی‌کند. فقط 127.0.0.1:8159 منتشر می‌شود؛ آن را عمومی نکنید. سیاست restart به‌تنهایی شاهد آزمون reboot نیست.

bash

ماشین اختصاصی Vaultwarden

set -eu
sudo docker pull 'docker.io/vaultwarden/server:1.37.4@sha256:efb3cde962015fcc036b2ea625242248611943b27212ebf4392841fb30fad055'
sudo docker run -d --name 'academy_vaultwarden' --restart unless-stopped \
  --user '23159:23159' --cap-drop ALL \
  --security-opt no-new-privileges:true --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --env-file '/srv/academy-vaultwarden/config/settings.env' \
  --mount 'type=bind,src=/srv/academy-vaultwarden/data,dst=/data' \
  --mount 'type=bind,src=/srv/academy-vaultwarden/secrets/admin.phc,dst=/run/secrets/admin.phc,readonly' \
  -p '127.0.0.1:8159:8000' \
  --entrypoint /vaultwarden 'docker.io/vaultwarden/server:1.37.4@sha256:efb3cde962015fcc036b2ea625242248611943b27212ebf4392841fb30fad055'
ready=no
for attempt in $(seq 1 30); do
  status=$(curl --silent --max-time 2 --output /dev/null --write-out '%{http_code}' 'http://127.0.0.1:8159/alive' || true)
  if test "$status" = 200; then ready=yes; break; fi
  sleep 1
done
test "$ready" = yes
sudo ss -lntp 'sport = :8159'
از کجا بدانم درست انجام شد؟

پاسخ /alive برابر 200 و listener فقط لوپ‌بک 8159 است.

همهٔ آموزش‌های آکادمی ↗