دیپلوی اپلیکیشن Go روی سرور اختصاصی و VPS با systemd و Nginx
اگر اپلیکیشن Go نوشتهاید و میخواهید آن را روی یک سرور اختصاصی یا VPS اجرا کنید، لازم نیست سراغ Docker یا Kubernetes بروید. خروجی کامپایل Go یک فایل باینری مستقل است که بدون نیاز به runtime یا پکیج جانبی روی هر سرور لینوکسی اجرا میشود. تنها چیزی که کم دارد یک مدیر پردازش برای بالا نگه داشتن سرویس و یک reverse proxy برای مدیریت ترافیک HTTP/HTTPS است؛ همینجاست که systemd و Nginx وارد میشوند.

چرا دیپلوی Go سادهتر از خیلی زبانهای دیگر است؟
در زبانهایی مثل Node.js یا Python، روی سرور باید runtime مناسب، پکیج منیجر، و وابستگیها را نصب کنید. در Go این مرحله حذف میشود. کامپایلر Go کد را به یک باینری استاتیک تبدیل میکند که تمام وابستگیها داخلش است. کافی است این فایل را روی سرور کپی کنید و اجرا شود.
این ویژگی برای دیپلوی Go روی سرور اختصاصی یا VPS مزیت بزرگی است: نیازی به نصب Go روی سرور پروداکشن نیست، کامپایل روی ماشین توسعه یا در CI انجام میشود و فقط فایل خروجی منتقل میشود.
ساخت باینری استاتیک برای دیپلوی
برای اینکه باینری واقعاً مستقل باشد و به کتابخانههای داینامیک سیستم (مثل glibc) وابسته نباشد، باید CGO را غیرفعال کنید:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o myapp main.go
GOOS=linux GOARCH=amd64کامپایل برای معماری سرور لینوکسی را مشخص میکند، حتی اگر این دستور را روی مک یا ویندوز اجرا کنید.CGO_ENABLED=0مانع لینکشدن به کتابخانههای C سیستم میشود و باینری را کاملاً استاتیک میکند.-ldflags="-s -w"اطلاعات دیباگ و symbol table را حذف میکند و حجم فایل خروجی را کاهش میدهد.
اگر سرور شما معماری ARM دارد (مثلاً برخی سرورهای اختصاصی جدید)، کافی است GOARCH=arm64 را جایگزین کنید.
آمادهسازی سرور قبل از دیپلوی
قبل از انتقال باینری، چند قدم پایه روی سرور لازم است:
- یک کاربر غیر روت برای اجرای اپلیکیشن بسازید، چون اجرای سرویسهای شبکه با کاربر root توصیه نمیشود:
bash sudo adduser --system --group appuser - یک دایرکتوری مشخص برای اپلیکیشن بسازید:
bash sudo mkdir -p /opt/myapp sudo chown appuser:appuser /opt/myapp - فایل باینری را با
scpیاrsyncبه سرور منتقل کنید:bash scp myapp user@server-ip:/opt/myapp/myapp
همین سه قدم کافی است، چه روی یک VPS اجرا کنید چه روی سرور اختصاصی.
اجرای اپلیکیشن با systemd
اجرای مستقیم باینری در یک ترمینال باز مشکلساز است: با بستهشدن session، پردازش هم متوقف میشود. systemd این مشکل را حل میکند و اپلیکیشن را بهصورت یک سرویس لینوکسی مدیریت میکند، با راهاندازی خودکار بعد از ریبوت سرور و ریاستارت خودکار در صورت کرش.
فایل سرویس را در مسیر /etc/systemd/system/myapp.service بسازید:
[Unit]
Description=My Go Application
After=network.target
[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp
Restart=on-failure
RestartSec=5
Environment=PORT=8080
EnvironmentFile=-/opt/myapp/.env
[Install]
WantedBy=multi-user.target
نکات کلیدی این فایل:
Restart=on-failureباعث میشود systemd در صورت خروج غیرمنتظره اپلیکیشن، آن را دوباره اجرا کند.EnvironmentFile=-/opt/myapp/.envمتغیرهای محیطی (مثل connection string دیتابیس) را از یک فایل جداگانه میخواند؛ علامت-در ابتدا یعنی اگر فایل وجود نداشت، systemd خطا ندهد.User=appuserتضمین میکند اپلیکیشن با دسترسی محدود اجرا شود.
اگر چند اپلیکیشن روی یک سرور اجرا میکنید و میخواهید مصرف CPU و RAM هرکدام را محدود کنید، systemd از طریق cgroups این امکان را هم میدهد؛ جزئیات در محدود کردن مصرف CPU و RAM سرویسها با systemd و cgroups.
حالا سرویس را فعال و اجرا کنید:
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
برای دیدن لاگهای برنامه:
sudo journalctl -u myapp -f
هر بار که فایل سرویس را تغییر دادید، دستور daemon-reload را دوباره اجرا کنید؛ فراموشکردن این مرحله یکی از رایجترین دلایل این است که تغییرات اعمال نمیشوند.
تنظیم Nginx بهعنوان ریورس پروکسی
اکثر اپلیکیشنهای Go روی پورتی مثل 8080 گوش میدهند، نه پورت 80 یا 443. قرار دادن Nginx جلوی اپلیکیشن چند مزیت دارد: مدیریت HTTPS، امکان اجرای چند اپلیکیشن پشت یک IP با دامنههای متفاوت، و لایهای اضافه برای rate limiting یا caching.
یک فایل جدید در /etc/nginx/sites-available/myapp بسازید:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
سپس آن را فعال کنید:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

فعالسازی HTTPS با Let's Encrypt
برای گرفتن گواهی SSL رایگان با Let's Encrypt و Certbot و تنظیم خودکار HTTPS در Nginx، از certbot استفاده کنید:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
certbot فایل تنظیمات Nginx را خودش بهروزرسانی میکند و redirect از HTTP به HTTPS را هم اضافه میکند. تمدید گواهی هم بهصورت خودکار از طریق یک cron job یا systemd timer انجام میشود که همراه بسته نصب میشود.
دیپلوی مستقیم با systemd در مقابل Docker یا Kubernetes
برای یک اپلیکیشن Go، قبل از انتخاب روش دیپلوی خوب است هزینه و پیچیدگی هر گزینه را بسنجید:
| معیار | systemd + Nginx | Docker / Kubernetes |
|---|---|---|
| پیچیدگی راهاندازی اولیه | کم، چند فایل تنظیمات | بیشتر، نیاز به image build و orchestration |
| مصرف منابع سرور | حداقلی، بدون overhead کانتینر | بالاتر به دلیل لایههای اضافه |
| مناسب برای | یک یا چند سرویس روی یک یا چند سرور مشخص | تعداد زیاد سرویس با نیاز به مقیاسپذیری افقی خودکار |
| سرعت دیباگ | مستقیم با journalctl و دسترسی به فایلسیستم سرور | نیاز به ابزار اضافه برای لاگ و دسترسی به کانتینر |
| هزینه یادگیری تیم | کم | بیشتر |
اگر پروژه یک یا چند سرویس Go دارد که روی تعداد مشخصی سرور اجرا میشوند و نیازی به auto-scaling پیچیده نیست، ترکیب systemd و Nginx سادهتر، سبکتر و قابل نگهداریتر است. Docker و Kubernetes زمانی ارزش overhead خودشان را نشان میدهند که تعداد سرویسها و نیاز به مقیاسپذیری خودکار زیاد شود.
نکات امنیتی و نگهداری
چند نکته برای اینکه این روش دیپلوی در محیط پروداکشن پایدار بماند:
- فایروال را فقط روی پورتهای لازم (80، 443، و پورت SSH) باز نگه دارید؛ پورت اپلیکیشن (مثلاً 8080) نباید مستقیماً از بیرون قابل دسترسی باشد.
- برای بهروزرسانی بدون قطعی، باینری جدید را با نام دیگری کنار باینری قبلی بگذارید، لینک symlink را به نسخه جدید تغییر دهید و فقط
systemctl restart myappرا اجرا کنید؛ این کار downtime را به چند صدم ثانیه محدود میکند. - لاگهای journald را با
journalctl --vacuum-time=30dمحدود کنید تا فضای دیسک پر نشود. - اگر چند اپلیکیشن Go روی یک سرور دارید، برای هر کدام یک فایل سرویس و یک server block جدا در Nginx تعریف کنید تا مدیریت و دیباگ هرکدام مستقل باشد.
جمعبندی
دیپلوی Go روی سرور اختصاصی یا VPS نیازی به ابزارهای پیچیده ندارد. یک باینری استاتیک، یک فایل سرویس systemd، و یک تنظیم ساده Nginx برای reverse proxy و HTTPS کافی است تا اپلیکیشن بهصورت پایدار و با ریاستارت خودکار در پروداکشن اجرا شود. این روش برای اغلب پروژههای Go، بهخصوص در مراحل اولیه یا با مقیاس متوسط، سریعتر از راهاندازی Docker یا Kubernetes به نتیجه میرسد.
اگر هنوز سروری برای اجرای این تنظیمات ندارید، میتوانید با یک VPS آریانت در چند دقیقه شروع کنید. برای پروژههایی که به منابع اختصاصی و پایدارتر نیاز دارند، سرور اختصاصی آریانت گزینه مناسبی برای اجرای همین تنظیمات در مقیاس بزرگتر است.




