چگونه Full Strict SSL کلودفلر را برای وب‌سایت داکری فعال کنیم: 3 گام تا رسیدن به امنیت واقعی


در این آموزش یاد می‌گیریم که چگونه SSL Full Strict در داکر را برای وردپرس فعال کنیم. در دو یادداشت قبلی، مسیر راه‌اندازی وردپرس با داکر را بررسی کردیم و دیدیم چطور می‌توان با استفاده از فایل .env امنیت متغیرهای حساس سایت را تا حد زیادی تأمین کرد. با این حال، هنوز یک قطعه‌ی مهم از پازل امنیت باقی مانده است: امنیت در مسیر انتقال داده‌ها (Transport Layer Security – TLS).

چرا به SSL Full Strict در داکر نیاز داریم؟

اگر از Cloudflare استفاده می‌کنید و تنظیمات SSL را روی حالت Flexible گذاشته‌اید، باید بدانید ارتباط بین مرورگر کاربر و Cloudflare امن است. اما ارتباط بین Cloudflare و سرور شما همچنان به‌صورت ناامن (HTTP) برقرار می‌شود. راه حل أن
SSL Full Strict در داکر است، به همین دلیل تصمیم گرفتم این حفره‌ی امنیتی را در سایت خودم که با وردپرس پیاده‌سازی شده است، با استفاده از حالت Full (Strict) ببندم.

در این نوشته، روش دقیق انجام این کار را بدون استفاده از هیچ پلاگینی و صرفاً از طریق Docker توضیح می‌دهم. در حالت Full (Strict)، Cloudflare برای برقراری ارتباط با سرور شما به یک گواهی SSL معتبر نیاز دارد. من در این راهنما از گواهی‌های Cloudflare Origin CA استفاده می‌کنم؛ گواهی‌هایی که مخصوص ارتباط Cloudflare با سرور هستند و دردسر تمدید سالانه هم ندارند.

گام اول: دریافت گواهی از کلادفلر

  1. وارد پنل Cloudflare شوید و به مسیر SSL/TLS → Origin Server بروید.
  2. روی دکمه‌ی Create Certificate کلیک کنید.
  3. در این مرحله دو بخش به شما نمایش داده می‌شود:
  • Origin Certificate
    این بخش شامل گواهی SSL (کلید عمومی) است که با عبارت -----BEGIN CERTIFICATE----- شروع می‌شود.
  • Private Key
    این بخش شامل کلید خصوصی شماست و با عبارت -----BEGIN PRIVATE KEY----- شروع می‌شود.

محتوای این دو بخش را به‌ترتیب در دو فایل با نام‌های زیر ذخیره کنید:

  • cert.pem (کلید عمومی)
  • key.pem (کلید خصوصی)

استفاده از این نام‌ها یک استاندارد رایج است؛ به‌خصوص اگر از Nginx یا Docker استفاده می‌کنید.

4. این دو فایل را در پوشه‌ی اصلی پروژه‌ی Docker خود (در کنار فایل docker-compose.yml) قرار دهید.

Open terminal:
ctrl + t

nano cert.pem
nano key.pem

press Ctrl + O (Write Out) to save your changes to the current file, then press Enter to confirm the filename.

موارد ضروری مرتبط با Cloudflare و مانت کردن گواهی‌ها

وقتی از Cloudflare استفاده می‌کنیم و می‌خواهیم حالت SSL Full Strict در داکر را فعال کنیم، وب‌سرور ما باید یک گواهی معتبر داشته باشد تا Cloudflare بتواند به‌صورت امن با آن ارتباط برقرار کند.
در Docker، برای اینکه Apache داخل کانتینر به گواهی‌ها دسترسی داشته باشد، آن‌ها را از سیستم میزبان Mount می‌کنیم. یعنی فایل‌های cert.pem و key.pem روی مسیر مشخصی در کانتینر قرار می‌گیرن تا Apache بتونه از آن‌ها استفاده کنه.

نکته: Mount کردن به این معناست که فایل‌ها داخل کانتینر کپی نمی‌شوند بلکه کانتینر مستقیماً از همان مسیر روی سیستم شما استفاده می‌کند. این روش باعث می‌شود مدیریت گواهی‌ها راحت‌تر و امن‌تر باشد.

فعال‌سازی SSL در Apache

وقتی فایل‌های گواهی را Mount کردیم، باید Apache را تنظیم کنیم تا از آن‌ها استفاده کند.
در این فایل docker-compose.yml، با دستور sed مسیر گواهی‌های پیش‌فرض (snakeoil) را به مسیر گواهی‌های واقعی ما تغییر می‌دهیم، سپس ماژول‌های SSL و HTTP/2 را فعال می‌کنیم و سایت SSL را راه‌اندازی می‌کنیم. به زبان ساده: به Apache می‌گوییم «این گواهی‌ها را استفاده کن و اتصال امن برقرار کن».

تفاوت این روش با Flexible SSL

حالتنحوه ارتباط
Flexibleمرورگر ↔ Cloudflare امن است، اما Cloudflare ↔ سرور شما ناامن (HTTP)
Full (Strict)مرورگر ↔ Cloudflare امن + Cloudflare ↔ سرور شما هم کاملاً امن (HTTPS)

به همین دلیل، حالت Flexible فقط برای تست مناسب است!

گام دوم: به‌روزرسانی Docker Compose

برای اینکه وب‌سرور آپاچی داخل کانتینر بتواند از این گواهی‌ها استفاده کند، باید آن‌ها را به کانتینر “Mount” کنیم و تنظیمات آپاچی را تغییر دهیم. محتویات فایل docker-compose.yml را ابتدا به طور کامل می‌گذارم سپس خطوط مرتبط با سرتیفیکیت و کلادفلر و SSL Full Strict در داکر را توضیح میدم.

فایل docker-compose.yml برای مشاهده محتویات فایل کلیک کنید
services:
  db:
    image: mariadb:10.11
    restart: always
    volumes:
      - ./db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  wordpress:
    depends_on:
      - db
    image: wordpress:6.9-php8.2-apache
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      - WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST}
      - WORDPRESS_DB_USER=${WORDPRESS_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
      - WORDPRESS_DB_NAME=${WORDPRESS_DB_NAME}
    volumes:
      - ./wp_content:/var/www/html
      - ./cert.pem:/etc/apache2/ssl/cert.pem:ro
      - ./key.pem:/etc/apache2/ssl/key.pem:ro
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    command: >
      sh -c "sed -i 's|/etc/ssl/certs/ssl-cert-snakeoil.pem|/etc/apache2/ssl/cert.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             sed -i 's|/etc/ssl/private/ssl-cert-snakeoil.key|/etc/apache2/ssl/key.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             a2enmod ssl &&
             a2enmod http2 &&
             a2ensite default-ssl &&
             apache2-foreground"


توضیح خطوط مرتبط با SSL در Docker Compose

در ادامه، فایل docker-compose.yml را فقط خطوط مرتبط با SSL Full Strict در داکر و Cloudflare به‌صورت خط‌به‌خط و ساده توضیح می‌دهم.

  wordpress:
    volumes:
      - ./wp_content:/var/www/html
      - ./cert.pem:/etc/apache2/ssl/cert.pem:ro
      - ./key.pem:/etc/apache2/ssl/key.pem:ro
    ports:
      - "80:80"
      - "443:443"
    command: >
      sh -c "sed -i 's|/etc/ssl/certs/ssl-cert-snakeoil.pem|/etc/apache2/ssl/cert.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             sed -i 's|/etc/ssl/private/ssl-cert-snakeoil.key|/etc/apache2/ssl/key.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             a2enmod ssl &&
             a2enmod http2 &&
             a2ensite default-ssl &&
             apache2-foreground"

Volumes

      - ./cert.pem:/etc/apache2/ssl/cert.pem:ro
      - ./key.pem:/etc/apache2/ssl/key.pem:ro

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

مسیر سمت چپ (./cert.pem) مسیر روی سیستم شماست، مسیر سمت راست (/etc/apache2/ssl/cert.pem) مسیر داخل کانتینر است.

عبارت :ro یعنی read-only، کانتینر نمیتونه فایل را تغییر بده؛ فقط میتواند از آن استفاده کند. بدون این Mount، Apache داخل کانتینر به گواهی دسترسی نخواهد داشت و SSL کار نمی‌کند.

Ports

      - "80:80"
      - "443:443"

80 برای HTTP و 443 برای HTTPS است.

بدون پورت 443، حتی اگر SSL فعال باشد، مرورگرها نمی‌توانند با HTTPS به سایت وصل شوند.

Command

      sh -c "sed -i 's|/etc/ssl/certs/ssl-cert-snakeoil.pem|/etc/apache2/ssl/cert.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             sed -i 's|/etc/ssl/private/ssl-cert-snakeoil.key|/etc/apache2/ssl/key.pem|g' /etc/apache2/sites-available/default-ssl.conf &&
             a2enmod ssl &&
             a2enmod http2 &&
             a2ensite default-ssl &&
             apache2-foreground"
  • خط اول و دوم (sed -i) مسیر گواهی‌های پیش‌فرض snakeoil را با مسیر گواهی‌های واقعی شما جایگزین می‌کند.
  • a2enmod ssl → ماژول SSL را فعال می‌کند.
  • a2enmod http2 → HTTP/2 را فعال می‌کند (سرعت و امنیت بهتر).
  • a2ensite default-ssl → سایت پیش‌فرض SSL را فعال می‌کند.
  • apache2-foreground → Apache را در foreground اجرا می‌کند تا کانتینر فعال بماند.

به زبان ساده: این دستور به Apache می‌گوید:

گواهی‌های واقعی من را استفاده کن، SSL و HTTP/2 را فعال کن و سایت رو با HTTPS بالا بیار.

گام سوم: هماهنگی با Reverse Proxy و Cloudflare


همان‌طور که می‌دانید، وردپرس پشت پروکسی معکوس کلادفلر ممکن است در تشخیص پروتکل دچار مشکل شود و در حلقه ریدایرکت (Redirect Loop) بیفتد. برای حل این مشکل و ایجاد قابلیت SSL Full Strict در داکر کدهای زیر را به ابتدای فایل wp-config.php اضافه کردم تا وردپرس بفهمد ترافیک از سمت یک پروکسی امن می‌آید:

نسخه نمونه فایل wp-config.php (برای مشاهده محتویات فایل کلیک کنید). این فایل نمونه آموزشی است و فقط شامل این موارد است:
تنظیمات دیتابیس (Docker)
Cloudflare / Reverse Proxy
SSL و HTTPS.
توجه: این نسخه‌ی wp-config.php عمداً به‌صورت خلاصه تهیه شده و فقط شامل تنظیمات مرتبط با Docker، Cloudflare، Reverse Proxy و SSL Full Strict در داکر است.
سایر تنظیمات وردپرس (مانند کش، دیباگ یا افزونه‌ها) برای جلوگیری از سردرگمی در این مثال حذف شده‌اند.

<?php
/**
 * Minimal wp-config.php example
 * Docker + Cloudflare SSL Full (Strict)
 */

// -----------------------------------------------------------------------------
// Helper function for Docker environment variables
// -----------------------------------------------------------------------------
if (!function_exists('getenv_docker')) {
	function getenv_docker($env, $default) {
		if ($fileEnv = getenv($env . '_FILE')) {
			return rtrim(file_get_contents($fileEnv), "\r\n");
		} elseif (($val = getenv($env)) !== false) {
			return $val;
		}
		return $default;
	}
}

// -----------------------------------------------------------------------------
// Database configuration (via Docker environment variables)
// -----------------------------------------------------------------------------
define('DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'wordpress'));
define('DB_USER', getenv_docker('WORDPRESS_DB_USER', 'wordpress'));
define('DB_PASSWORD', getenv_docker('WORDPRESS_DB_PASSWORD', 'password'));
define('DB_HOST', getenv_docker('WORDPRESS_DB_HOST', 'db'));
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');

// -----------------------------------------------------------------------------
// Cloudflare + Reverse Proxy + SSL Full (Strict)
// -----------------------------------------------------------------------------

// Detect HTTPS behind Cloudflare to prevent redirect loops
if (
	isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
	$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'
) {
	$_SERVER['HTTPS'] = 'on';
}

// Force HTTPS for WordPress admin panel
define('FORCE_SSL_ADMIN', true);

// Force HTTPS URLs (example domain)
if (isset($_SERVER['HTTP_HOST']) && strpos($_SERVER['HTTP_HOST'], 'example.com') !== false) {
	define('WP_HOME', 'https://example.com');
	define('WP_SITEURL', 'https://example.com');
}

// -----------------------------------------------------------------------------
// WordPress bootstrap
// -----------------------------------------------------------------------------
if (!defined('ABSPATH')) {
	define('ABSPATH', __DIR__ . '/');
}

require_once ABSPATH . 'wp-settings.php';

توضیح خط‌به‌خط فایل نمونه wp-config.php

تنظیمات دیتابیس

define('DB_NAME', getenv_docker(...));
define('DB_USER', getenv_docker(...));
define('DB_PASSWORD', getenv_docker(...));
define('DB_HOST', getenv_docker(...));

این بخش اطلاعات اتصال وردپرس به دیتابیس را مشخص می‌کند. در این ساختار، مقادیر از طریق متغیرهای محیطی Docker تأمین می‌شوند و داخل فایل ذخیره نمی‌شوند؛ به این شکل، اطلاعات حساس (مثل رمز عبور دیتابیس) از سورس‌کد جدا می‌مانند.

تشخیص HTTPS پشت Cloudflare (مهم‌ترین بخش)

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
    $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Cloudflare درخواست‌ها را با HTTPS از کاربر دریافت می‌کند، اما معمولاً آن‌ها را با HTTP به سرور مبدا (Origin) ارسال می‌کند. این کد به وردپرس اعلام می‌کند که: «درخواست اصلی کاربر امن بوده است که به دلیل فعال بودن SSL Full Strict در داکر است» و در نهایت از بروز مشکلاتی مثل Redirect Loop جلوگیری می‌کند.

اجبار SSL برای پنل مدیریت وردپرس

define('FORCE_SSL_ADMIN', true);

با این تنظیم:

  • پنل مدیریت وردپرس (/wp-admin) همیشه از HTTPS استفاده می‌کند که به دلیل راه اندازی SSL Full Strict در داکر است.
  • حتی اگر وردپرس به‌اشتباه HTTP را تشخیص دهد

اجبار HTTPS برای آدرس سایت

define('WP_HOME', 'https://iBijan.com');
define('WP_SITEURL', 'https://iBijan.com');

این خطوط باعث می‌شوند:

  • آدرس اصلی سایت و وردپرس همیشه HTTPS باشد
  • از مشکلاتی مثل mixed content یا ریدایرکت‌های ناخواسته جلوگیری شود

گام نهایی

پس از اعمال تنظیمات در فایل‌های بالا (docker-compose.yml و wp-config.php)، دستور زیر را در ترمینال اجرا کنید تا تغییرات اعمال شوند:

docker compose up -d 

بعد از اطمینان از بالا آمدن سایت و در دسترس بودن آن از طریق HTTPS و فراهم شدن قابلیت SSL Full Strict در داکر، به پنل Cloudflare برگردید و وضعیت SSL را از حالت Flexible به Full (Strict) تغییر دهید. در این مرحله، ارتباط بین کاربر، Cloudflare و سرور مبدا به‌صورت کامل و امن برقرار شده است و تمام مسیر انتقال داده‌ها تحت TLS محافظت می‌شود. سپس برای چک کردن فعال بودن سرتیفیکیت که آن را در تنظیمات کلادفلر ۱۵ ساله ست کردیم دستور زیر را در ترمینال میزنیم. توجه داشته باشید باید با دستور cd وارد پوشه ای شوید که کلید عمومی و خصوصی کلادفلر را در آن ذخیره کرده اید:

openssl x509 -in cert.pem -text -noout | grep -A 2 "Validity"

همانطور که در تصویر مشخص است تاریخ انقضای ۱۵ ساله گواهی کلادفلر در خروجی ترمینال کاملا واضح است:

خلاصه موارد گفته شده

  1. فایل‌های cert.pem و key.pem را از Cloudflare Origin CA دریافت و در پروژه Docker ذخیره کنید تا SSL Full Strict در داکر فعال شود
  2. docker-compose.yml را طوری به‌روزرسانی کنید که Apache داخل کانتینر بتواند این گواهی‌ها را Mount کند و SSL Full Strict در داکر و HTTP/2 فعال شوند.
  3. در wp-config.php، تنظیمات Reverse Proxy و HTTPS را اعمال کنید تا وردپرس از HTTPS پشت Cloudflare مطلع باشد.
  4. با اجرای دستور docker compose up -d تغییرات را اعمال کنید.
  5. وضعیت SSL در Cloudflare را از Flexible به Full (Strict) تغییر دهید.

چک‌لیست نهایی Cloudflare

چک‌لیست قبل از تغییر به SSL Full (Strict) در Cloudflare

  1. cert.pem و key.pem از Cloudflare Origin CA دریافت و در پروژه Docker ذخیره شده‌اند و تنظیمات امنیتی با موفقیت پیاده‌سازی شد.
  2. docker-compose.yml به‌روزرسانی شده و Apache می‌تواند گواهی‌ها را Mount کند.
  3. ماژول‌های SSL و HTTP/2 در Apache فعال شده‌اند.
  4. wp-config.php تنظیمات مربوط به Reverse Proxy و HTTPS را دارد:

تشخیص HTTPS از Cloudflare

FORCE_SSL_ADMIN = true

WP_HOME و WP_SITEURL با HTTPS

  1. سایت با دستور docker compose up -d بالا آمده و از طریق HTTPS قابل دسترسی است.

وقتی همه موارد بالا انجام شد، SSL Full Strict در داکر راه اندازی شد می‌توانید در Cloudflare SSL را به Full (Strict) تغییر دهید.

1 دیدگاه دربارهٔ «چگونه Full Strict SSL کلودفلر را برای وب‌سایت داکری فعال کنیم: 3 گام تا رسیدن به امنیت واقعی;

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