داکروردپرس

نحوه نصب وردپرس با Docker Compose

مقدمه

وردپرس یک سیستم مدیریت محتوای (CMS) رایگان و متن-باز است که روی دیتابیس MySQL با پردازش PHP بنا شده. به‌دلیل معماری پلاگینِ توسعه‌پذیر و سیستم قالب‌سازی‌اش، بیشتر مدیریتش را می‌توان از طریق رابط وب انجام داد. این دلیل محبوبيت وردپرس هنگام ساخت انواع مختلف وب‌سایت‌هاست—از بلاگ تا صفحات محصول تا سایت‌های فروشگاهی.

اجرای وردپرس معمولاً شامل نصب استک LAMP (لینوکس، Apache، MySQL و PHP) یا LEMP (لینوکس، Nginx، MySQL و PHP) است؛ که می‌تواند زمان‌بر باشد. اما با استفاده از ابزارهایی مثل داکر و Docker Compose، می‌توانید فرایند راه‌اندازی استک مورد علاقه و نصب وردپرس را ساده‌تر کنید. به‌جای نصب دستی اجزای منفرد، از Imageها استفاده کنید—که چیزهایی مثل کتابخانه‌ها، فایل‌های پیکربندی و متغیرهای محیطی را استاندارد می‌کنند. سپس این Imageها را در کانتینرها—پروسه‌های ایزوله‌ای که روی سیستم‌عامل مشترک اجرا می‌شوند—اجرا کنید. علاوه بر این، با استفاده از Compose می‌توانید چند کانتینر را—مثلاً اپلیکیشن و دیتابیس—هماهنگ کنید تا با هم ارتباط برقرار کنند.

در این tutorial، نصب چندکانتینریِ وردپرس می‌سازید. کانتینرهای شما شامل دیتابیس MySQL، وب‌سرور Nginx و خود وردپرس خواهند بود. هم‌چنین نصب‌تان را با دریافت گواهی‌های TLS/SSL از Let’s Encrypt برای دامنه‌ای که می‌خواهید با سایت‌تان مرتبط باشد، امن می‌کنید. در نهایت، Cron Jobای راه می‌اندازید تا گواهی‌های‌تان را تمدید کند تا دامنه‌تان امن بماند.

نکات کلیدی

  • Docker Compose استقرار وردپرس را ساده می‌کند با حذف نیاز به نصب دستی اجزای استک LAMP/LEMP. به‌جایش، از Imageهای استاندارد استفاده می‌کنید که کتابخانه‌ها، پیکربندی‌ها و متغیرهای محیطی را در کانتینرهای ایزوله باندل می‌کنند.
  • راه‌اندازی، چهار سرویس متمایزِ همکار لازم دارد: کانتینر دیتابیس MySQL، کانتینر اپلیکیشن وردپرس (با PHP-FPM)، کانتینر وب‌سرور Nginx و کانتینر Certbot برای مدیریت گواهی SSL.
  • اعتبارنامه‌های حساس (رمز root مربوط به MySQL، نام کاربری/رمز عبور دیتابیس) در فایل .env ذخیره می‌شوند که با فایل‌های .gitignore و .dockerignore از Version Control و Imageهای داکر مستثنی شده—که از افشای تصادفی جلوگیری می‌کند.
  • این tutorial گواهی‌های TLS/SSL رایگان را از طریق Certbot مربوط به Let’s Encrypt پیاده می‌کند؛ با استفاده از پلاگین webroot برای اعتبارسنجی دامنه. فرایند شامل تست با گواهی‌های staging قبل از دریافت گواهی‌های پروداکشن است.
  • Volumeهای نام‌دار داکر (dbdata، wordpress، certbot-etc) داده‌های اپلیکیشن، فایل‌های دیتابیس و گواهی‌های SSL را روی فایل‌سیستم هاست ذخیره می‌کنند؛ که تضمین می‌کند داده‌ها—even وقتی کانتینرها بازسازی می‌شوند—ماندگار باشند.
  • وب‌سرور پیکربندی خاص وردپرس لازم دارد؛ شامل پردازش PHP از طریق FastCGI، کش دارایی‌های استاتیک، هدرهای امنیتی (X-Frame-Options، Content-Security-Policy) و ریدایرکت HTTP-به-HTTPS.
  • همه کانتینرها از طریق شبکه Bridge تعریف‌شده-توسط-کاربر (app-network) متصل می‌شوند؛ که ارتباط بین-کانتینری را ممکن می‌کند در حالی که فقط پورت‌های 80 و 443 برای امنیت به دنیای بیرون افشا می‌شوند.
  • Cron Jobای اسکریپت تمدید را اجرا می‌کند که از certbot renew برای رفرش خودکار گواهی‌ها قبل از انقضایشان (هر ۹۰ روز) استفاده؛ سپس پیکربندی Nginx را برای اعمال گواهی‌های به‌روز بدون قطعی Reload می‌کند.

پیش‌نیازها

اگر از نسخه اوبونتو 20.04 یا پایین‌تر استفاده می‌کنید، ارتقا به جدیدترین نسخه را توصیه می‌کنیم؛ چون اوبونتو دیگر این نسخه‌ها را پشتیبانی نمی‌کند.

برای دنبال کردن این tutorial به این موارد نیاز دارید:

  • سروری اجراکننده اوبونتو، همراه با کاربر غیر root دارای دسترسی sudo و فایروال فعال. برای راهنمایی راه‌اندازی، به راهنمای راه‌اندازی اولیه سرور با اوبونتو در پارمین کلود مراجعه کنید.
  • داکر نصب‌شده روی سرورتان، با دنبال کردن گام‌های ۱ و ۲ راهنمای «نحوه نصب و استفاده از داکر روی اوبونتو» در پارمین کلود.
  • Docker Compose نصب‌شده روی سرورتان، با دنبال کردن گام ۱ راهنمای «نحوه نصب Docker Compose روی اوبونتو» در پارمین کلود.
  • نام دامنه ثبت‌شده. این tutorial در سراسر متن از your_domain استفاده می‌کند.
  • هر دوی رکوردهای DNS زیر برای سرورتان تنظیم‌شده. برای جزئیات نحوه افزودن آن‌ها می‌توانید مقدمه DNS پارمین کلود را دنبال کنید:
    • رکورد A با your_domain که به IP عمومی سرورتان اشاره کند.
    • رکورد A با www.your_domain که به IP عمومی سرورتان اشاره کند.

وقتی همه‌چیز را راه‌اندازی کردید، آماده شروع گام اول هستید.

نصب وردپرس با Docker Compose

  • Define کردن پیکربندی وب‌سرور
  • Define کردن متغیرهای محیطی
  • Define کردن سرویس‌ها در Docker Compose
  • دریافت گواهی SSL
  • تغییر پیکربندی وب‌سرور
  • تکمیل نصب از طریق رابط وب
  • فعال‌سازی تمدید خودکار SSL

گام ۱ — تعریف پیکربندی وب‌سرور

قبل از اجرای هر کانتینری، اولین قدم‌تان تعریف پیکربندی وب‌سرور Nginx است. فایل پیکربندی‌تان شامل برخی بلاک‌های location خاص-وردپرس—to‌همراه بلاک locationای برای هدایت درخواست‌های تأیید Let’s Encrypt به کلاینت Certbot برای تمدیدهای خودکار گواهی—خواهد بود.

اول، دایرکتوری پروژه‌ای برای راه‌اندازی وردپرس‌تان بسازید. در این مثال، wordpress نامیده شده. اگر بخواهید می‌توانید نام دیگری برای این دایرکتوری بگذارید:

mkdir wordpress

سپس به دایرکتوری بروید:

cd wordpress

بعد، برای فایل پیکربندی دایرکتوری بسازید:

mkdir nginx-conf

فایل را با nano یا ویرایشگر مورد علاقه‌تان باز کنید:

nano nginx-conf/nginx.conf

در این فایل، server blockای با دایرکتیوهایی برای نام سرور و ریشه سند، و بلاک‌های locationای برای هدایت درخواست گواهی کلاینت Certbot، پردازش PHP و درخواست‌های دارایی استاتیک اضافه کنید.

کد زیر را در فایل اضافه کنید. حتماً your_domain را با نام دامنه خودتان جایگزین کنید:

~/wordpress/nginx-conf/nginx.conf

server {
        listen 80;
        listen [::]:80;

        server_name your_domain www.your_domain;

        index index.php index.html index.htm;

        root /var/www/html;

        location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
        }

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location ~ /\.ht {
                deny all;
        }

        location = /favicon.ico {
                log_not_found off; access_log off;
        }
        location = /robots.txt {
                log_not_found off; access_log off; allow all;
        }
        location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
                expires max;
                log_not_found off;
        }
}

Server block ما شامل اطلاعات زیر است:

دایرکتیوها:

  • listen: به Nginx می‌گوید روی پورت 80 گوش بدهد؛ که به شما اجازه استفاده از پلاگین webroot مربوط به Certbot برای درخواست‌های گواهی‌تان را می‌دهد. دقت کنید که هنوز پورت 443 را شامل نشده—وقتی گواهی‌های‌تان را با موفقیت گرفتید، پیکربندی‌تان را برای شامل کردن SSL به‌روزرسانی می‌کنید.
  • server_name: نام سرور و server blockی که برای درخواست‌های به سرورتان استفاده شود را تعریف می‌کند. حتماً your_domain را در این خط با نام دامنه خودتان جایگزین کنید.
  • index: این دایرکتیو فایل‌هایی را تعریف می‌کند که هنگام پردازش درخواست‌ها به سرورتان به‌عنوان Index استفاده می‌شوند. ترتیب اولویت پیش‌فرض را اینجا تغییر داده و index.php را جلوی index.html گذاشته‌اید تا Nginx تا جای ممکن فایل‌های به‌نام index.php را اولویت بدهد.
  • root: این دایرکتیو دایرکتوری ریشه برای درخواست‌ها به سرورتان را نام‌گذاری می‌کند. این دایرکتوری یعنی /var/www/html، به‌عنوان Mount Point در زمان بیلد توسط دستورالعمل‌های Dockerfile مربوط به وردپرس ساخته می‌شود.

بلاک‌های Location:

  • location ~ /.well-known/acme-challenge: این بلاک درخواست‌ها به دایرکتوری .well-known را مدیریت می‌کند؛ جایی که Certbot فایل موقتی برای تأیید اینکه DNS دامنه‌تان به سرورتان Resolve می‌شود قرار می‌دهد. با برقراری این پیکربندی، می‌توانید از پلاگین webroot مربوط به Certbot برای گرفتن گواهی برای دامنه‌تان استفاده کنید.
  • location /: در این بلاک، دایرکتیو try_files برای چک کردن فایل‌های منطبق با درخواست‌های URI منفرد استفاده می‌شود. اما به‌جای برگرداندن وضعیت 404 Not Found به‌عنوان پیش‌فرض، کنترل را با آرگومان‌های درخواست به فایل index.php وردپرس پاس می‌دهید.
  • location ~ .php$: این بلاک پردازش PHP را مدیریت و این درخواست‌ها را به کانتینر wordpress شما Proxy می‌کند. چون Docker Image مربوط به وردپرس‌تان بر پایه image یعنی php:fpm خواهد بود، گزینه‌های پیکربندی خاصِ پروتکل FastCGI را هم در این بلاک شامل می‌شوید. Nginx پردازشگر PHP مستقلی برای درخواست‌های PHP لازم دارد. در این مورد، این درخواست‌ها توسط پردازشگر php-fpmِ موجود با image یعنی php:fpm مدیریت می‌شوند.
  • location ~ /.ht: این بلاک فایل‌های .htaccess را مدیریت می‌کند؛ چون Nginx آن‌ها را سرو نمی‌کند. دایرکتیو deny_all تضمین می‌کند فایل‌های .htaccess هرگز به کاربران سرو نشوند.
  • location = /favicon.ico، location = /robots.txt: این بلاک‌ها تضمین می‌کنند درخواست‌های به /favicon.ico و /robots.txt لاگ نشوند.
  • location ~ .(css|gif|ico|jpeg|jpg|js|png)$:* این بلاک لاگینگ برای درخواست‌های دارایی استاتیک را خاموش و تضمین می‌کند این دارایی‌ها—چون معمولاً سرو کردن‌شان پرهزینه است—بسیار قابل‌کش باشند.

برای اطلاعات بیشتر درباره Proxy کردن FastCGI، راهنمای «درک و پیاده‌سازی FastCGI Proxying در Nginx» و برای اطلاعات درباره Server و Location Blockها، راهنمای «درک الگوریتم‌های انتخاب Server و Location Block در Nginx» را در پارمین کلود بخوانید.

وقتی ویرایش تمام شد فایل را ذخیره و ببندید. اگر از nano استفاده می‌کنید، با CTRL+X، Y و سپس ENTER این کار را بکنید.

با برقراری پیکربندی Nginx، می‌توانید به ساخت متغیرهای محیطی برای پاس دادن به کانتینرهای اپلیکیشن و دیتابیس‌تان در زمان اجرا بروید.

گام ۲ — تعریف متغیرهای محیطی

کانتینرهای دیتابیس و اپلیکیشن وردپرس شما در زمان اجرا به دسترسی متغیرهای محیطی خاصی نیاز دارند تا داده‌های اپلیکیشن‌تان ماندگار و برای اپلیکیشن در دسترس بمانند. این متغیرها شامل اطلاعات حساس و غیرحساس هستند: مقادیر حساس برای رمز عبور root مربوط به MySQL و کاربر/رمز عبور دیتابیس اپلیکیشن؛ و اطلاعات غیرحساس برای نام و هاست دیتابیس اپلیکیشن.

به‌جای تنظیم همه این مقادیر در فایل Docker Compose خودتان—فایل اصلی حاوی اطلاعات نحوه اجرای کانتینرهای‌تان—مقادیر حساس را در فایل .env تنظیم و گردش‌شان را محدود کنید. این از کپی شدن این مقادیر به مخازن پروژه‌تان و افشای عمومی جلوگیری می‌کند.

در دایرکتوری اصلی پروژه یعنی ~/wordpress، فایلی به نام .env باز کنید:

nano .env

مقادیر محرمانه‌ای که در این فایل تنظیم می‌کنید شامل رمز عبوری برای کاربر root مربوط به MySQL و نام کاربری و رمز عبوری که وردپرس برای دسترسی به دیتابیس استفاده می‌کند، هستند.

نام‌ها و مقادیر متغیر زیر را به فایل اضافه کنید. یادتان باشد برای هر متغیر مقادیر خودتان را فراهم کنید:

~/wordpress/.env

MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password

شامل رمز عبوری برای حساب مدیریتی root—to‌همراه نام کاربری و رمز عبور مورد علاقه برای دیتابیس اپلیکیشن‌تان.

وقتی ویرایش تمام شد فایل را ذخیره و ببندید.

چون فایل .env شما اطلاعات حساسی شامل می‌شود، می‌خواهید مطمئن شوید در فایل‌های .gitignore و .dockerignore پروژه‌تان گنجانده شده باشد. این به Git و داکر می‌گوید چه فایل‌هایی را—به‌ترتیب—to مخازن Git و Imageهای داکر شما کپی نکنند.

اگر قصد کار با Git برای Version Control را دارید، دایرکتوری کاری فعلی‌تان را با git init به‌عنوان مخزن مقداردهی اولیه کنید:

git init

سپس فایل .gitignore بسازید و بازش کنید:

nano .gitignore

.env را به فایل اضافه کنید:

~/wordpress/.gitignore

.env

وقتی ویرایش تمام شد فایل را ذخیره و ببندید.

به‌طور مشابه، احتیاط خوبی است که .env را به فایل .dockerignore اضافه کنید تا وقتی از این دایرکتوری به‌عنوان Build Context استفاده می‌کنید، در کانتینرهای‌تان ننشیند.

فایل را باز کنید:

nano .dockerignore

.env را به فایل اضافه کنید:

~/wordpress/.dockerignore

.env

زیر این، می‌توانید اختیاری فایل‌ها و دایرکتوری‌های مرتبط با توسعه اپلیکیشن‌تان را اضافه کنید:

~/wordpress/.dockerignore

.env
.git
docker-compose.yml
.dockerignore

وقتی تمام شد فایل را ذخیره و ببندید.

با برقراری اطلاعات حساس‌تان، حالا می‌توانید به تعریف سرویس‌های‌تان در فایل docker-compose.yml بروید.

گام ۳ — تعریف سرویس‌ها با Docker Compose

فایل docker-compose.yml شما شامل تعاریف سرویس برای راه‌اندازی‌تان خواهد بود. سرویس در Compose یعنی کانتینرِ در حال اجرا؛ و تعاریف سرویس اطلاعات نحوه اجرای هر کانتینر را مشخص می‌کنند.

با استفاده از Compose، می‌توانید سرویس‌های مختلفی برای اجرای اپلیکیشن‌های چندکانتینری تعریف کنید؛ چون Compose به شما اجازه می‌دهد این سرویس‌ها را با شبکه‌ها و Volumeهای مشترک به هم لینک کنید. این برای راه‌اندازی فعلی‌تان مفید خواهد بود؛ چون کانتینرهای مختلفی برای دیتابیس، اپلیکیشن وردپرس و وب‌سرور می‌سازید. هم‌چنین کانتینری برای اجرای کلاینت Certbot برای گرفتن گواهی برای وب‌سرورتان می‌سازید.

برای شروع، فایل docker-compose.yml را بسازید و بازش کنید:

nano docker-compose.yml

کد زیر را برای تعریف نسخه فایل Compose و سرویس دیتابیس یعنی db اضافه کنید:

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

تعریف سرویس db شامل گزینه‌های زیر است:

  • image: به Compose می‌گوید چه Imageای برای ساخت کانتینر Pull کند. اینجا Image یعنی mysql:8.0 را Pin کرده‌اید تا از تعارض‌های آینده اجتناب شود؛ چون image یعنی mysql:latest همچنان به‌روزرسانی می‌شود.
  • container_name: این نامی برای کانتینر تعیین می‌کند.
  • restart: این سیاست ری‌استارت کانتینر را تعریف می‌کند. پیش‌فرض no است؛ اما کانتینر را طوری تنظیم کرده‌اید که مگر دستی متوقف شود ری‌استارت شود.
  • env_file: این گزینه به Compose می‌گوید که می‌خواهید متغیرهای محیطی را از فایلی به نام .env—واقع در Build Context خودتان—اضافه کند. در این مورد، Build Context دایرکتوری فعلی‌تان است.
  • environment: این گزینه به شما اجازه افزودن متغیرهای محیطی اضافی—فراتر از آن‌های تعریف‌شده در فایل .env—را می‌دهد. متغیر MYSQL_DATABASE را روی wordpress تنظیم می‌کنید تا نامی برای دیتابیس اپلیکیشن‌تان فراهم شود. چون این اطلاعات غیرحساس است، می‌توانید مستقیم در فایل docker-compose.yml شاملش کنید.
  • volumes: اینجا، Volume نام‌داری به نام dbdata را به دایرکتوری /var/lib/mysql روی کانتینر Mount می‌کنید. این دایرکتوری داده استاندارد MySQL روی بیشتر توزیع‌هاست.
  • command: این گزینه دستوری برای Override کردن دستورالعمل CMD پیش‌فرض image تعیین می‌کند. در این مورد خاص، گزینه‌ای به دستور استاندارد mysqld مربوط به Docker Image—which سرور MySQL را روی کانتینر شروع می‌کند—اضافه می‌کنید. این گزینه یعنی --default-authentication-plugin=mysql_native_password، متغیر سیستمی authentication-plugin– را روی mysql_native_password تنظیم می‌کند؛ که تعیین می‌کند کدام سازوکار احراز هویت باید درخواست‌های احراز هویت جدید به سرور را اداره کند. چون PHP—and بنابراین Image وردپرس شما—پیش‌فرضِ جدیدترِ احراز هویت MySQL را پشتیبانی نمی‌کند، باید این تنظیم را انجام بدهید تا کاربر دیتابیس اپلیکیشن‌تان احراز هویت شود.
  • networks: این تعیین می‌کند که سرویس اپلیکیشن‌تان به شبکه app-network—که در پایین فایل تعریف خواهید کرد—بپیوندد.

بعد، زیر تعریف سرویس db، تعریف سرویس اپلیکیشن وردپرس خودتان را اضافه کنید:

~/wordpress/docker-compose.yml

...
  wordpress:
    depends_on:
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

در این تعریف سرویس، کانتینر را نام‌گذاری و سیاست ری‌استارت تعریف می‌کنید—مثل کاری که با سرویس db کردید. هم‌چنین برخی گزینه‌های خاص این کانتینر را اضافه می‌کنید:

  • depends_on: این گزینه تضمین می‌کند کانتینرهای‌تان به ترتیب وابستگی شروع شوند؛ با شروع کانتینر wordpress بعد از کانتینر db. اپلیکیشن وردپرس شما به وجود دیتابیس و کاربرِ اپلیکیشن وابسته است؛ پس بیان این ترتیب وابستگی امکان شروع درست اپلیکیشن را می‌دهد.
  • image: برای این راه‌اندازی، از Image یعنی 5.1.1-fpm-alpine مربوط به وردپرس استفاده می‌کنید. همان‌طور که در گام ۱ بحث شد، استفاده از این image تضمین می‌کند اپلیکیشن‌تان پردازشگر php-fpm لازمِ Nginx برای مدیریت پردازش PHP را داشته باشد. این هم‌چنین imageای Alpine است—مشتق‌گرفته از پروژه Alpine Linux—که کمک می‌کند حجم کلی image‌تان پایین بماند.
  • env_file: دوباره، تعیین می‌کنید که می‌خواهید مقادیر را از فایل .env بکشید؛ چون اینجا کاربر و رمز عبور دیتابیس اپلیکیشن‌تان را تعریف کردید.
  • environment: اینجا، از مقادیر تعریف‌شده در فایل .env استفاده اما آن‌ها را به نام‌های متغیری که Image وردپرس انتظار دارد تخصیص می‌دهید: WORDPRESS_DB_USER و WORDPRESS_DB_PASSWORD. هم‌چنین WORDPRESS_DB_HOSTای تعریف می‌کنید که سرور MySQLِ اجراشده روی کانتینر db—قابل دسترس روی پورت پیش‌فرض MySQL یعنی 3306—خواهد بود. WORDPRESS_DB_NAME شما همان مقداری خواهد بود که در تعریف سرویس MySQL برای MYSQL_DATABASE تعیین کردید: wordpress.
  • volumes: Volume نام‌داری به نام wordpress را به Mount Point یعنی /var/www/html—ساخته‌شده توسط Image وردپرس—Mount می‌کنید. استفاده از Volume نام‌دار به این شکل به شما اجازه اشتراک کد اپلیکیشن‌تان با کانتینرهای دیگر را می‌دهد.
  • networks: هم‌چنین کانتینر wordpress را به شبکه app-network اضافه می‌کنید.

بعد، زیر تعریف سرویس اپلیکیشن وردپرس، تعریف زیر را برای سرویس Nginx یعنی webserver اضافه کنید:

~/wordpress/docker-compose.yml

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

اینجا، کانتینر را نام‌گذاری و در ترتیب شروع به کانتینر wordpress وابسته‌اش می‌کنید. هم‌چنین از imageای Alpine—یعنی 1.15.12-alpine مربوط به Nginx—استفاده می‌کنید.

این تعریف سرویس هم‌چنین شامل گزینه‌های زیر است:

  • ports: این پورت 80 را افشا می‌کند تا گزینه‌های پیکربندی‌ای که در فایل nginx.conf در گام ۱ تعریف کردید فعال شوند.
  • volumes: اینجا، ترکیبی از Volumeهای نام‌دار و Bind Mountها را تعریف می‌کنید:
    • wordpress:/var/www/html: این کد اپلیکیشن وردپرس شما را به دایرکتوری /var/www/html—دایرکتوری‌ای که به‌عنوان root در Server Block مربوط به Nginx تنظیم کردید—Mount می‌کند.
    • ./nginx-conf:/etc/nginx/conf.d: این دایرکتوری پیکربندی Nginx روی هاست را به دایرکتوری مربوطه روی کانتینر Bind Mount می‌کند؛ و تضمین می‌کند هر تغییری که در فایل‌های هاست بدهید در کانتینر منعکس شود.
    • certbot-etc:/etc/letsencrypt: این گواهی‌ها و کلیدهای مربوطه Let’s Encrypt برای دامنه‌تان را به دایرکتوری مناسب روی کانتینر Mount می‌کند.

هم‌چنین این کانتینر را به شبکه app-network اضافه کرده‌اید.

در نهایت، زیر تعریف webserver خودتان، آخرین تعریف سرویس را برای سرویس certbot اضافه کنید. حتماً آدرس ایمیل و نام‌های دامنه فهرست‌شده اینجا را با اطلاعات خودتان جایگزین کنید:

~/wordpress/docker-compose.yml

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

این تعریف به Compose می‌گوید Image یعنی certbot/certbot را از Docker Hub بکشد. هم‌چنین از Volumeهای نام‌دار برای اشتراک منابع با کانتینر Nginx—including گواهی‌های دامنه و کلید در certbot-etc و کد اپلیکیشن در wordpress—استفاده می‌کند.

دوباره، از depends_on برای تعیین اینکه کانتینر certbot باید وقتی سرویس webserver در حال اجراست شروع شود استفاده کرده‌اید.

هم‌چنین گزینه commandای شامل کرده‌اید که زیردستوری را برای اجرا با دستور پیش‌فرض certbot مربوط به کانتینر تعیین می‌کند. زیردستور certonly گواهی‌ای را با گزینه‌های زیر می‌گیرد:

  • –webroot: به Certbot می‌گوید از پلاگین webroot برای قرار دادن فایل‌ها در پوشه webroot برای احراز هویت استفاده کند. این پلاگین به روش اعتبارسنجی HTTP-01 وابسته است؛ که از درخواست HTTP برای اثبات اینکه Certbot می‌تواند از سروری که به نام دامنه داده‌ای پاسخ می‌دهد به منابع دسترسی پیدا کند استفاده می‌کند.
  • –webroot-path: مسیر دایرکتوری webroot را تعیین می‌کند.
  • –email: ایمیل مورد علاقه برای ثبت و بازیابی.
  • –agree-tos: تعیین می‌کند با توافق‌نامه Subscriber مربوط به ACME موافقید.
  • –no-eff-email: به Certbot می‌گوید که نمی‌خواهید ایمیل‌تان را با بنیاد مرزهای الکترونیکی (EFF) به اشتراک بگذارید. اگر ترجیح می‌دهید، آزادید حذفش کنید.
  • –staging: به Certbot می‌گوید که می‌خواهید از محیط staging مربوط به Let’s Encrypt برای گرفتن گواهی‌های تست استفاده کنید. استفاده از این گزینه به شما اجازه تست گزینه‌های پیکربندی‌تان و اجتناب از محدودیت‌های احتمالی درخواست دامنه را می‌دهد.
  • -d: به شما اجازه تعیین نام‌های دامنه‌ای که می‌خواهید به درخواست‌تان اعمال شوند را می‌دهد. در این مورد، your_domain و www.your_domain را شامل کرده‌اید. حتماً این‌ها را با دامنه خودتان جایگزین کنید.

زیر تعریف سرویس certbot، تعاریف شبکه و Volume خودتان را اضافه کنید:

~/wordpress/docker-compose.yml

...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge

کلید volumes سطح-بالا شما، Volumeهای certbot-etc، wordpress و dbdata را تعریف می‌کند. وقتی داکر Volumeها را می‌سازد، محتوای Volume در دایرکتوری‌ای روی فایل‌سیستم هاست یعنی /var/lib/docker/volumes/—که توسط داکر مدیریت می‌شود—ذخیره می‌شود. محتوای هر Volume سپس از این دایرکتوری به هر کانتینری که از Volume استفاده می‌کند Mount می‌شود. به این شکل، اشتراک کد و داده بین کانتینرها ممکن است.

شبکه Bridge تعریف‌شده-توسط-کاربر یعنی app-network، ارتباط بین کانتینرهای شما را ممکن می‌کند؛ چون روی همان هاست Docker Daemon هستند. این ترافیک و ارتباط درون اپلیکیشن را ساده می‌کند؛ چون همه پورت‌ها بین کانتینرهای روی همان شبکه Bridge را—بدون افشای هیچ پورتی به دنیای بیرون—باز می‌کند. بدین ترتیب، کانتینرهای db، wordpress و webserver شما می‌توانند با هم ارتباط برقرار کنند؛ و شما فقط لازم است پورت 80 را برای دسترسی فرانت-اند به اپلیکیشن افشا کنید.

در زیر، فایل docker-compose.yml به‌طور کامل آمده:

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on:
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge

وقتی ویرایش تمام شد فایل را ذخیره و ببندید.

با برقراری تعاریف سرویس‌تان، آماده شروع کانتینرها و تست درخواست‌های گواهی‌تان هستید.

گام ۴ — دریافت گواهی‌های SSL

کانتینرهای‌تان را با دستور docker-compose up شروع کنید؛ که کانتینرهای‌تان را به ترتیبی که تعیین کرده‌اید می‌سازد و اجرا می‌کند. با افزودن فلگ -d، دستور کانتینرهای db، wordpress و webserver را در پس‌زمینه اجرا می‌کند:

docker-compose up -d

خروجی زیر موفق ساخته‌شدن سرویس‌های‌تان را تأیید می‌کند:

Output
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot   ... done

با docker-compose ps، وضعیت سرویس‌های‌تان را چک کنید:

docker-compose ps

وقتی کامل شد، سرویس‌های db، wordpress و webserver شما Up خواهند بود و کانتینر certbot با پیام وضعیت 0 خارج شده:

Output
  Name                 Command               State           Ports
-------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp
webserver   nginx -g daemon off;             Up       0.0.0.0:80->80/tcp
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp

هر چیزی غیر از Up در ستون State برای سرویس‌های db، wordpress یا webserver—یا وضعیت خروجی غیر از 0 برای کانتینر certbot—یعنی ممکن است لازم باشد لاگ‌های سرویس را با دستور docker-compose logs چک کنید:

docker-compose logs service_name

حالا می‌توانید چک کنید که گواهی‌های‌تان به کانتینر webserver Mount شده‌اند با docker-compose exec:

docker-compose exec webserver ls -la /etc/letsencrypt/live

وقتی درخواست‌های گواهی‌تان موفق شوند، این خروجی است:

Output
total 16
drwx------    3 root     root          4096 May 10 15:45 .
drwxr-xr-x    9 root     root          4096 May 10 15:45 ..
-rw-r--r--    1 root     root           740 May 10 15:45 README
drwxr-xr-x    2 root     root          4096 May 10 15:45 your_domain

حالا که می‌دانید درخواست‌تان موفق خواهد بود، می‌توانید تعریف سرویس certbot را برای حذف فلگ --staging ویرایش کنید.

docker-compose.yml را باز کنید:

nano docker-compose.yml

بخشی از فایل با تعریف سرویس certbot را پیدا کنید و فلگ --staging در گزینه command را با فلگ --force-renewal جایگزین کنید؛ که به Certbot می‌گوید می‌خواهید گواهی جدیدی با همان دامنه‌های گواهی موجود درخواست کنید. در زیر، تعریف سرویس certbot با فلگ به‌روز شده آمده:

~/wordpress/docker-compose.yml

...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...

حالا می‌توانید docker-compose up را برای بازسازی کانتینر certbot اجرا کنید. هم‌چنین گزینه --no-deps را شامل می‌کنید تا به Compose بگویید می‌تواند شروع سرویس webserver را رد کند؛ چون از قبل در حال اجراست:

docker-compose up --force-recreate --no-deps certbot

خروجی زیر نشان می‌دهد درخواست گواهی‌تان موفق بوده:

Output
Recreating certbot ... done
Attaching to certbot
certbot      | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot      | Plugins selected: Authenticator webroot, Installer None
certbot      | Renewing an existing certificate
certbot      | Performing the following challenges:
certbot      | http-01 challenge for your_domain
certbot      | http-01 challenge for www.your_domain
certbot      | Using the webroot path /var/www/html for all unmatched domains.
certbot      | Waiting for verification...
certbot      | Cleaning up challenges
certbot      | IMPORTANT NOTES:
certbot      |  - Congratulations! Your certificate and chain have been saved at:
certbot      |    /etc/letsencrypt/live/your_domain/fullchain.pem
certbot      |    Your key file has been saved at:
certbot      |    /etc/letsencrypt/live/your_domain/privkey.pem
...
certbot exited with code 0

با برقراری گواهی‌های‌تان، می‌توانید به تغییر پیکربندی Nginx برای شامل کردن SSL بروید.

گام ۵ — تغییر پیکربندی و تعریف سرویس وب‌سرور

فعال کردن SSL در پیکربندی Nginx شما شامل افزودن ریدایرکت HTTP به HTTPS، تعیین مکان‌های گواهی و کلید SSL شما، و افزودن پارامترها و هدرهای امنیتی خواهد بود.

چون قصد بازسازی سرویس webserver برای شامل کردن این افزودنی‌ها را دارید، الان می‌توانید متوقفش کنید:

docker-compose stop webserver

قبل از تغییر فایل پیکربندی، پارامتر امنیتی توصیه‌شده Nginx را از Certbot با curl بگیرید:

curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf

این دستور این پارامترها را در فایلی به نام options-ssl-nginx.conf—واقع در دایرکتوری nginx-conf—ذخیره می‌کند.

بعد، فایل پیکربندی Nginxای که قبلاً ساختید را حذف کنید:

rm nginx-conf/nginx.conf

نسخه دیگری از فایل بسازید و بازش کنید:

nano nginx-conf/nginx.conf

کد زیر را به فایل اضافه کنید تا HTTP به HTTPS ریدایرکت و اعتبارنامه‌ها، پروتکل‌ها و هدرهای امنیتی SSL اضافه شوند. یادتان باشد your_domain را با دامنه خودتان جایگزین کنید:

~/wordpress/nginx-conf/nginx.conf

server {
        listen 80;
        listen [::]:80;

        server_name your_domain www.your_domain;

        location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
        }

        location / {
                rewrite ^ https://$host$request_uri? permanent;
        }
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name your_domain www.your_domain;

        index index.php index.html index.htm;

        root /var/www/html;

        server_tokens off;

        ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

        include /etc/nginx/conf.d/options-ssl-nginx.conf;

        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
        add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
        # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        # فقط وقتی پیامدهایش را می‌فهمید strict transport security را فعال کنید

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location ~ /\.ht {
                deny all;
        }

        location = /favicon.ico {
                log_not_found off; access_log off;
        }
        location = /robots.txt {
                log_not_found off; access_log off; allow all;
        }
        location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
                expires max;
                log_not_found off;
        }
}

Server Block مربوط به HTTP، webroot برای درخواست‌های تمدید Certbot به دایرکتوری acme-challenge/.well-known را تعیین می‌کند. هم‌چنین دایرکتیو rewriteای را شامل می‌شود که درخواست‌های HTTP به دایرکتوری ریشه را به HTTPS هدایت می‌کند.

Server Block مربوط به HTTPS، ssl و http2 را فعال می‌کند. برای خواندن بیشتر درباره نحوه ارتقای HTTP/2 روی پروتکل‌های HTTP و مزایایی که می‌تواند برای کارایی وب‌سایت داشته باشد، لطفاً مقدمه راهنمای «راه‌اندازی Nginx با پشتیبانی HTTP/2 روی اوبونتو 22.04» در پارمین کلود را بخوانید.

این بلاک هم‌چنین مکان‌های گواهی و کلید SSL شما—به‌همراه پارامترهای امنیتی توصیه‌شده Certbot که در nginx-conf/options-ssl-nginx.conf ذخیره کردید—را شامل می‌شود.

علاوه بر این، برخی هدرهای امنیتی شامل شده‌اند که به شما امتیازهای A در چیزهایی مثل سایت‌های تست SSL Labs و Security Headers می‌دهند. این هدرها شامل X-Frame-Options، X-Content-Type-Options، Referrer Policy، Content-Security-Policy و X-XSS-Protection هستند. هدر HTTP Strict Transport Security (HSTS) کامنت شده—این را فقط وقتی فعال کنید که پیامدهایش را بفهمید و قابلیت «preload»‌اش را ارزیابی کرده باشید.

دایرکتیوهای root و index شما هم در این بلاک قرار دارند؛ مثل بقیه بلاک‌های location خاص-وردپرسی که در گام ۱ بحث شد.

وقتی ویرایش تمام شد، فایل را ذخیره و ببندید.

قبل از بازسازی سرویس webserver، لازم است نگاشت پورت 443 را به تعریف سرویس webserver خودتان اضافه کنید.

فایل docker-compose.yml خودتان را باز کنید:

nano docker-compose.yml

در تعریف سرویس webserver، نگاشت پورت زیر را اضافه کنید:

~/wordpress/docker-compose.yml

...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

در زیر، فایل کامل docker-compose.yml بعد از ویرایش‌ها آمده:

~/wordpress/docker-compose.yml

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress:
    depends_on:
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain

volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
  app-network:
    driver: bridge

وقتی ویرایش تمام شد فایل را ذخیره و ببندید.

سرویس webserver را بازسازی کنید:

docker-compose up -d --force-recreate --no-deps webserver

سرویس‌های‌تان را با docker-compose ps چک کنید:

docker-compose ps

خروجی باید نشان بدهد سرویس‌های db، wordpress و webserver شما در حال اجرایند:

Output
  Name                 Command               State                     Ports
----------------------------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp
webserver   nginx -g daemon off;             Up       0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp

با در حال اجرا بودن کانتینرهای‌تان، می‌توانید نصب وردپرس‌تان را از طریق رابط وب کامل کنید.

گام ۶ — تکمیل نصب از طریق رابط وب

با در حال اجرا بودن کانتینرهای‌تان، نصب را از طریق رابط وب وردپرس تمام کنید.

در مرورگر وب خودتان، به دامنه سرورتان بروید. یادتان باشد your_domain را با نام دامنه خودتان جایگزین کنید:

https://your_domain

زبانی که می‌خواهید استفاده کنید را انتخاب کنید:

انتخابگر زبان وردپرس

بعد از کلیک روی Continue، به صفحه اصلی راه‌اندازی می‌رسید؛ جایی که لازم است نامی برای سایت‌تان و نام کاربری انتخاب کنید. انتخاب نام کاربری به‌یادماندنی اینجا ایده خوبی است (به‌جای «admin») به‌همراه رمز عبور قوی. می‌توانید از رمز عبوری که وردپرس خودکار تولید می‌کند استفاده کنید یا خودتان بسازید.

در نهایت، لازم است آدرس ایمیل‌تان را وارد و تصمیم بگیرید که می‌خواهید موتورهای جستجو از Index کردن سایت‌تان منصرف شوند یا نه:

صفحه راه‌اندازی اصلی وردپرس

کلیک روی Install WordPress در پایین صفحه، شما را به پرامپت ورود می‌برد:

صفحه ورود وردپرس

بعد از ورود، به داشبورد مدیریتی وردپرس دسترسی خواهید داشت:

داشبورد مدیریت وردپرس

با تکمیل نصب وردپرس، می‌توانید قدم‌هایی برای اطمینان از تمدید خودکار گواهی‌های SSL بردارید.

گام ۷ — تمدید گواهی‌ها

گواهی‌های Let’s Encrypt برای ۹۰ روز معتبرند. می‌توانید فرایند تمدید خودکاری راه بیندازید تا مطمئن شوید منقضی نمی‌شوند. راهی برای این کار، ساخت Jobای با ابزار زمان‌بندی cron است. در مثال زیر، Cron Jobای می‌سازید که دوره‌ای اسکریپتی را اجرا کند تا گواهی‌های‌تان را تمدید و پیکربندی Nginx را Reload کند.

اول، اسکریپتی به نام ssl_renew.sh را باز کنید:

nano ssl_renew.sh

کد زیر را به اسکریپت اضافه کنید تا گواهی‌های‌تان تمدید و پیکربندی وب‌سرورتان Reload شود. یادتان باشد نام کاربری نمونه اینجا را با نام کاربری غیر root خودتان جایگزین کنید:

~/wordpress/ssl_renew.sh

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af

این اسکریپت اول باینری docker-compose را به متغیری به نام COMPOSE تخصیص می‌دهد و گزینه --no-ansi را تعیین می‌کند؛ که دستورات docker-compose را بدون کاراکترهای کنترلی ANSI اجرا می‌کند. سپس همین کار را با باینری docker می‌کند. در نهایت، به دایرکتوری پروژه ~/wordpress تغییر می‌دهد و دستورات docker-compose زیر را اجرا می‌کند:

  • docker-compose run: این کانتینر certbot را شروع و دستورِ تأمین‌شده در تعریف سرویس certbot شما را Override می‌کند. به‌جای استفاده از زیردستور certonly، از زیردستور renew استفاده می‌شود؛ که گواهی‌های نزدیک به انقضا را تمدید می‌کند. هم‌چنین گزینه --dry-run برای تست اسکریپت‌تان شامل شده است.
  • docker-compose kill: این سیگنال SIGHUP را به کانتینر webserver می‌فرستد تا پیکربندی Nginx را Reload کند.

سپس docker system prune را اجرا می‌کند تا همه کانتینرها و Imageهای بلااستفاده حذف شوند.

وقتی ویرایش تمام شد فایل را ببندید. با دستور زیر قابل اجرایش کنید:

chmod +x ssl_renew.sh

بعد، فایل crontab مربوط به root خودتان را باز کنید تا اسکریپت تمدید در بازه مشخصی اجرا شود:

sudo crontab -e

اگر اولین‌بار است این فایل را ویرایش می‌کنید، از شما خواسته می‌شود ویرایشگری انتخاب کنید:

Output
no crontab for root - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]:
...

در انتهای این فایل، خط زیر را اضافه کنید:

crontab
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1

این بازه Job را روی هر پنج دقیقه تنظیم می‌کند تا بتوانید تست کنید درخواست تمدیدتان طبق موردنظر کار کرده یا نه. فایل لاگی به نام cron.log برای ثبت خروجی مربوطه از Job ساخته می‌شود.

بعد از پنج دقیقه، cron.log را برای تأیید موفق بودن یا نبودن درخواست تمدید چک کنید:

tail -f /var/log/cron.log

خروجی زیر تمدید موفق را تأیید می‌کند:

Output
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/your_domain/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

با تایپ CTRL+C در ترمینال‌تان از آن خارج شوید.

می‌توانید فایل crontab را برای تنظیم بازه روزانه تغییر دهید. مثلاً برای اجرای اسکریپت هر روز ساعت ظهر، خط آخر فایل را مثل زیر تغییر می‌دهید:

crontab
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1

هم‌چنین می‌خواهید گزینه --dry-run را از اسکریپت ssl_renew.sh خودتان حذف کنید:

~/wordpress/ssl_renew.sh

#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af

Cron Job شما تضمین می‌کند گواهی‌های Let’s Encrypt شما با تمدید وقتی واجد شرایط‌اند منقضی نشوند. هم‌چنین می‌توانید چرخش لاگ را با ابزار Logrotate روی اوبونتو برای چرخاندن و فشرده کردن فایل‌های لاگ‌تان راه بیندازید.

سوالات متداول

۱. چرا باید از Docker Compose برای وردپرس استفاده کنم؟

استفاده از Docker Compose فرایند نصب وردپرس را ساده می‌کند. به‌جای نصب دستی استک LAMP (لینوکس، Apache، MySQL، PHP) یا LEMP (لینوکس، Nginx، MySQL، PHP)، می‌توانید کل محیط چندکانتینری‌تان را در فایل docker-compose.yml منفردی تعریف کنید. این فایل همه سرویس‌هایی را که اپلیکیشن‌تان لازم دارد هماهنگ می‌کند؛ در این مورد: دیتابیس MySQL، اپلیکیشن وردپرس و وب‌سرور Nginx. این روش کمتر زمان‌بر است و به شما اجازه استاندارد کردن راه‌اندازی با Imageهای از-پیش-ساخته‌شده را می‌دهد.

۲. وب‌سرور Nginx و اپلیکیشن وردپرس چگونه متصل می‌شوند؟

کانتینر وب‌سرور Nginx و کانتینر wordpress از طریق شبکه Bridge سفارشیِ تعریف‌شده در فایل Compose—به نام app-network—متصل می‌شوند. این شبکه به کانتینرها اجازه ارتباط امن را می‌دهد. پیکربندی Nginx یعنی (nginx.conf) طوری تنظیم شده که پردازش PHP را با Proxy کردن درخواست‌ها مدیریت کند. مشخصاً، هر درخواستِ منطبق با \.php$ با استفاده از دایرکتیو fastcgi_pass wordpress:9000; به کانتینر wordpress پاس می‌شود. این کار می‌کند؛ چون کانتینر wordpress در حال اجرای Image یعنی wordpress:5.1.1-fpm-alpine است؛ که پردازشگر php-fpm لازمِ Nginx را شامل می‌شود.

۳. این راه‌اندازی چگونه اطلاعات حساسی مثل رمزهای عبور دیتابیس را مدیریت می‌کند؟

این راه‌اندازی اطلاعات حساس را با جداسازی‌اش از پیکربندی اصلی امن مدیریت می‌کند. همه اعتبارنامه‌ها—مثل MYSQL_ROOT_PASSWORD، MYSQL_USER و MYSQL_PASSWORD—در فایل .env ذخیره می‌شوند. سپس سرویس‌های db و wordpress در فایل docker-compose.yml با استفاده از دایرکتیو env_file: .env به این فایل ارجاع می‌دهند. این از Hard-code شدن، افشای عمومی یا Commit تصادفی داده‌های حساس به مخزن Git جلوگیری می‌کند. برای تقویت بیشتر، tutorial افزودن .env به فایل‌های .gitignore و .dockerignore را توصیه می‌کند.

۴. فرایند دریافت گواهی SSL چیست؟

این راه‌اندازی از کانتینر اختصاصی certbot برای گرفتن گواهی از Let’s Encrypt استفاده می‌کند.

  • تست اولیه: اول، docker-compose up -d را اجرا می‌کنید. سرویس certbot در فایل docker-compose.yml ابتدا شامل فلگ --staging است. این به Certbot می‌گوید گواهی تستی از محیط staging مربوط به Let’s Encrypt درخواست کند؛ که به شما کمک می‌کند از محدودیت‌های نرخ اجتناب و در عین حال از صحت پیکربندی‌تان مطمئن شوید.
  • تأیید: گواهی تستی ساخته‌شده را با چک کردن دایرکتوری /etc/letsencrypt/live کانتینر webserver تأیید می‌کنید.
  • گواهی واقعی: وقتی موفقیت تست را تأیید کردید، دستور سرویس certbot در فایل docker-compose.yml خودتان را تغییر می‌دهید. فلگ --staging را حذف و --force-renewal اضافه می‌کنید.
  • درخواست نهایی: سپس docker-compose up --force-recreate --no-deps certbot را اجرا می‌کنید تا کانتینر certbot قدیمی متوقف، با دستور جدید بازسازی و گواهی واقعیِ آماده-پروداکشن درخواست شود.

۵. گواهی‌های SSL چگونه خودکار تمدید می‌شوند؟

اسکریپت Shellای به نام ssl_renew.sh روی ماشین هاست برای خودکارسازی فرایند تمدید ساخته می‌شود. این اسکریپت:

  • به دایرکتوری پروژه (~/wordpress) تغییر می‌دهد.
  • $COMPOSE run certbot renew را برای چک اینکه گواهی‌ها نزدیک انقضا هستند و در صورت لزوم تمدیدشان اجرا می‌کند.
  • $COMPOSE kill -s SIGHUP webserver را برای فرستادن سیگنال SIGHUP به کانتینر Nginx اجرا می‌کند؛ که پیکربندی‌اش را با ظرافت Reload و استفاده از گواهی جدید را شروع می‌کند.

سپس این اسکریپت با افزودن به فایل crontab مربوط به root—که اجرایش را در بازه تعریف‌شده‌ای (مثلاً روزانه) تنظیم می‌کند—زمان‌بندی می‌شود تا خودکار اجرا شود.

۶. آیا با توقف کانتینرها، دیتابیس و فایل‌های وردپرسم را از دست می‌دهم؟

نه، این راه‌اندازی برای ماندگاری داده با Volumeهای نام‌دار طراحی شده است.

  • Volume یعنی dbdata به /var/lib/mysql در کانتینر db Mount می‌شود؛ و همه فایل‌های دیتابیس MySQL شما را ذخیره می‌کند.
  • Volume یعنی wordpress به /var/www/html در هر دوی کانتینرهای wordpress و webserver Mount می‌شود؛ و فایل‌های Core وردپرس، قالب‌ها، پلاگین‌ها و آپلودهای شما را ذخیره می‌کند.
  • Volume یعنی certbot-etc گواهی‌های SSL شما را ذخیره می‌کند.

این Volumeها توسط داکر روی فایل‌سیستم هاست مدیریت می‌شوند و مستقل از چرخه حیات کانتینرند. یعنی می‌توانید کانتینرها را بدون از دست دادن هیچ‌کدام از داده‌های‌تان متوقف، حذف یا بازسازی کنید.

۷. هدف دستور در تعریف سرویس db چیست؟

سرویس db از Image یعنی mysql:8.0 استفاده می‌کند؛ که روش احراز هویت پیش‌فرض جدیدتری دارد. Image وردپرس—which به PHP متکی است—این روش جدید را پشتیبانی نمی‌کند.

برای رفع این مسئله سازگاری، دایرکتیو command: '--default-authentication-plugin=mysql_native_password' به تعریف سرویس db اضافه می‌شود. این دستور پیش‌فرض image را Override کرده و به سرور MySQL می‌گوید از پلاگین احراز هویت قدیمی‌تر و سازگارِ mysql_native_password استفاده کند؛ که به وردپرس اجازه اتصال موفق به دیتابیس را می‌دهد.

۸. کانتینر Nginx چگونه گواهی‌های SSL را از کانتینر Certbot می‌گیرد؟

هر دوی کانتینرهای webserver (یعنی Nginx) و certbot، Volume نام‌داری به نام certbot-etc را شریک می‌شوند.

  • در سرویس certbot، این Volume به /etc/letsencrypt Mount می‌شود. وقتی Certbot گواهی‌ها را می‌گیرد، آن‌ها را در این دایرکتوری می‌نویسد.
  • در سرویس webserver، همین Volume هم به /etc/letsencrypt Mount می‌شود.

چون هر دو کانتینر همان Volume را Mount می‌کنند، کانتینر webserver دسترسی فوری به گواهی‌هایی که Certbot ایجاد کرده دارد.


نکته درباره میرور پارمین کلود: اگر در ایران هستید و Pull کردن مستقیم Imageها از Docker Hub کند یا ناموفق است، می‌توانید Imageهای این tutorial (مثل mysql، wordpress، nginx و certbot) را از میرور رجیستری پارمین کلود (hub.cr.parmincloud.ir) بکشید. برای این کار کافی است نام Imageها را در فایل docker-compose.yml با پیشوند میرور بنویسید؛ مثلاً به‌جای image: mysql:8.0 از image: hub.cr.parmincloud.ir/library/mysql:8.0 استفاده کنید.


نتیجه‌گیری

در این tutorial، نصب چندکانتینریِ وردپرس با Docker Compose را کامل کردید. کانتینرهای شما شامل دیتابیس MySQL، اپلیکیشن وردپرس با PHP-FPM، وب‌سرور Nginx و کلاینت Certbot برای گواهی‌های SSL بودند. شما تونستید:

  • پیکربندی وب‌سرور Nginx را با بلاک‌های location خاص-وردپرس تعریف کنید
  • متغیرهای محیطی حساس را در فایل .env امن نگه دارید
  • سرویس‌ها را در فایل docker-compose.yml تعریف و با شبکه Bridge مشترک متصل کنید
  • گواهی‌های SSL را از Let’s Encrypt—اول با staging و بعد واقعی—بگیرید
  • نصب وردپرس را از طریق رابط وب کامل کنید
  • تمدید خودکار گواهی‌ها را با اسکریپت و Cron Job راه بیندازید

حالا یک سایت وردپرس کاملاً عملیاتی با SSL و تمدید خودکار دارید که همه اجزایش در کانتینرهای ایزوله اجرا می‌شوند و داده‌هایش با Volumeهای نام‌دار ماندگارند.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا