تثبيت MySQL أمر واحد. أما معظم العمل فيأتي بعده: مستخدم للتطبيق، وطريقة للوصول إلى قاعدة البيانات من حاسوبك دون أن تضع المنفذ 3306 على الإنترنت، وإعدادات ذاكرة لخادم صغير، ونسخ احتياطية تعمل دون تدخلك. يغطي هذا الدليل الأربعة كلها على Ubuntu 24.04. نُفّذت كل خطوة على صورة Ubuntu 24.04 لدينا، والأرقام أدناه من ذلك الخادم.
نفّذ الأوامر بمستخدم لديه صلاحية sudo. ودليل تجهيز Ubuntu ينشئ واحداً.
1. التثبيت
sudo apt update
sudo apt install -y mysql-server
mysql --version
استغرق التثبيت على خادمنا 51 ثانية وأعطانا MySQL 8.0.46. يبدأ فوراً، ويبدأ من جديد مع كل إقلاع، ويستمع على الخادم نفسه فقط: 127.0.0.1:3306 للاتصالات العادية و127.0.0.1:33060 لبروتوكول X الأحدث في MySQL. لا شيء يمكن الوصول إليه من الخارج بعد.
2. أنشئ قاعدة بيانات ومستخدماً
يستخدم حساب root في MySQL على Ubuntu المصادقة عبر المقبس، لذلك يدخلك sudo mysql بلا كلمة مرور. أنشئ قاعدة بيانات ومستخدماً لتطبيقك:
sudo mysql
CREATE DATABASE app CHARACTER SET utf8mb4;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';
EXIT;
اختبره بالطريقة التي سيتصل بها تطبيقك:
mysql -u app -p app -e "SELECT CURRENT_USER();"
يجب أن يطبع app@localhost. وكلمة المرور الخاطئة تحصل على ERROR 1045 (28000): Access denied for user 'app'@'localhost'. يستطيع المستخدم فعل أي شيء داخل app ولا شيء خارجها.
3. الاتصال من حاسوبك: نفق SSH
لاستخدام برنامج مكتبي مثل DBeaver أو MySQL Workbench أو سطر أوامر mysql على جهازك، لا تفتح أي منفذ. وجّه منفذاً عبر SSH:
ssh -L 3307:127.0.0.1:3306 deploy@YOUR.SERVER.IP
في خطة NAT أضف -p ومنفذ SSH الخاص بك من لوحة التحكم. وما دامت تلك النافذة مفتوحة، وجّه البرنامج إلى المضيف 127.0.0.1 والمنفذ 3307 والمستخدم app. استخدمنا 3307 في الطرف المحلي كي لا يتعارض مع MySQL قد يعمل على حاسوبك. في اختبارنا أجاب الخادم فوراً عبر النفق، بينما رُفض الاتصال المباشر بعنوانه على المنفذ 3306.
4. وصول مباشر لخادم آخر واحد
أحياناً يعمل التطبيق على خادم ثانٍ ويجب أن يتصل مباشرة. ولهذا تحتاج قاعدة البيانات إلى خطة لها IPv4 خاص، لأن خطة NAT لا توجّه إلا منفذ SSH الخاص بك. ثلاثة تغييرات، كلها مقصورة على عنوان خادم التطبيق (هنا 203.0.113.20):
sudo sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
sudo systemctl restart mysql
sudo ufw allow from 203.0.113.20 to any port 3306 proto tcp
CREATE USER 'app'@'203.0.113.20' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'203.0.113.20';
إذا لم يكن ufw مفعّلاً بعد، فاسمح بـ SSH أولاً (sudo ufw allow OpenSSH) ثم شغّل sudo ufw enable. والتفاصيل في دليل ufw.
فحصنا القفلين كلاً على حدة. مع وجود قاعدة جدار الحماية ودون مستخدم MySQL مطابق، رفض الخادم برسالة error 1130: Host '…' is not allowed to connect to this MySQL server. وبعد إضافة المستخدم مرّ الاتصال. وعند إزالة قاعدة جدار الحماية انتهت مهلة الاتصال ببساطة. وأي عنوان آخر على الإنترنت يحصل على انتهاء المهلة نفسه.
5. استخدم ذاكرة أقل
في وضع الخمول ودون بيانات خاصة به، استهلك MySQL 8.0 على خادمنا 383 MB. معظمها يعود إلى Performance Schema، وهي ميزة تشخيص تحجز الذاكرة مسبقاً. على VPS صغير أوقفها وحدّد حجم الذاكرة المؤقتة الرئيسية بنفسك:
sudo tee /etc/mysql/mysql.conf.d/zz-small-vps.cnf >/dev/null <<'EOF'
[mysqld]
performance_schema = OFF
innodb_buffer_pool_size = 256M
max_connections = 50
EOF
sudo systemctl restart mysql
ps -o rss= -C mysqld
بعد إعادة التشغيل استهلك 165 MB. يخزّن buffer pool بياناتك وفهارسك مؤقتاً، و256 MB تناسب خادماً بسعة 2 GB يشغّل التطبيق أيضاً. ارفعه إذا كانت قاعدة البيانات هي الأساس على الخادم وكبرت أكثر من الذاكرة المؤقتة. وmax_connections = 50 أكثر من كافٍ لتطبيق واحد يستخدم مجمّع اتصالات. ستفقد إحصاءات performance_schema. أعد تشغيلها إذا احتجت يوماً إلى تحليل الاستعلامات البطيئة بالتفصيل.
6. نسخ احتياطية كل ليلة
يأخذ mysqldump --single-transaction نسخة متسقة من جداول InnoDB دون أن يحجب التطبيق. ضعه في سكربت صغير:
sudo tee /usr/local/bin/mysql-backup >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
umask 077
mkdir -p /var/backups/mysql
mysqldump --single-transaction --routines --triggers app | gzip > /var/backups/mysql/app-$(date +%F).sql.gz
find /var/backups/mysql -name 'app-*.sql.gz' -mtime +14 -delete
EOF
sudo chmod 755 /usr/local/bin/mysql-backup
echo '0 3 * * * root /usr/local/bin/mysql-backup' | sudo tee /etc/cron.d/mysql-backup
sudo /usr/local/bin/mysql-backup && sudo ls -l /var/backups/mysql
لكل سطر سبب:
umask 077يجعل ملف التفريغ قابلاً للقراءة من root فقط (-rw-------)، لأنه يحوي كل بياناتك.pipefailيجعل السكربت كله يفشل إذا فشلmysqldump. ومن دونه سيكتبgzipأرشيفاً صغيراً فارغاً ويعلن النجاح. أفسدنا الأمر عمداً فخرج السكربت بالرمز 2 كما ينبغي.find … -mtime +14 -deleteيحتفظ بنسخ أسبوعين.- يعمل السكربت باسم root، لذا يدخل
mysqldumpعبر المقبس ولا توجد كلمة مرور في أي ملف.
النسخة التي لم تستعدها قط لا تُحسب بعد. استعدها إلى قاعدة بيانات مؤقتة وانظر إلى البيانات:
sudo mysql -e "CREATE DATABASE app_restore"
gunzip -c /var/backups/mysql/app-2026-10-25.sql.gz | sudo mysql app_restore
sudo mysql -e "SHOW TABLES FROM app_restore"
sudo mysql -e "DROP DATABASE app_restore"
في اختبارنا احتوى الجدول المستعاد على الصفوف نفسها التي في الأصل. النسخ على القرص نفسه لا تحميك إذا فقدت الخادم، فانقلها من حين لآخر إلى جهاز آخر بـ scp أو restic. وتضيف Managed Backups فوق ذلك نقاط استعادة يومية للخادم كله.
أي خطة تختار
خطة Micro (2 vCPU، 2 GB، 25 GB، $5 شهرياً) تتسع لـ MySQL مضبوطاً كما سبق إضافة إلى تطبيق ويب. وإذا تجاوزت قاعدة البيانات نفسها بضعة غيغابايت، فإن Small بـ 4 GB و35 GB مقابل $8 شهرياً تتيح لك إعطاء buffer pool 1 GB أو أكثر. كلتاهما خطة NAT، ونفق SSH من الخطوة 3 يعمل عليهما. أما الخطوة 4 فتحتاج IPv4 خاصاً: Micro-IP بسعر $10 شهرياً.
تفضّل PostgreSQL؟ دليل PostgreSQL يتبع الخطة نفسها. كل الخطط في VPS، والدفع بعملات USDT أو USDC أو ETH على شبكات Base أو Ethereum أو Polygon.
التعليقات
لا تعليقات بعد. كن الأول.