MAATRIX / Блог / VPS для .NET / ASP.NET Core на Linux

VPS для .NET / ASP.NET Core на Linux

VPS для .NET и ASP.NET Core на Linux: деплой и systemd
Блог MAATRIX · 2026-07-07

ASP.NET Core давно кроссплатформенный и отлично работает на Linux. Разберём публикацию проекта, установку рантайма, запуск Kestrel под systemd и проксирование через nginx с TLS.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

.NET на Linux: что важно знать

Современный .NET (6/8 LTS) полностью работает на Linux без Mono и Windows-зависимостей. Встроенный веб-сервер Kestrel быстрый и продакшн-готовый, но наружу его принято закрывать nginx.

Публиковать можно двумя способами: framework-dependent (нужен установленный рантайм на сервере) или self-contained (рантайм упакован в сборку). Первый компактнее, второй не требует ставить .NET на VPS.

  • Kestrel — быстрый встроенный сервер.
  • Два режима публикации — с рантаймом или без.
  • LTS-версии — 3 года поддержки, стабильность для прода.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS для .NET

Установка рантайма

Для framework-dependent публикации ставим ASP.NET Core Runtime из репозитория Microsoft.

sudo apt update
sudo apt install -y wget nginx
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install -y aspnetcore-runtime-8.0

Публикация приложения

Собираем локально в конфигурации Release. Для self-contained укажите рантайм-идентификатор.

# framework-dependent
dotnet publish -c Release -o ./publish

# self-contained (рантайм не нужен на сервере)
dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish
scp -r ./publish/* appuser@SERVER_IP:/opt/dotnetapp/

Запуск Kestrel под systemd

Kestrel слушает локальный порт, systemd управляет процессом. Задаём окружение Production и адрес привязки.

[Unit]
Description=ASP.NET Core app
After=network.target

[Service]
User=appuser
WorkingDirectory=/opt/dotnetapp
ExecStart=/usr/bin/dotnet /opt/dotnetapp/MyApp.dll
Restart=always
RestartSec=5
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://127.0.0.1:5000

[Install]
WantedBy=multi-user.target

Для self-contained в ExecStart укажите путь к бинарнику: /opt/dotnetapp/MyApp. Переменная ASPNETCORE_ENVIRONMENT=Production переключает приложение в боевой режим: отключает детальные страницы ошибок и включает production-конфигурацию из appsettings.Production.json.

Строки подключения и секреты не храните в appsettings — передавайте их через переменные окружения systemd или через EnvironmentFile с правами 600. .NET автоматически читает переменные с префиксом и мапит их на конфигурацию.

sudo systemctl daemon-reload
sudo systemctl enable --now dotnetapp
journalctl -u dotnetapp -f

Проверить, что Kestrel действительно слушает локальный адрес, можно прямым запросом с сервера — так вы отделите проблемы приложения от проблем nginx.

curl -i http://127.0.0.1:5000/

nginx и заголовки прокси

ASP.NET Core должен доверять заголовкам forwarded, чтобы корректно определять схему и IP клиента. В коде подключите ForwardedHeaders, а в nginx пробросьте нужные заголовки.

server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d example.com

Железо и частые ошибки

JIT-компиляция и работа GC в .NET чувствительны к скорости CPU и диска. AMD EPYC + NVMe у MAATRIX дают быстрый холодный старт и стабильную латентность, а от $8/мес и ежедневных бэкапов удобно держать прод. Локации UK/США/РФ и оплата из России (карта РФ, СБП, крипта, MAAT) решают вопрос зарубежного сервера.

  • Забыли ForwardedHeaders — приложение видит IP nginx, ломается редирект на HTTPS.
  • Несовпадение версии рантайма — сборка под 8.0 не запустится на рантайме 6.0.
  • ASPNETCORE_URLS на 0.0.0.0 — Kestrel торчит наружу мимо nginx.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.

Арендовать VPS для .NET

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Нужен ли Windows-сервер для .NET?

Нет. Современный .NET кроссплатформенный, ASP.NET Core на Linux работает штатно и часто дешевле в хостинге.

Self-contained или framework-dependent?

Self-contained не требует ставить рантайм на сервер и изолирует версию, но весит больше. Framework-dependent компактнее при установленном рантайме.

Как обновить .NET-приложение?

Скопируйте новую публикацию в каталог и выполните systemctl restart dotnetapp. Для нулевого простоя используйте два инстанса за балансировщиком.