نصب دستی

نصب کاملاً دستی: از یک VPS تازه‌خریداری‌شده تا یک داشبورد آماده، گام‌به‌گام. آماده‌سازی سرور، ساخت سایت، پایگاه‌داده، config.php و SSL همین‌جا شرح داده شده‌اند. دستورهای مربوط به هر ابزار امنیتی و cron در مرجع FAQ آمده‌اند، پیوندها در طول متن.

قاعده اصلی: هنگام تغییر SSH یا فایروال، اتصال فعلی را نبندید تا وقتی اتصال جدید را در پنجره‌ای جدا آزمایش کنید. اگر با این حال دسترسی را از دست دادید — تقریباً همه هاستینگ‌ها یک کنسول اضطراری (VNC/Recovery) در پنل مدیریت ارائه می‌دهند.

01. یک VPS با Ubuntu/Debian خریدم — از کجا شروع کنم

پس از خرید، هاستینگ این موارد را می‌فرستد: آدرس IP، نام کاربری (معمولاً root) و رمز عبور (یا کلید SSH). همین برای ورود کافی است. ترتیب کارها (هر مرحله یک بخش در پایین است):

  1. اتصال به سرور از طریق SSH؛
  2. به‌روزرسانی سیستم، تعیین نام میزبان و منطقهٔ زمانی؛
  3. ایجاد یک کاربر عادی با دسترسی sudo (کار نکردن با root)؛
  4. تنظیم ورود با کلید SSH و غیرفعال کردن ورود با رمز عبور؛
  5. فعال کردن فایروال و حفاظت خودکار؛
  6. (اختیاری) نصب پنل مدیریت HestiaCP — وب‌سرور، پایگاه داده و ایمیل به‌صورت آماده.

02. نخستین اتصال از طریق SSH

SSH یک ترمینال امن برای اتصال به سرور است. به جای 203.0.113.10 IP خودتان را قرار دهید.

203.0.113.10 فقط یک نمونه است، آدرسی واقعی نیست (برای مستندسازی رزرو شده). آن را همان‌طور که هست وارد نکنید — با IP واقعی سرور خود از ایمیل میزبان جایگزینش کنید. در غیر این صورت اتصال برقرار نمی‌شود.

Windows 10/11: PowerShell یا «ترمینال» را باز کنید و از ssh داخلی استفاده کنید (یا کلاینت‌های PuTTY / MobaXterm).
macOS / Linux: «ترمینال» را باز کنید.

# ورود با کاربر root (رمز عبور را میزبان ارسال کرده است): ssh root@203.0.113.10 # اگر میزبان به جای رمز عبور فایل کلید داده است: ssh -i مسیر/به/کلید root@203.0.113.10
در نخستین اتصال، SSH درباره «authenticity of host» می‌پرسد — yes را وارد کنید. رمز عبور هنگام تایپ نمایش داده نمی‌شود (این طبیعی است). اگر میزبان رمز عبور موقت داده است، آن را با فرمان passwd تغییر دهید.

03. به‌روزرسانی سیستم و پیکربندی پایه

در گام نخست — همه بسته‌ها را به‌روز کنید و نام میزبان و منطقه زمانی را تنظیم کنید.

# به‌روزرسانی سیستم: apt update && apt upgrade -y # ابزارهای پایه: apt install -y curl wget ufw fail2ban unattended-upgrades # منطقه زمانی (نمونه) و نام میزبان: timedatectl set-timezone Asia/Tehran hostnamectl set-hostname myserver # به‌روزرسانی‌های خودکار امنیتی: dpkg-reconfigure -plow unattended-upgrades
فهرست منطقه‌های زمانی — timedatectl list-timezones. اگر در پایان به‌روزرسانی پنجره آبی «Daemons using outdated libraries» ظاهر شد — همه سرویس‌ها را انتخاب کنید (Space) و OK را بزنید، این کار امن است.

04. ساخت کاربر با دسترسی sudo

کار دائمی با کاربر root امن نیست. یک کاربر عادی بسازید و به او دسترسی sudo بدهید (اجرای دستورات مدیریتی در صورت نیاز). deploy را با هر نامی جایگزین کنید.

# ساخت کاربر (رمز را تنظیم می‌کند و اطلاعات را می‌پرسد — می‌توانید Enter بزنید): adduser deploy # افزودن به گروه sudo: usermod -aG sudo deploy # بررسی (با root): su - deploy sudo whoami # باید خروجی بدهد: root exit
از این پس با همین کاربر به سرور وارد شوید: ssh deploy@203.0.113.10، و دستورات مدیریتی را با پیشوند sudo اجرا کنید.

05. کلیدهای SSH و غیرفعال کردن ورود با رمز عبور

ورود با کلید امن‌تر از رمز عبور است: رمز عبور را می‌توان حدس زد، اما کلید را تقریباً هرگز. ابتدا کلید را روی رایانه خودتان می‌سازیم، آن را روی سرور کپی می‌کنیم، ورود را بررسی می‌کنیم — و تنها پس از آن رمز عبور را غیرفعال می‌کنیم.

گام ۱. ساخت کلید روی رایانه خودتان (Windows PowerShell / macOS / Linux):

ssh-keygen -t ed25519 -C "my-laptop" # Enter برای همه پرسش‌ها (کلید در ~/.ssh/id_ed25519 قرار می‌گیرد)

گام ۲. کپی کلید عمومی روی سرور:

# macOS / Linux: ssh-copy-id deploy@203.0.113.10 # Windows (PowerShell): type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

گام ۳. بررسی ورود با کلید در یک پنجره جدید — باید بدون رمز عبور اجازه ورود بدهد:

ssh deploy@203.0.113.10
گزینهٔ B را تا زمانی که ورود با کلید آزموده نشده و کار نمی‌کند (گام‌های ۱ تا ۳) اجرا نکنید و نشست فعلی را نبندید. این کار ورود با رمز عبور را برای همهٔ کاربران، از جمله root، غیرفعال می‌کند. بدون کلید سالم دسترسی به سرور را کاملاً از دست می‌دهید — و بازگرداندن آن تنها از طریق کنسول میزبان ممکن است. کلید ندارید — گزینهٔ A را انتخاب کنید.

گام ۴. سخت‌گیرانه‌کردن دسترسی SSH. تنظیمات را در یک فایل جداگانه می‌گذاریم و پیکربندی اصلی را دست نمی‌زنیم. گزینهٔ مناسب وضعیت خود را انتخاب کنید:

گزینهٔ A — فقط بستن root و نگه‌داشتن رمز عبور. نیازی به کلید نیست و دسترسی را از دست نمی‌دهید:

echo 'PermitRootLogin no' | sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null sudo systemctl restart ssh

گزینهٔ B — سخت‌سازی کامل. غیرفعال‌کردن ورود با رمز عبور و نگه‌داشتن root فقط با کلید. تنها پس از اطمینان از کارکرد ورود با کلید اجرا کنید:

sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null <<'EOF' PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin prohibit-password KbdInteractiveAuthentication no EOF sudo systemctl restart ssh
در هر دو گزینه ورود root با رمز عبور بسته می‌شود. PermitRootLogin no root را کاملاً ممنوع می‌کند و prohibit-password ورود را فقط با کلید نگه می‌دارد (برای مدیریت با deploy وارد شوید و از sudo استفاده کنید). اگر می‌خواهید پورت SSH را تغییر دهید — خط Port 2222 را اضافه کنید، اما ابتدا پورت جدید را در فایروال باز کنید (بخش بعدی) و ورود را بررسی کنید، وگرنه دسترسی خود را می‌بندید.

06. فایروال پایه و محافظت خودکار

هر چیز غیرضروری را با فایروال ببندید و fail2ban را فعال کنید (تلاش‌های مکرر برای حدس رمز SSH را مسدود می‌کند). ابتدا SSH را مجاز کنید، وگرنه پس از فعال‌سازی UFW دسترسی خود را از دست می‌دهید.

# مجاز کردن SSH (یا پورت خودتان اگر تغییرش داده‌اید) و وب: sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # فعال کردن فایروال: sudo ufw enable sudo ufw status verbose # fail2ban — محافظت SSH در برابر حدس مکرر (پروفایل پایه بلافاصله فعال است): sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd
این حداقل است. تنظیمات کاربردی fail2ban، فهرست مسدودسازی ipsum، UFW پیشرفته و ابزارهای دیگر در گروه «ابزارهای امنیتی» راهنما آمده است. خود پنل Arcivéo Monitor وضعیت همهٔ این‌ها را به‌روشنی نشان می‌دهد.

07. نصب پنل HestiaCP (اختیاری)

HestiaCP — پنل رایگان مدیریت هاستینگ: وب‌سرور (nginx + apache)، PHP، پایگاه‌داده (MariaDB)، ایمیل، DNS و گواهی‌های SSL را نصب و پیکربندی می‌کند و رابط وب برای سایت‌ها می‌دهد. اگر نمی‌خواهید همه‌چیز را دستی تنظیم کنید و قصد میزبانی سایت‌ها (از جمله خود پنل Arcivéo Monitor) را دارید، مناسب است.

HestiaCP را روی یک سرور تمیز نصب کنید (نسخه پشتیبانی‌شده و تازه Ubuntu/Debian، حداقل ~۱ تا ۲ گیگابایت RAM)، پیش از نصب سایر وب‌سرورها و پایگاه‌داده — وگرنه تداخل پیش می‌آید. نصب ۱۰ تا ۲۰ دقیقه طول می‌کشد و سرور را ری‌استارت می‌کند.
# دانلود نصب‌کننده و اجرای آن: wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh sudo bash hst-install.sh

نصب‌کننده ایمیل و نام میزبان را می‌پرسد، سپس کل مجموعه را نصب می‌کند. پس از ری‌استارت، پنل در نشانی https://YOUR_IP:8083 در دسترس است (نام کاربری و رمز عبور را نصب‌کننده در پایان نشان می‌دهد).

HestiaCP خودش UFW و fail2ban را مدیریت می‌کند — لازم نیست جداگانه آن‌ها را تنظیم کنید، خودش سراغشان می‌رود. کلیدهای SSH و غیرفعال کردن رمز عبور (بخش قبل) را باز هم انجام دهید.

08. نیازمندی‌های سیستمی و ionCube

پنل یک برنامهٔ PHP روی پشتهٔ متداول LAMP/LEMP است:

  • سیستم‌عامل: Linux (توصیه: Ubuntu/Debian)؛
  • وب‌سرور: nginx یا Apache همراه با PHP-FPM؛
  • PHP 8.0+ با افزونه‌های: pdo_mysql، openssl، curl، json، mbstring؛
  • ionCube Loader — افزونهٔ PHP لازم برای کارکرد پنل؛
  • پایگاه‌داده: MySQL 5.7+ یا MariaDB 10.3+؛
  • HTTPS — الزامی (ورود و WebAuthn فقط روی https کار می‌کنند)؛
  • sudo برای کاربر وب‌سرور (مجموعه‌ای محدود — گام ۱۳).
# بررسی نسخهٔ PHP و افزونه‌ها: php -v php -m | grep -iE 'pdo_mysql|openssl|curl|mbstring|ioncube'

نصب ionCube Loader (اگر هنوز نصب نیست). روی هاست دارای پنل (HestiaCP، cPanel) با یک تیک در تنظیمات PHP فعال می‌شود. به‌صورت دستی روی Ubuntu/Debian:

# یافتن نسخهٔ PHP و مسیر افزونه‌ها: php -v EXTDIR=$(php -r 'echo ini_get("extension_dir");'); PHPVER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') # دانلود و استخراج لودرها (64-bit): cd /tmp wget -q https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz tar xzf ioncube_loaders_lin_x86-64.tar.gz # کپی لودر متناسب با نسخهٔ PHP شما به مسیر افزونه‌ها: sudo cp ioncube/ioncube_loader_lin_${PHPVER}.so "$EXTDIR"/ # فعال‌سازی (CLI + PHP-FPM) و راه‌اندازی مجدد: echo "zend_extension=ioncube_loader_lin_${PHPVER}.so" | sudo tee /etc/php/${PHPVER}/mods-available/ioncube.ini sudo phpenmod ioncube sudo systemctl restart php${PHPVER}-fpm # بررسی — در خروجی خط "with the ionCube PHP Loader" ظاهر می‌شود: php -v
نسخهٔ لودر باید با نسخهٔ PHP یکی باشد (مثلاً ioncube_loader_lin_8.1.so برای PHP 8.1). اگر از چند نسخهٔ PHP استفاده می‌کنید — لودر را برای هر کدام فعال کنید.

09. دامنه و DNS

برای باز کردن پنل با نشانی‌ای مانند monitor.example.com و دریافت SSL رایگان، به دامنه‌ای نیاز دارید که به سرور شما اشاره کند. در پنل مدیریت DNS یک رکورد A بسازید:

نوع: A نام: monitor (زیردامنه → monitor.example.com) یا @ (ریشه دامنه → example.com) مقدار: 203.0.113.10 ← IP سرور شما TTL: 3600

چند دقیقه بعد بررسی کنید که دامنه به سرور اشاره می‌کند:

dig +short monitor.example.com # باید IP شما را برگرداند # یا، اگر dig نبود: getent hosts monitor.example.com
گواهی SSL از Let's Encrypt فقط برای دامنه صادر می‌شود — DNS باید پیش از صدور گواهی به سرور اشاره کند.

10. ساخت سایت و آپلود فایل‌های پنل

Apache: مقدار DocumentRoot باید ریشه پنل باشد، نه public/. استایل‌ها (CSS/JS)، sw.js و manifest.json در پوشه assets/ کنار public/ قرار دارند و از ریشه سایت درخواست می‌شوند. فایل .htaccess ریشه، فرانت‌کنترلر است. اگر در Apache مقدار DocumentRoot را روی public/ بگذارید، پنل بدون استایل باز می‌شود. برای nginx خالص برعکس است: ریشه روی public/ تنظیم می‌شود و assets/ با یک قانون جداگانه ارائه می‌شود (به بلوک nginx در پایین نگاه کنید).
فایل‌های پنل (آرشیو نسخه توزیع) پس از خرید در حساب کاربری my.arciveo.com«دانلودها» قابل دریافت است. پیش از آپلود، آرشیو را از حالت فشرده خارج کنید.

۱) دایرکتوری پنل را بسازید و محتوای نسخه توزیع را در آن آپلود کنید (تا public/، assets/، config.php و غیره داخل آن قرار گیرند):

sudo mkdir -p /var/www/monitor # سپس فایل‌های نسخه توزیع را در /var/www/monitor آپلود کنید (FileZilla / WinSCP / scp)

۲) وب‌سرور را پیکربندی کنید. Apache: مقدار DocumentRoot را روی ریشه پنل بگذارید (نه /publicAllowOverride All الزامی است. مسیر سوکت PHP-FPM به‌صورت خودکار تشخیص داده می‌شود. این بلوک را به‌طور کامل در ترمینال وارد کنید:

PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # تشخیص خودکار سوکت PHP-FPM sudo tee /etc/apache2/sites-available/monitor.conf > /dev/null <<'EOF' <VirtualHost *:80> ServerName monitor.example.com DocumentRoot /var/www/monitor <Directory /var/www/monitor> AllowOverride All Require all granted </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:__PHPSOCK__|fcgi://localhost" </FilesMatch> </VirtualHost> EOF sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/apache2/sites-available/monitor.conf sudo a2dissite 000-default.conf sudo a2ensite monitor.conf sudo apache2ctl configtest sudo systemctl reload apache2

nginx: در nginx فایل .htaccess وجود ندارد، بنابراین ریشه را روی public/ می‌گذاریم و assets/، sw.js، manifest.json (یک سطح بالاتر) را با یک قانون جداگانه ارائه می‌کنیم:

PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # تشخیص خودکار سوکت PHP-FPM sudo tee /etc/nginx/sites-available/monitor.conf > /dev/null <<'EOF' server { listen 80; server_name monitor.example.com; root /var/www/monitor/public; index index.php; # assets، service worker و manifest یک سطح بالاتر از public/ قرار دارند location ~ ^/(assets/|sw\.js|manifest\.json) { root /var/www/monitor; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:__PHPSOCK__; } } EOF sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/nginx/sites-available/monitor.conf sudo ln -s /etc/nginx/sites-available/monitor.conf /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx

آپلود فایل‌ها — SFTP/SCP (FileZilla، WinSCP) یا scp:

# نمونه با scp از رایانه محلی: scp -r ./monitor/* deploy@203.0.113.10:/var/www/monitor/
دسترسی‌های فایل‌ها را تنظیم کنید — این مرحله الزامی است. اگر با کاربر root یا از طریق SFTP آپلود کرده‌اید، فایل‌ها به root تعلق دارند و وب‌سرور (www-data) نمی‌تواند آن‌ها را بخواند — پنل خالی یا با خطای ۴۰۳ باز می‌شود (در لاگ: .htaccess unreadable / directory not executable). دستور زیر این مشکل را رفع می‌کند:
# دسترسی‌های کل وب‌روت را نرمال می‌کنیم: دایرکتوری ساخته‌شده توسط root برای # وب‌سرور (www-data) قابل دسترسی نیست — بدون این، پنل صفحه خالی یا ۴۰۳ می‌دهد. # Apache با www-data کار می‌کند؛ اگر کاربر وب دیگری دارید — آن را جایگزین کنید. cd /var/www/monitor # پوشه‌های کاری را پیش از chown می‌سازیم — وگرنه دایرکتوری‌های جدید root:root می‌مانند # و با chmod 750 وب‌سرور (www-data) نمی‌تواند در آن‌ها بنویسد. sudo mkdir -p data/lynis data/logwatch tmp logs sudo chown -R www-data:www-data /var/www/monitor sudo find /var/www/monitor -type d -exec chmod 755 {} \; sudo find /var/www/monitor -type f -exec chmod 644 {} \; sudo chmod 640 /var/www/monitor/config.php sudo chmod 750 data tmp logs

۳) بارگذاری فایل با SFTP را برای خودتان باز کنید. پس از دستور بالا همهٔ فایل‌ها متعلق به www-data هستند، در حالی که FileZilla / WinSCP با کاربر خودتان وصل می‌شوند — آنگاه بارگذاری با خطای SSH_FX_PERMISSION_DENIED (Permission denied) شکست می‌خورد. ورود با root برای بارگذاری هم ممکن نیست؛ ورود root در گام ۰۵ غیرفعال شد. یکی از دو گزینه را انتخاب کنید.

گزینهٔ A — یک ACL فقط برای کاربر خودتان (توصیه‌شده). دسترسی نوشتن تنها به شما داده می‌شود و وب‌سرور همچنان نمی‌تواند کد پنل را بازنویسی کند:

sudo apt install -y acl # دسترسی نوشتن برای کاربر شما روی کل پوشهٔ پنل: sudo setfacl -R -m u:deploy:rwX /var/www/monitor # همان قاعده به‌صورت پیش‌فرض — برای فایل‌ها و پوشه‌هایی که بعداً ساخته می‌شوند: sudo setfacl -R -d -m u:deploy:rwX /var/www/monitor

گزینهٔ B — از طریق گروه www-data. ساده‌تر است، اما دسترسی نوشتن روی فایل‌های پنل به وب‌سرور هم می‌رسد: با وجود یک آسیب‌پذیری در PHP می‌توان کد را جایگزین کرد. ترتیب دستورها مهم است — config.php و پوشه‌های کاری در پایان بسته می‌شوند:

sudo usermod -aG www-data deploy # دسترسی نوشتن برای گروه + setgid (بیت ۲): فایل‌های بارگذاری‌شده با SFTP # در گروه www-data باقی می‌مانند — وگرنه پنل نمی‌تواند آن‌ها را بازنویسی کند. sudo find /var/www/monitor -type d -exec chmod 2775 {} \; sudo find /var/www/monitor -type f -exec chmod 664 {} \; sudo chmod 640 /var/www/monitor/config.php sudo chmod 2750 /var/www/monitor/data /var/www/monitor/tmp /var/www/monitor/logs
پس از گزینهٔ B در FileZilla دوباره وصل شوید (سرور ← قطع اتصال، سپس ورود دوباره) — گروه جدید فقط با ورود تازه اعمال می‌شود و تا آن زمان همچنان دسترسی نخواهید داشت. بررسی: id deploy — در فهرست گروه‌ها باید www-data ظاهر شود؛ ls -ld /var/www/monitor — دسترسی‌ها drwxrwsr-x و حرف s به‌جای x یعنی setgid تنظیم شده است.

11. پایگاه داده

یک پایگاه داده و کاربر بسازید، سپس اسکیما را وارد کنید. این بلوک را یکجا در ترمینال بچسبانید. monitor_db و monitor_user فقط نمونه‌اند و می‌توانید هر نامی انتخاب کنید؛ نام پایگاه داده، کاربر و رمز عبور را به خاطر بسپارید — در گام بعد آن‌ها را در config.php وارد می‌کنید:

# 1. پایگاه داده. رمز عبور یک بار در DBPASS تعیین و در همه خطوط جایگذاری می‌شود. # این بلوک را یکجا در ترمینال بچسبانید؛ sudo mysql با root از طریق سوکت unix وارد می‌شود # (رمز root لازم نیست). از `sudo mysql -u root -p` تعاملی با کپی‌پیست استفاده نکنید # — هنگام چسباندن، خطوط SQL به درخواست رمز می‌روند و از بین می‌روند. DBPASS='CHOOSE_A_PASSWORD' # ← فقط همین خط را تغییر دهید sudo mysql <<SQL CREATE DATABASE IF NOT EXISTS monitor_db CHARACTER SET utf8mb4; CREATE USER IF NOT EXISTS 'monitor_user'@'localhost' IDENTIFIED BY '$DBPASS'; GRANT ALL ON monitor_db.* TO 'monitor_user'@'localhost'; FLUSH PRIVILEGES; SQL # بررسی (باید monitor_db را نشان دهد): mysql -u monitor_user -p"$DBPASS" -e "SHOW DATABASES;" # همین رمز عبور را در config.php → DB_PASS وارد کنید.
نیازی به وارد کردن اسکیما نیست — پنل خودش هنگام نخستین ورود از مرورگر جدول‌ها و حساب admin را می‌سازد (از database/db.sql)، اگر پایگاه داده خالی باشد. وارد کردن دستی اسکیما فقط زمانی لازم است که مقداردهی خودکار انجام نشده باشد.
اگر از نصب‌کننده مرورگری public/start_db.php استفاده کرده‌اید — بلافاصله پس از نصب آن را حذف کنید: این فایل امکان بازسازی پایگاه داده را بدون احراز هویت می‌دهد. تا زمانی که این فایل در ریشه پنل یا در public/ باشد، پنل هشدار قرمز نشان می‌دهد.

12. پیکربندی config.php

config.php در ریشه پنل (/var/www/monitor/config.php) تنها فایلی است که باید دستی ویرایش شود. همه تنظیمات پنل در آن به‌صورت ثابت‌های define() تعریف شده‌اند. آن را در ویرایشگر باز کنید:

sudo nano /var/www/monitor/config.php

مقادیر خود را در جاهای هایلایت‌شده جایگزین کنید؛ بقیه را همان‌طور که هست رها کنید:

// --- پایگاه داده (از مرحله ۱۱) --- define('DB_HOST', 'localhost'); // رها کنید define('DB_NAME', 'db_name'); // آنچه در مرحله ۱۱ ساختید define('DB_USER', 'user'); // آنچه در مرحله ۱۱ ساختید define('DB_PASS', 'db_password'); // آنچه در مرحله ۱۱ تعیین کردید define('DB_CHARSET', 'utf8mb4'); // رها کنید // --- برنامه --- define('APP_URL', 'https://monitor.example.com'); // نشانی پنل، بدون اسلش در انتها define('TIMEZONE', 'Asia/Tehran'); // منطقه زمانی شما // --- زمان نشست --- define('SESSION_LIFETIME', 28800); // بی‌کاری تا ورود مجدد، ثانیه (28800 = ۸ س)

چه چیزهایی را تغییر دهید:

  • DB_NAME، DB_USER، DB_PASS — دقیقاً همان نام پایگاه داده، کاربر و رمزی که هنگام ساخت پایگاه داده در مرحله ۱۱ تعیین کردید (اگر نمونه‌ها را نگه داشتید — monitor_db / monitor_user). DB_HOST و DB_CHARSET را دست نزنید.
  • APP_URL — نشانی کامل پنل با https://، بدون اسلش در انتها و بدون www. باید با دامنه‌ای که لایسنس را روی آن فعال می‌کنید (مرحله ۱۶) یکی باشد، وگرنه کلید رد می‌شود.
  • TIMEZONE — منطقه زمانی شما (فهرست — timedatectl list-timezones). فقط بر نحوه نمایش تاریخ‌ها توسط پنل اثر می‌گذارد؛ بر زمان اجرای وظایف cron اثری ندارد (آنجا منطقه سیستم اعمال می‌شود).
  • SESSION_LIFETIME — پس از چند ثانیه بی‌کاری، پنل دوباره ورود می‌خواهد (پیش‌فرض ۸ ساعت). مثلاً 3600 = ۱ ساعت، 86400 = یک شبانه‌روز.
  • بلوک ثبت خطاها (display_errors، log_errors، error_log) — پیش‌فرض را رها کنید.

فایل را ذخیره کنید (Ctrl+O، Enter، سپس Ctrl+X) و PHP-FPM را بازراه‌اندازی کنید — وگرنه به دلیل OPcache تغییرات اعمال نمی‌شوند:

sudo systemctl restart php*-fpm
config.php فایلی محرمانه است (رمز پایگاه داده در آن است). در ریشه پنل قرار دارد که همان ریشه وب است، اما بسته شده است: مجوز 640 (در مرحله ۱۰ تنظیم شده) و منع صریح در .htaccess ریشه. آن را در مخازن عمومی قرار ندهید و با رمز واقعی به پشتیبانی ارسال نکنید.
بررسی مفصل همه پارامترها — در FAQ: «فایل config.php — همه تنظیمات پنل».

13. پیکربندی sudo برای وب‌سرور

PHP با کاربر وب‌سرور اجرا می‌شود که مجوز اجرای فرمان‌های سیستمی را ندارد. دسترسی به‌طور محدود اعطا می‌شود: sudo نقطه‌ای برای ابزارهای مشخص و خواندن لاگ‌ها از طریق گروه‌ها (بدون sudo). نفوذ به لایه‌ی وب دسترسی root نمی‌دهد.

در مثال‌ها www-data کاربر استاندارد Apache است. اگر کاربر شما متفاوت است (در برخی پنل‌ها PHP با کاربر جداگانه اجرا می‌شود) — همه‌جا جایگزین کنید. برای دانستن آن: ps -o user= -C php-fpm | sort -u.

1. فایل /etc/sudoers.d/monitor را با sudo visudo -f /etc/sudoers.d/monitor بسازید و این را وارد کنید (خطوط ماژول‌های استفاده‌نشده را حذف کنید):

# UFW — وضعیت و قوانین (صفحه‌ی «دیوار آتش») www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw status, /usr/sbin/ufw status verbose, /usr/sbin/ufw status numbered www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw allow [0-9]*, /usr/sbin/ufw deny [0-9]*, /usr/sbin/ufw --force delete [0-9]* # Fail2ban — وضعیت، بن و رفع بن (banned بن‌های همه‌ی jailها را با یک فرمان می‌دهد؛ # ban/unban برای دکمه‌های داشبورد لازم است) www-data ALL=(ALL) NOPASSWD: /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *, /usr/bin/fail2ban-client banned, /usr/bin/fail2ban-client set * banip *, /usr/bin/fail2ban-client set * unbanip * # به‌روزرسانی‌های امنیتی (کارت «به‌روزرسانی‌ها»). فقط خواندن، اما دقیقاً با root: # کش apt (~۷۰ مگابایت) فقط برای root در دسترس است، غیر-root آن را در هر فراخوانی بازسازی می‌کند # (۴.۲ ثانیه CPU در برابر ۰.۰۱ ثانیه). بدون wildcard — دقیقاً همین یک فرمان، چیزی نصب نمی‌کند. www-data ALL=(ALL) NOPASSWD: /usr/bin/apt list --upgradable # IPset (نقشه‌ی حملات، داشبورد) www-data ALL=(ALL) NOPASSWD: /usr/sbin/ipset list -t ipsum # CrowdSec www-data ALL=(ALL) NOPASSWD: /usr/bin/cscli decisions list *, /usr/bin/cscli alerts list *, /usr/bin/cscli bouncers list *, /usr/bin/cscli scenarios list * # Auditd — جست‌وجوی رویدادها + خواندن آخرین خطوط لاگ (مسیر دقیق) www-data ALL=(ALL) NOPASSWD: /usr/sbin/ausearch -m * www-data ALL=(ALL) NOPASSWD: /usr/bin/tail -n 300 /var/log/audit/audit.log # Monit / ModSecurity / AppArmor / PSAD www-data ALL=(ALL) NOPASSWD: /usr/bin/monit status www-data ALL=(ALL) NOPASSWD: /usr/sbin/apache2ctl -M www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec www-data ALL=(ALL) NOPASSWD: /usr/sbin/aa-status www-data ALL=(ALL) NOPASSWD: /usr/sbin/psad --Status # پورت‌های باز (لاگ‌های هسته/SSH/Falco بدون sudo خوانده می‌شوند — از طریق گروه # systemd-journal، بند ۲ را ببینید؛ دادن sudo برای journalctl لازم نیست و ناامن است) www-data ALL=(ALL) NOPASSWD: /usr/bin/ss -tuln, /usr/sbin/ss -tuln, /bin/ss -tuln # PostgreSQL (فقط اگر استفاده می‌کنید) — اسکریپت read-only ثابت، # طبق FAQ «PostgreSQL نمایش داده نمی‌شود» بسازید؛ بدون آن این خط را حذف کنید www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
sudo chmod 440 /etc/sudoers.d/monitor sudo visudo -c # باید "parsed OK" باشد

2. دسترسی به لاگ‌ها و ژورنال systemd. ماژول‌ها /var/log/fail2ban.log، auth.log، ufw.log، apache2/*، aide را مستقیم می‌خوانند (در Debian/Ubuntu این لاگ‌ها در گروه adm هستند). رویدادهای هسته، SSH و Falco از journald با فرمان journalctl بدون sudo و از طریق گروه systemd-journal گرفته می‌شوند. کاربر وب را به هر دو گروه اضافه کنید و PHP-FPM را ری‌استارت کنید:

sudo usermod -aG adm,systemd-journal www-data sudo systemctl restart php*-fpm # ضروری است، وگرنه گروه‌ها اعمال نمی‌شوند

3. اگر ClamAV یا Suricata لاگ‌ها را در گروه adm نمی‌نویسند (گاهی root:root است) — با ACL دسترسی بدهید:

sudo apt install acl sudo setfacl -R -m u:www-data:rX /var/log/clamav /var/log/suricata 2>/dev/null sudo setfacl -d -m u:www-data:rX /var/log/clamav /var/log/suricata 2>/dev/null

4. پوشش ModSecurity. لاگ ممیزی WAF (/var/log/apache2/modsec_audit.log) متعلق به root با مجوز 640 است و کاربر وب نمی‌تواند آن را مستقیم بخواند. صفحه‌ی ModSecurity حالت موتور، رویدادها و فهرست قوانین فعال را از طریق یک اسکریپت read-only ثابت می‌گیرد — همان که در sudoers با خط بالا مجاز شده است:

sudo tee /usr/local/bin/monitor-modsec >/dev/null <<'EOF' #!/bin/sh echo "ENGINE=$(grep -hE '^SecRuleEngine[[:space:]]+' /etc/modsecurity/*.conf 2>/dev/null | tail -1 | awk '{print $2}')" echo "---LOG---" tail -n 3000 /var/log/apache2/modsec_audit.log 2>/dev/null echo "---RULES---" for f in /etc/modsecurity/crs/rules/*.conf /usr/share/modsecurity-crs/rules/*.conf /etc/modsecurity/custom-rules.conf; do [ -f "$f" ] && { echo "===FILE:$(basename "$f")==="; cat "$f"; } done EOF sudo chown root:root /usr/local/bin/monitor-modsec sudo chmod 755 /usr/local/bin/monitor-modsec
بدون فایل /etc/modsecurity/modsecurity.conf خود WAF کار نمی‌کند: بسته فقط modsecurity.conf-recommended را قرار می‌دهد و موتور قوانین خاموش می‌ماند — برای فعال‌سازی، FAQ ← «نصب ModSecurity» را ببینید.
کاربر در همه‌ی خطوط sudoers باید با کاربر pool FPM یکسان باشد: در Apache/Debian معمولی این www-data است، در HestiaCP pool سایت با مالک سایت اجرا می‌شود (مثلاً admin) — با grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf بررسی کنید.

5. اگر جلوی Apache یک Nginx قرار دارد (HestiaCP، ISPmanager و پنل‌های دیگر — آنجا Nginx فرمان PHP را به Apache پراکسی می‌کند و استاتیک را خودش می‌دهد). دایرکتوری‌های سرویسی با فایل‌های .htaccess بسته شده‌اند، اما Nginx آن‌ها را نمی‌خواند: هر فایل استاتیک (.json، .txt، .log، .dat) را مستقیم و با دور زدن Apache می‌دهد. کش‌های پنل و داده‌ها به بیرون درز می‌کنند — مثلاً tmp/modsec_cache.json با رویدادهای WAF و IPهای مهاجمان. یک منع را به کانفیگ سایت Nginx اضافه کنید:

location ^~ /data/ { deny all; } location ^~ /tmp/ { deny all; } location ^~ /logs/ { deny all; } location ^~ /includes/ { deny all; } location ^~ /cron/ { deny all; } location ^~ /database/ { deny all; } location = /config.php { deny all; }
پیشوند ^~ ضروری است: پیش از قانون منظمِ استاتیک درون location / انتخاب می‌شود، وگرنه منع اعمال نمی‌شود.
در HestiaCP این را در فایلی جداگانه /home/<user>/conf/web/<domain>/nginx.ssl.conf_denynginx.conf_deny برای HTTP) قرار دهید — کانفیگ سایت nginx.ssl.conf_* را ضمیمه می‌کند و هنگام بازسازی چنین فایل‌هایی را پاک نمی‌کند. اعمال: sudo nginx -t && sudo systemctl reload nginx.
بررسی: curl -s -o /dev/null -w '%{http_code}\n' https://monitor.example.com/tmp/modsec_cache.json — باید 403 باشد. اگر Apache بدون Nginx کار می‌کند (خودش روی 80/443 گوش می‌دهد)، افزودن چیزی لازم نیست — .htaccess کافی است.
مسیر باینری‌ها را با which بررسی کنید (مثلاً which ufw cscli ausearch ss). sudoers را فقط با visudo ویرایش کنید. فهرست همه‌ی پایگاه‌های MySQL با یک GRANT جداگانه فعال می‌شود (FAQ ← «فقط یک پایگاه داده دیده می‌شود»).

14. محدودسازی دسترسی بر اساس IP

دسترسی به مانیتور را بر اساس آدرس IP محدود کنید — حتی اگر URL لو برود، صفحه ورود باز نمی‌شود. این کار را می‌توان در سطح وب‌سرور (نمونهٔ nginx در ادامه) یا در خود پنل انجام داد («تنظیمات» ← «محدودسازی دسترسی بر اساس IP»). اگر از Apache استفاده می‌کنید، از محدودسازی داخل پنل استفاده کنید.

اگر سایت nginx را قبلاً طبق گام ۱۰ پیکربندی کرده‌اید، یک بلوک دوم اضافه نکنید location / — خطوط allow/deny را در بلوک موجود بنویسید. دو location / یکسان در یک server { } خطای پیکربندی است و nginx مجدداً راه‌اندازی نمی‌شود.
# در کانفیگ nginx (داخل server { }): # مسیر ACME مربوط به Let's Encrypt را خارج از محدودیت IP باز نگه می‌داریم — # تا صدور و تمدید خودکار SSL (گام 15) به فیلتر IP وابسته نباشد. location ^~ /.well-known/acme-challenge/ { allow all; } location / { allow 203.0.113.10; # ← IP خود را وارد کنید allow 10.0.0.0/8; # شبکهٔ محلی (در صورت نیاز) deny all; try_files $uri $uri/ /index.php?$query_string; } # راه‌اندازی مجدد nginx: sudo nginx -t && sudo systemctl reload nginx

15. صدور SSL (HTTPS)

داشبورد فقط با HTTPS کار می‌کند. نشست ورود از یک کوکی امن استفاده می‌کند و WebAuthn (2FA) تنها روی HTTPS کار می‌کند. با http:// نمی‌توان وارد شد.

گواهی رایگان است (Let's Encrypt). DNS دامنه باید از قبل به سرور اشاره کند. فرمان بسته به وب‌سرور فرق می‌کند:

# Apache: sudo certbot --apache -d monitor.example.com # nginx — فقط اگر دقیقاً nginx دارید. روی Apache اجرا نکنید: # apt نصب nginx را می‌کشد و پورت 80 را می‌گیرد، تداخل با Apache. # sudo apt install python3-certbot-nginx # sudo certbot --nginx -d monitor.example.com # certbot خودش HTTPS را در کانفیگ می‌نویسد و تمدید خودکار را تنظیم می‌کند
certbot چه می‌پرسد: e-mail ← پذیرش Terms (Y) ← ارسال e-mail به EFF (به انتخاب شما). سپس خودش گواهی را صادر می‌کند، <VirtualHost *:443> را می‌نویسد، ریدایرکت http→https و تمدید خودکار را تنظیم می‌کند.
DNS باید پیش از اجرای certbot به سرور اشاره کند (تأیید مالکیت از طریق پورت 80). بررسی: dig +short monitor.example.com ← IP سرور. پورت‌های 80/443 باز باشند: sudo ufw allow 80,443/tcp.

پس از صدور: https://monitor.example.com با قفل باز می‌شود، http:// به https:// ریدایرکت می‌شود (APP_URL در config.php در گام ۱۲ از قبل تنظیم شده است).

16. ورود و پیکربندی اولیه

https://monitor.example.com را باز کنید، با admin / useradmin وارد شوید و این چک‌لیست را طی کنید:

  1. تغییر رمز عبور admin — بخش «کاربران» در منو.
  2. فعال‌سازی WebAuthn (2FA) — «کلیدهای WebAuthn» ← ثبت کلید/passkey (نیازمند HTTPS). دو کلید را همزمان ثبت کنید: در صورت گم‌شدن تنها کلید، ورود با آن ممکن نخواهد بود. جزئیات بیشتر.
  3. محدود کردن دسترسی بر اساس IP — «تنظیمات» ← «محدودیت دسترسی بر اساس IP» (پیش از فعال‌سازی IP خود را وارد کنید، وگرنه دسترسی خود را می‌بندید).
  4. وارد کردن لایسنس — کد ARCIVEO-… از حساب کاربری را روی دامنه خود فعال کنید و کلید را در «تنظیمات» ← «لایسنس» بگذارید. جزئیات بیشتر.
  5. تنظیم اعلان‌ها — Telegram و/یا Email در «تنظیمات». جزئیات بیشتر.
  6. حذف نصب‌کننده public/start_db.php، اگر باقی مانده است (مرحله ۱۱).

17. ابزارهای امنیتی (اختیاری)

پنل هم‌اکنون کار می‌کند. ابزارها به دلخواه نصب می‌شوند — هر چه لازم دارید نصب کنید، پنل بلافاصله وضعیت را نشان می‌دهد. دستورهای نصب هر کدام در راهنما آمده است (بخش‌های جداگانه برای هر ابزار):

18. Cron و نگهداری

یک‌بار تنظیم می‌شود، آن هم اختیاری، اما توصیه می‌شود. دستورهای کامل در راهنما آمده است:

  1. وظایف Cron (گزارش‌ها، به‌روزرسانی فهرست‌ها، بررسی‌ها)؛
  2. پشتیبان‌گیری؛
  3. به‌روزرسانی و انتقال پنل؛
  4. بازیابی دسترسی — برای مواقع از دست رفتن کلید/رمز عبور.
چیزی کار نمی‌کند یا «داده‌ای نیست» نشان می‌دهد؟ به گروه «عیب‌یابی» در راهنما سر بزنید.
Arcivéo - Security Monitor © 2026