لماذا الاستضافة الذاتية لـ Spring Boot على خادم VPS
يتضمّن تطبيق Spring Boot خادمه الخاص (Tomcat أو Undertow) ويُسلَّم على هيئة ملفّ JAR قابل للتنفيذ ومستقلّ. وهذا مثالي لخادم VPS: ملفّ app.jar واحد، وآلة JVM واحدة، وأنت جاهز للعمل. تفرض منصّات PaaS مثل Heroku أو الحاويات المُدارة رسومًا على كلّ شريحة 512 ميجابايت من الذاكرة، في حين أنّ JVM شرهة عند الإقلاع. على خادم VPS، تضبط -Xmx بنفسك، وتشارك قاعدة بيانات PostgreSQL وواجهة API على الآلة نفسها، وتتحكّم في الإحماء البارد دون مهلة زمنية مفروضة. كما تحتفظ بالسيطرة على إصدار JDK المحدّد (Temurin 21 LTS وGraalVM) وعلى معاملات GC، وهو أمر نادرًا ما يكون ممكنًا في بيئة مُدارة.
الفوائد الملموسة
- تحكّم كامل في كومة JVM (
-Xmxو-Xms) وفي جامع المهملات وفقًا لحملك الفعلي - قاعدة بيانات PostgreSQL وواجهة API في الموقع نفسه: زمن استجابة شبكي شبه معدوم بين التطبيق والبيانات
- تكلفة شهرية ثابتة وقابلة للتوقّع، دون فرض رسوم على شريحة الذاكرة أو زمن الحوسبة
- حرّية اختيار JDK: Temurin 21 LTS أو GraalVM native-image أو Azul Zulu حسب احتياجاتك
- لا إقلاع بارد مفروض: تبقى خدمتك ساخنة على مدار الساعة طوال الأسبوع لأزمنة استجابة مستقرّة
- Actuator وMicrometer وPrometheus مكشوفة بحرّية لمراقبة دقيقة دون تكلفة إضافية
المتطلّبات العتادية والبرمجية
تعمل واجهة Spring Boot مع قاعدة بيانات بارتياح على خادم VPS بمعالجين افتراضيين (2 vCPU) و4 جيجابايت من الذاكرة (احسب 1 إلى 1.5 جيجابايت لـ JVM، والباقي لـ PostgreSQL والنظام). أمّا لخدمة مصغّرة خفيفة دون ORM ثقيل، فإنّ 2 جيجابايت تكفي لكنّها تبقى ضيّقة عند الإقلاع. ثبّت Docker وDocker Compose، وJDK 21 إذا كنت تُصرّف على الخادم (وإلّا فابنِ ملفّ JAR في CI وأرسل الأثر فقط)، ووجّه اسم نطاق من نوع api.mydomain.com نحو عنوان IP الخاص بخادم VPS عبر سجلّ A. جهّز 10 جيجابايت من القرص كحدّ أدنى لصور Docker والسجلّات.
النشر خطوة بخطوة
بناء ملفّ JAR القابل للتنفيذ
شغّل ./mvnw clean package -DskipTests (أو ./gradlew bootJar). تحصل على ملفّ في target/app.jar يتضمّن Tomcat وجميع التبعيات. تحقّق محليًا باستخدام java -jar target/app.jar قبل أيّ إرسال.
الحوسبة في حاوية عبر ملفّ Dockerfile متعدّد المراحل
استخدم eclipse-temurin:21-jre-alpine كصورة نهائية وانسخ ملفّ JAR فقط. يقلّص البناء متعدّد المراحل (maven:3.9-eclipse-temurin-21 للتصريف، وJRE للتنفيذ) حجم الصورة من 700 ميجابايت إلى نحو 250 ميجابايت. اكشف المنفذ 8080.
تنسيق التطبيق + PostgreSQL باستخدام Docker Compose
صرّح عن خدمتين في docker-compose.yml: app وdb (الصورة postgres:16). مرّر بيانات الاعتماد عبر متغيّرات البيئة (SPRING_DATASOURCE_URL وSPRING_DATASOURCE_USERNAME) واربطهما عبر شبكة داخلية. شغّل docker compose up -d.
إعداد Nginx كوكيل عكسي
ثبّت Nginx وأنشئ مضيفًا افتراضيًا يقوم بـ proxy_pass http://127.0.0.1:8080;. أضف الترويستين X-Forwarded-For وX-Forwarded-Proto كي يكتشف Spring بشكل صحيح HTTPS خلف الوكيل (server.forward-headers-strategy=framework).
تفعيل HTTPS باستخدام Certbot
شغّل certbot --nginx -d api.mydomain.com للحصول على شهادة Let's Encrypt وتثبيتها. يتولّى مؤقّت systemd الخاص بـ Certbot التجديد التلقائي. افرض إعادة التوجيه من HTTP إلى HTTPS في المضيف الافتراضي.
جعل إعادة التشغيل موثوقة
أضف restart: unless-stopped إلى خدمات Compose الخاصة بك واضبط فحص السلامة الخاص بـ Actuator (/actuator/health) كمِسبار لـ Docker. وبهذا يُعيد التطبيق تشغيل نفسه بعد إعادة إقلاع خادم VPS أو تعطّل JVM.
صرّف تطبيقك إلى صورة أصلية (native) باستخدام GraalVM (./mvnw -Pnative native:compile عبر Spring Boot 3): يبدأ الملفّ الثنائي في أقل من 100 ms ويستهلك ذاكرة أقل بثلاث إلى خمس مرّات من JVM التقليدية. وهذا أمر حاسم على خادم VPS صغير حيث تُحسب كلّ مئة ميجابايت. كما يجدر بك تحديد الكومة صراحةً باستخدام JAVA_OPTS=-Xmx512m في Compose لمنع JVM من المطالبة بكامل الذاكرة المتاحة.