Доброго дня, господа. Сегодня мы затронем тему, за обсуждение которой ещё два года назад сожгли бы на костре — запуск ASP.NET приложения под linux. В данной статье будет использоваться Ubuntu 16.04
Для начала, добавим dotnet-репозиторий:
На выходе получаем примерно следующее:
![image](https://lh5.googleusercontent.com/T8thm-Uwx8BCo6k4vRyUWx1mXWpaaQ9g28AaItYSFhkxUAjerpLvNXNuzl9Hg7KUVSZYkwYWEZi0NsFT8sw4U4EhHi5n-mTtbHdit9_3SJamVCrGm2FSewsXciZVXXTVUqdRngOq)
Теперь обновим индекс наших пакетов:
Далее, мы можем просто установить dotnet-пакет при помощи apt-get:
Теперь можем смело приступать к созданию приложения
При помощи команды
На текущий момент (07.2017), команда dotnet new поддерживает следующие шаблоны:
![image](https://lh3.googleusercontent.com/J_OiD7Zxs5kTsESuZ5qFwzsBJrGZybZaVAI0KS8UCVmvYFdWforhepgLOxTiT9ZaikFJkhQ9-lLjBYPXjV8_JEZ-_RHIa6KxSXmWLn30b9UJXi8m0PeS4OBnryWmdLPhjQ-tVQrz)
Мы создадим веб-приложение ASP.NET Core:
На выходе консоль выдаст нам следующее сообщение:
![image](https://lh3.googleusercontent.com/ScmADtUTKLdWjOXROrj7cjsYZ2LppOB4iw7oFbHM0my5W8frlcGYgfv6pz-9G7uI23Lah06F2iERvAfGaYpTk_w8bE35nXxjqO-GU7JZCf6qNuXIDxkUATaMwU-6dcAI0R0_elEh)
Чтобы убедиться, что шаблон сгенерировался правильно, заглянем в содержимое папки при помощи команды
![image](https://lh3.googleusercontent.com/rCsacytu5dlwao7_vKCXQgcTKAQx0dEWfffgP90o45ujf2NI4cyfJfSYgHhFa69veUcf2RBwbuMoIRprbLs8qiEKoNbIplK07avs9ZmUncz2uNKHt0Is-cN92_ZkDyK22I9cBnhF)
Все необходимые папки для сборки приложения на месте, приступим! Для начала, восстановим все пакеты при помощи
![image](https://lh3.googleusercontent.com/k3wLKo-GCSuIieqoIuma_4nRspCgaIiGIJDc6oLLgWdiVjupwJ8KVD1JZ0MzoXVLRfNTPy42Z2Vl0ZAO3wy58sxVYhyAPJSLiVZ7E1avv-n38qWeDKwS-JWLwqnhHcx0LMOzouc-)
Теперь можем собрать приложение:
![image](https://lh3.googleusercontent.com/jZsCXbHJzJq90GaTgk_50hhkGp32FdYUWH6Jlqr8Jw5WBEIfHSVifFElVzu-2R4kN6oHDTMD8ukMS0pLfM4eHkgu4dVtuzQQd0RtZoONe9DLAqVM84n4_kg5qzIhA-3mhmNlUPsH)
Запустим приложение с помощью:
![image](https://lh3.googleusercontent.com/8eMwOR2M7RQgi5goKW6nlLUazYg2c5MyATp64KHX0y49zMbbtigdeWrJBgcVhR5yA9X4G5lEW9Xmx11MWi9cWzrDcGF0uQrlq5b-_Cc-Re8G2L8OQslGcXhyC0tl3I3msLrNSCM4)
Консоль говорит нам, что приложение запустилось по адресу localhost:5000/. Проверим:
![image](https://lh4.googleusercontent.com/B0mqIqAwIVk6-LdqeeGKxvIhsuWfj7FIpPodkzJzgmZKih2otQK9Ky8C9o2PeEmfu7ItFc7q4KK7YGeqdfn1aJQo5of4Zs0Ygn7LssHdyUpjcSx06XQjQ44JalavMvA5ni2Ex2H0)
Желающих подробнее узнать, как работает web-сервер отсылаю к официальному источнику.
Теперь убьём процесс нажав Ctrl + C и опубликуем приложение командой dotnet publish. Эта команда упаковывает приложение и все его зависимости для дальнейшего развёртывания (желающим интимных подробностей сюда).
В случае проблем с правами доступа Вам поможет команда sudo chmod и эта страница документации.
Развертывание на сервере.
Если мы хотим развернуть наше приложение под linux-сервером, необходимо настроить прокси и демонизировать процесс запуска приложения. Для проксирования мы будем использовать nginx, для демонизации процесса systemd. Краткое описание утилиты
Создаём прокси-сервер.
Как следует из документации выше, с asp.net core в коробке идет kestrel — веб-сервер для asp.net приложений. Зачем нам тогда нужен прокси-сервер? Ответ даётся на официальной странице Microsoft:
![image](https://lh3.googleusercontent.com/AT8_qy9C2RuO2luf_6M5z1VzirJH1pAbUum2TXdj567ZHAc2yXFsLYjoommSvHVpV6-siQw0wawVVdqBGh3iGZYlUMouwlA47NpSS3uz8ymVyieiBcKN_jp7K6xver_p-C4xWyWE)
Как говорилось выше, в качестве прокси-сервера мы будем использовать nginx.
Т.к. в качестве прокси-сервера у нас используется не IIS, следует добавить следующие строки в метод Configure файла Startap.cs.
Здесь мы включаем поддержку ForwardedHeaders мидлвера из пакета. Microsoft.AspNetCore.HttpOverrides, который будет вставлять в Http-запрос заголовки X-Forwarded-For и X-Forwarded-Proto, использующиеся для определения исходного IP адреса клиента и передачи его прокси-серверу. Определение мидлверов и практическое использование так же будет рассмотрено в дальнейших частях этого гайда.
Если у Вас nginx не установлен, выполните следующую команду.
и запустите его командой:
Далее, нам необходимо сконфигурировать nginx для проксирования http-запросов.
Создадим файл /etc/nginx/sites-available/aspnetcore.conf. Папка sites-avalible укахывает nginx-у, какие веб-сайты доступны на текущем сервере для обработки. Добавим в него следующие строки:
Создадим символическую ссылку на aspnetcore.conf в папку sites-enabled, в которой отражаются запущенные nginx-ом сайты.
Nginx настроен на то, чтобы принимать запросы с localhost:8888. Перезапускаем nginx командой
![image](https://lh3.googleusercontent.com/MBNt3MIRuXCIg08raLLrtE9wlRvk1I6PBvOfdbTJDSNEi3I_qTx3TNnECaYpC61D2Kq3q7FWUsH-Sfk6KLynu1hemZ2D5jf48SoEhVBr8J0ba2FMofm64VPGP1D0zRZeNXWINRi6)
502-я ошибка говорит, что сервер перенаправляет нас в другое место и в этом месте что-то пошло не так. В нашем случае — я убил процесс с нашим веб-приложением, которое было ранее запущено командой dotnet run. Потому что могу :)
На самом деле, потому что запускать dotnet run в консоли и вечно держать эту вкладку открытой грустно. Именно поэтому процесс будем демонизировать, то есть настроем автозапуск после перезагрузки и автоматическую работу в фоне с помощью systemd.
Для этого создадим файл в директории /etc/systemd/system/ с расширением .service
Назовём его kestrel-test:
И положим в него следующее содержимое:
Теперь включим и запустим сервис при помощи следующих команд:
Проверим статус сервиса:
Если всё было сделано правильно, на эта команда выдаст нам следующее:
![image](https://lh6.googleusercontent.com/ScViWYWIqpyUCR-4jZJwXieM9naJL9AlILN81Rhic-4b3EQjsfxqIbOvlKuYymVzvBNBmR1TkgHRU3p-kRgb3_QE7bxfxEwl_D1FE4n_-XAcaw79kYxkJYtqEvoDvSGpODFYFT2M)
Перейдём по ссылке ещё раз:
![image](https://lh4.googleusercontent.com/u7Ofxz27AsXYcZWJO6eDLAmNwxdoEjbLx88eQYrlKKtGS89Lz_Ux2UY4DmB_Kg8yAioXHrWWbExHTQk3E-nLGytyQ9_bxr9mXB-9oUKaGHJ8go7hrUFgTvm8jWGZVNAleF-VZPOf)
Ну вот, дело в шляпе. Спасибо за внимание!
Подготовка окружения
Для начала, добавим dotnet-репозиторий:
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
На выходе получаем примерно следующее:
Теперь обновим индекс наших пакетов:
sudo apt-get update
Далее, мы можем просто установить dotnet-пакет при помощи apt-get:
sudo apt-get install dotnet-dev-1.0.4
Теперь можем смело приступать к созданию приложения
Создание приложения
При помощи команды
dotnet new
мы можем создать шаблон для нашего приложения, подобно шаблонам из Visual Studio. Подробная документация к команде.На текущий момент (07.2017), команда dotnet new поддерживает следующие шаблоны:
Мы создадим веб-приложение ASP.NET Core:
dotnet new mvc
На выходе консоль выдаст нам следующее сообщение:
Чтобы убедиться, что шаблон сгенерировался правильно, заглянем в содержимое папки при помощи команды
ls -la
.Все необходимые папки для сборки приложения на месте, приступим! Для начала, восстановим все пакеты при помощи
dotnet restore
.Теперь можем собрать приложение:
dotnet build
Запустим приложение с помощью:
dotnet run
Консоль говорит нам, что приложение запустилось по адресу localhost:5000/. Проверим:
Желающих подробнее узнать, как работает web-сервер отсылаю к официальному источнику.
Теперь убьём процесс нажав Ctrl + C и опубликуем приложение командой dotnet publish. Эта команда упаковывает приложение и все его зависимости для дальнейшего развёртывания (желающим интимных подробностей сюда).
В случае проблем с правами доступа Вам поможет команда sudo chmod и эта страница документации.
Развертывание на сервере.
Если мы хотим развернуть наше приложение под linux-сервером, необходимо настроить прокси и демонизировать процесс запуска приложения. Для проксирования мы будем использовать nginx, для демонизации процесса systemd. Краткое описание утилиты
Создаём прокси-сервер.
Как следует из документации выше, с asp.net core в коробке идет kestrel — веб-сервер для asp.net приложений. Зачем нам тогда нужен прокси-сервер? Ответ даётся на официальной странице Microsoft:
Если вы выставляете ваше приложение в интернет, Вы должны использовать IIS, Nginx или Apache как обратный прокси-сервер.
Если Вы не знаете, что такое обратный прокси-сервер
Обратный прокси-сервер получает HTTP запросы из сети и направляет их в Kestrel после первоначальной обработки, как показано на след диаграмме:
Главная причина, по которой следует использовать обратный прокси сервер — безопасность. Kestrel относительно нов и ещё не имеет полного комплекта защиты от атак.
Ещё одна причина, по которой следует использовать обратный прокси-сервер — наличие на сервере нескольких приложений, использующих один порт. Kestrel не поддерживает разделение одного порта между несколькими приложениями.
Так же, использование обратного прокси-сервера может облегчить распределение нагрузки и поддержку SSL.
Как говорилось выше, в качестве прокси-сервера мы будем использовать nginx.
Т.к. в качестве прокси-сервера у нас используется не IIS, следует добавить следующие строки в метод Configure файла Startap.cs.
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
Здесь мы включаем поддержку ForwardedHeaders мидлвера из пакета. Microsoft.AspNetCore.HttpOverrides, который будет вставлять в Http-запрос заголовки X-Forwarded-For и X-Forwarded-Proto, использующиеся для определения исходного IP адреса клиента и передачи его прокси-серверу. Определение мидлверов и практическое использование так же будет рассмотрено в дальнейших частях этого гайда.
Если у Вас nginx не установлен, выполните следующую команду.
sudo apt-get install nginx
и запустите его командой:
sudo service nginx start
Далее, нам необходимо сконфигурировать nginx для проксирования http-запросов.
Создадим файл /etc/nginx/sites-available/aspnetcore.conf. Папка sites-avalible укахывает nginx-у, какие веб-сайты доступны на текущем сервере для обработки. Добавим в него следующие строки:
server {
listen 8888; # указываем порт, по которому nginx будет слушать запросы
location / {
proxy_pass http://localhost:5000; # указываем порт нашего приложения
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Создадим символическую ссылку на aspnetcore.conf в папку sites-enabled, в которой отражаются запущенные nginx-ом сайты.
sudo ln -s /etc/nginx/sites-available/aspnetcore.conf /etc/nginx/sites-enabled/aspnetcore.conf
Что такое символическая ссылка
(символическая ссылка — специальный файл в файловой системе, в котором вместо пользовательских данных содержится путь к файлу, открываемому при обращении к данной ссылке (файлу)(С) Википедия — прим. авт.)
Nginx настроен на то, чтобы принимать запросы с localhost:8888. Перезапускаем nginx командой
sudo service nginx restart
, чтобы созданные нами конфигурационные файлы вступили в силу. Проверяем:502-я ошибка говорит, что сервер перенаправляет нас в другое место и в этом месте что-то пошло не так. В нашем случае — я убил процесс с нашим веб-приложением, которое было ранее запущено командой dotnet run. Потому что могу :)
На самом деле, потому что запускать dotnet run в консоли и вечно держать эту вкладку открытой грустно. Именно поэтому процесс будем демонизировать, то есть настроем автозапуск после перезагрузки и автоматическую работу в фоне с помощью systemd.
Для этого создадим файл в директории /etc/systemd/system/ с расширением .service
Назовём его kestrel-test:
sudo nano /etc/systemd/system/kestrel-test.service
И положим в него следующее содержимое:
[Unit]
Description=Example .NET Web API Application running on Ubuntu
[Service]
WorkingDirectory=/home/robounicorn/projects/asp.net/core/test-lesson/bin/Debug/netcoreapp1.1/publish #путь к publish папке вашего приложения
ExecStart=/usr/bin/dotnet /home/robounicorn/projects/asp.net/core/test-lesson/bin/Debug/netcoreapp1.1/publish/test-lesson.dll # путь к опубликованной dll
Restart=always
RestartSec=10 # Перезапускать сервис через 10 секунд при краше приложения
SyslogIdentifier=dotnet-example
User=root # пользователь, под которым следует запускать ваш сервис
Environment=ASPNETCORE_ENVIRONMENT=Production
[Install]
WantedBy=multi-user.target
Теперь включим и запустим сервис при помощи следующих команд:
sudo systemctl enable kestrel-test.service
sudo systemctl start kestrel-test.service
Проверим статус сервиса:
sudo systemctl status kestrel-test.service
Если всё было сделано правильно, на эта команда выдаст нам следующее:
Перейдём по ссылке ещё раз:
Ну вот, дело в шляпе. Спасибо за внимание!