← شروع آموزش

WIUNIX ACADEMY

آموزش HAProxy و Let’s Encrypt با تمدید امن گواهی

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

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

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

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

Ubuntu 26.04 LTSبررسی‌شده با مستندات رسمی ·

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

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

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

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

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

قدم بعدی

پیش از ACME مسیر challenge را ثابت کنید

پس از اعتبارسنجی پیکربندی، دو سرویس اختصاصی را شروع کنید. از یک میزبان اینترنتی مستقل نیز همین probe را بدون resolve روی همهٔ مسیرهای A و AAAA بررسی کنید؛ پاسخ باید دقیق و بدون ریدایرکت باشد. مسیر عادی ۳۰۸ می‌دهد و مقصد آن دامنهٔ ثابت است، نه Host دلخواه کاربر. وب‌سرور Python در این آزمایش فقط loopback و فقط برای توکن عمومی است؛ سرویس عملیاتی باید پاسخ‌گوی استاتیک نگهداری‌شده داشته باشد.

bash

Bash روی VM اختصاصی؛ مورد بیرونی در متن مشخص است

set -eu
sudo haproxy -c -f '/srv/academy-haproxy-tls/haproxy.cfg'
sudo systemctl daemon-reload
sudo systemctl start academy-acme-webroot.service academy-haproxy.service
printf '%s\n' academy-http01-probe | sudo tee '/srv/academy-haproxy-tls/webroot/.well-known/acme-challenge/academy-probe' >/dev/null
curl --fail --resolve 'app.example.com:80:192.0.2.10' 'http://app.example.com/.well-known/acme-challenge/academy-probe'
curl --head --resolve 'app.example.com:80:192.0.2.10' 'http://app.example.com/'
dig +short A 'app.example.com'
dig +short AAAA 'app.example.com'
از کجا بدانم درست انجام شد؟

متن academy-http01-probe برمی‌گردد و مسیر عادی به HTTPS همان دامنه ریدایرکت ۳۰۸ می‌شود.

DNS، IPv6 و شرط‌های صدور را بررسی کنید

تمام A و AAAA عمومی باید روی پورت ۸۰ به همین پاسخ‌گو برسند. Let’s Encrypt معمولاً IPv6 را مقدم می‌داند؛ پاسخ اشتباه AAAA با IPv4 لزوماً جبران نمی‌شود. نمونهٔ حاضر فقط IPv4 دارد و نباید برایش AAAA منتشر کنید؛ IPv6 به bind صریح و آزمایش مسیر مستقل نیاز دارد. DNS مرجع، CAA، DNSSEC، خروجی HTTPS، ساعت و NAT/فایروال ارائه‌دهنده را پیش از سفارش بررسی کنید. HTTP-01 برای wildcard مناسب نیست.

مرحلهٔ بعد به CA عمومی وصل می‌شود و پس از مطالعهٔ شرایط ممکن است حساب بسازد. فقط دامنهٔ متعلق به خودتان را وارد کنید. برای این مقاله حساب یا گواهی عمومی صادر نشده است. خطا را پنهان نکنید؛ پس از محدودیت نرخ، Retry-After و راهنمای جاری را رعایت کنید.

09

قدم بعدی

staging را در مسیر مستقل امتحان کنید

شرایط CA را در فرایند تعاملی بخوانید و ایمیل قابل‌پیگیری را همان‌جا وارد کنید؛ ایمیل در فرم مقاله ذخیره نمی‌شود. حساب و گواهی staging مستقل و نامعتبر برای کاربران است و از این مسیر چیزی deploy نمی‌شود. موفقیت این مرحله به شبکه و CA واقعی وابسته است و پیش‌نمایش مقاله شاهد آن نیست.

bash

Bash روی VM اختصاصی؛ مورد بیرونی در متن مشخص است

sudo certbot certonly --dry-run --webroot -w '/srv/academy-haproxy-tls/webroot' -d 'app.example.com' --cert-name 'app.example.com' \
  --config-dir '/srv/academy-haproxy-tls/acme/staging-config' \
  --work-dir '/srv/academy-haproxy-tls/acme/staging-work' \
  --logs-dir '/srv/academy-haproxy-tls/acme/staging-logs'
از کجا بدانم درست انجام شد؟

Certbot صدور آزمایشی موفق را گزارش می‌کند و PEM سرویس تغییری نمی‌کند.

10

قدم بعدی

گواهی اصلی را یک‌بار درخواست کنید

فقط پس از پاسخ درست probe بیرونی و staging ادامه دهید. خروجی و وضعیت خطای Certbot را حفظ کنید. نام lineage با cert-name صریح ثابت می‌ماند. دستور certonly پیکربندی HAProxy را تغییر نمی‌دهد.

bash

Bash روی VM اختصاصی؛ مورد بیرونی در متن مشخص است

sudo certbot certonly --webroot -w '/srv/academy-haproxy-tls/webroot' -d 'app.example.com' --cert-name 'app.example.com' \
  --config-dir '/srv/academy-haproxy-tls/acme/config' \
  --work-dir '/srv/academy-haproxy-tls/acme/work' \
  --logs-dir '/srv/academy-haproxy-tls/acme/logs'
sudo certbot certificates --config-dir '/srv/academy-haproxy-tls/acme/config' --work-dir '/srv/academy-haproxy-tls/acme/work' --logs-dir '/srv/academy-haproxy-tls/acme/logs'
از کجا بدانم درست انجام شد؟

lineage اصلی همان نام را دارد و فایل‌های cert، chain، fullchain و کلید خصوصی محفوظ ایجاد شده‌اند.

11

قدم بعدی

اولین PEM را با اعتبارسنجی بسازید

ابتدا fullchain و سپس کلید متناظر در PEM قرار می‌گیرد. نام دامنه، کاربرد سرور، زنجیرهٔ اعتماد و بیش از یک روز اعتبار کنترل می‌شوند. فایل موقت ۰۶۰۰ در همان فایل‌سیستم به‌صورت اتمیک جای‌گذاری می‌شود. برای دسترسی HAProxy مجوز درخت خصوصی ACME را باز نکنید.

bash

Bash روی VM اختصاصی؛ مورد بیرونی در متن مشخص است

set -eu
sudo python3 - <<'PY'
import os, subprocess, tempfile
from pathlib import Path
os.umask(0o077)
root=Path('/srv/academy-haproxy-tls')
lineage=root/'acme/config/live/app.example.com'
target=root/'certs/app.example.com.pem'
assert not target.exists() and not target.is_symlink()
def run(*args):
    return subprocess.run(args,check=True,capture_output=True).stdout
run('openssl','x509','-in',str(lineage/'cert.pem'),'-checkend','86400','-noout')
run('openssl','verify','-CAfile','/etc/ssl/certs/ca-certificates.crt',
    '-untrusted',str(lineage/'chain.pem'),'-purpose','sslserver',
    '-verify_hostname','app.example.com',str(lineage/'cert.pem'))
assert run('openssl','x509','-in',str(lineage/'cert.pem'),'-pubkey','-noout') == run('openssl','pkey','-in',str(lineage/'privkey.pem'),'-pubout')
fd,name=tempfile.mkstemp(dir=target.parent,prefix='.initial-')
with os.fdopen(fd,'wb') as f:
    f.write((lineage/'fullchain.pem').read_bytes()+b'\n'+(lineage/'privkey.pem').read_bytes())
    f.flush(); os.fsync(f.fileno())
os.replace(name,target)
print('Initial protected PEM assembled; TLS config not yet loaded')
PY
از کجا بدانم درست انجام شد؟

PEM با مالک root و مجوز ۰۶۰۰ ساخته شده و bootstrap همچنان challenge را پاسخ می‌دهد.

12

قدم بعدی

کاندیدای TLS را جدا ذخیره کنید

هر دو بک‌اند باید همان اپلیکیشن را اجرا کنند و health/ready تنها هنگام آمادگی واقعی وابستگی‌ها ۲۰۰ بدهد. Host برابر app.example.com باید پذیرفته شود. مدیریت نشست و داده مسئولیت اپلیکیشن است. فایل بعدی را در کاندیدای تازه وارد کنید؛ bootstrap در حال اجرا حفظ می‌شود. در این نمونه HSTS preload، includeSubDomains و سوکت مدیریتی فعال نیست.

bash

Bash روی VM اختصاصی؛ مورد بیرونی در متن مشخص است

set -eu
curl --fail -H 'Host: app.example.com' 'http://10.77.0.21:8080/health/ready'
curl --fail -H 'Host: app.example.com' 'http://10.77.0.22:8080/health/ready'
test ! -e '/srv/academy-haproxy-tls/haproxy.tls.cfg'
test ! -L '/srv/academy-haproxy-tls/haproxy.tls.cfg'
sudo install -m 0644 /dev/null '/srv/academy-haproxy-tls/haproxy.tls.cfg'
sudo nano '/srv/academy-haproxy-tls/haproxy.tls.cfg'
از کجا بدانم درست انجام شد؟

هر دو readiness پاسخ ۲۰۰ دارند و کاندیدای مستقل برای ویرایش آماده است.

13

قدم بعدی

TLS، هدر قابل‌اعتماد و readiness

این پنل کل محتوای کاندیداست. Forwarded حذف می‌شود و X-Forwarded-* از اتصال مستقیم ساخته می‌شود. option forwardfor را روی این سیاست اضافه نکنید. بک‌اند باید فقط IP مبدأ واقعی HAProxy را بپذیرد، نه تمام شبکه‌های خصوصی را.

text · /srv/academy-haproxy-tls/haproxy.tls.cfg

فایل روی VM اختصاصی

global
  log stdout format raw local0
  user haproxy
  group haproxy
  ssl-default-bind-options ssl-min-ver TLSv1.2

defaults
  log global
  mode http
  option httplog
  timeout connect 5s
  timeout client 30s
  timeout server 30s
  timeout http-request 10s

frontend public_http
  bind 192.0.2.10:80
  acl known_host hdr(host) -i app.example.com app.example.com:80
  http-request deny deny_status 421 unless known_host
  acl acme_path path_beg /.well-known/acme-challenge/
  http-request redirect prefix https://app.example.com code 308 unless acme_path
  use_backend acme_webroot if acme_path

backend acme_webroot
  server challenge 127.0.0.1:8888 check

frontend public_https
  bind 192.0.2.10:443 ssl crt /srv/academy-haproxy-tls/certs/app.example.com.pem alpn h2,http/1.1
  acl known_host hdr(host) -i app.example.com app.example.com:443
  http-request deny deny_status 421 unless known_host
  http-request del-header Forwarded
  http-request del-header X-Forwarded-For
  http-request del-header X-Forwarded-Proto
  http-request del-header X-Forwarded-Host
  http-request del-header X-Forwarded-Port
  http-request del-header X-Real-IP
  http-request set-header X-Forwarded-For %[src]
  http-request set-header X-Forwarded-Proto https
  http-request set-header X-Forwarded-Host app.example.com
  http-request set-header X-Forwarded-Port 443
  default_backend app_nodes

backend app_nodes
  balance roundrobin
  option httpchk
  http-check send meth GET uri /health/ready ver HTTP/1.1 hdr Host app.example.com
  http-check expect status 200
  server app_a 10.77.0.21:8080 check inter 2s fall 2 rise 2
  server app_b 10.77.0.22:8080 check inter 2s fall 2 rise 2
از کجا بدانم درست انجام شد؟

کاندیدا شامل دو ورودی عمومی، بک‌اند محلی challenge و دو نود اپلیکیشن با health check است.

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