Установка Asp.Net на Linux (nginx+mono+xsp)

    В этой статье я покажу, как настроить простую связку nginx + Asp.Net. Под простой надо понимать, что какие-то специфические особенности проектов, разграничение прав пользователей, высокие нагрузки и т.п. нужно настраивать отдельно (особенно это касается Asp.Net). Статья написана по просьбе хабраюзера mace.

    В свое время озадачившись проблемой хостинга маленьких Asp.Net-проектов я осознал одну простую вещь: покупать лицензию на Windows Server, а потом и арендовывать достаточно мощный выделенный/виртуальный сервер для каких-то домашних поделок/экспериментов — крайне неразумно. Решение как-то сразу всплыло в моей лысой голове: есть же Mono! Непродолжительный поиск по mono-project.com вывел на FAQ об Asp.Net. Фактически, документация показала мне три возможных варианта:

    You need the Mono runtime and use one of Apache with mod_mono, a CGI or FastCGI-aware web server with Mono's FastCGI support or the xsp standalone server (all available from our downloads page).

    Быстрый анализ интернета, для выбора одного из этих способов, привел меня к статье Максима Крентовского (mkrentovskiy), это достаточно забавно, т.к. спросить у Максима в аське я почему-то не догадался.

    Выводы Максима показались мне достаточно убедительными. Я не стал проводить какие-то дополнительные тесты или искать другие источники, для моей задачи ответ был уже очевиден: nginx + xsp. Учтите, в wiki Mono сказано, что xsp надо использовать для отладки и разработки!

    Установка nginx

    Итак, мы имеем свежеустановленный Debian Squeeze x64 Minimal. Самый простой вариант установки последних версий nginx — установка из репозиториев dotdeb.org. Кстати, очень хороший репозиторий: в нем, помимо nginx, всегда последние версии php, mysql (percona) и redis. Чуть сложнее установить из исходников — об этом чуть ниже.

    Добавим в sources.list новый репозиторий, пропишем GnuPG-ключ и обновим источники:
    root@falco:~# echo "deb http://packages.dotdeb.org stable all" >> /etc/apt/sources.list
    root@falco:~# wget -q http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
    root@falco:~# apt-get update
    

    Если все сделано правильно, то на команду apt-cache policy nginx мы увидим следующее:
    root@falco:~# apt-cache policy nginx
    nginx:
      Установлен: (отсутствует)
      Кандидат:   1.0.2-1~dotdeb.1
      Таблица версий:
         1.0.2-1~dotdeb.1 0
            500 http://packages.dotdeb.org/ stable/all amd64 Packages
         0.7.67-3 0
            500 http://mirror.yandex.ru/debian/ squeeze/main amd64 Packages
    

    Существует три разных пакета, собранных с разными наборами модулей: nginx-lite, nginx-full (пакет nginx как раз его алиас) и nginx-extras. Какой устанавливать — решать вам, нам бы хватило и lite версии (Proxy есть и ладно), но на момент написания статьи я уже установил full, поэтому будем устанавливать его:
    root@falco:~# apt-get install nginx
    

    Вот и все шаги для установки из пакетов.

    Если вы устанавливаете nginx из исходников, то ./configure надо запускать с такими параметрами:
    ./configure --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-debug --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-http_xslt_module --with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --with-mail --with-mail_ssl_module
    

    Это будет практически соответствовать пакету nginx-full, за исключением отсутствия сторонних модулей Upstream Fair Queue и Echo.

    Установка Mono

    Для Mono таких удобств с репозиториями нет, придется сразу компилировать последние исходники.

    upd. Как справедливо заметил Net_Rat, я немного слукавил: можно подключить экспериментальный репозиторий и через pining настроить установку mono и xsp оттуда.

    Качаем последние исходники mono и xsp (на момент написания 2.10.2):
    root@falco:~# wget "http://ftp.novell.com/pub/mono/sources/mono/mono-2.10.2.tar.bz2"
    root@falco:~# wget "http://ftp.novell.com/pub/mono/sources/xsp/xsp-2.10.2.tar.bz2"
    

    Теперь распакуем архивы:
    root@falco:~# tar -xvf mono-2.10.2.tar.bz2
    root@falco:~# tar -xvf xsp-2.10.2.tar.bz2
    

    Если tar ругнется на отсутствие bzip2 (в minimal точно ругнется), его нужно поставить:
    root@falco:~# apt-get install bzip2
    

    Для компиляции mono и xsp нам понадобится следующее:
    root@falco:~# apt-get install build-essential gawk bison gettext libgdiplus pkg-config libglib2.0-0 libglib2.0-dev
    

    Приступим к конфигурированию и компиляции (процесс непосредственно компиляции может занять продолжительное время, до 20-30 минут):
    root@falco:~/mono-2.10.2# ./configure --prefix=/usr --sysconfdir=/etc/mono
    root@falco:~/mono-2.10.2# make && make install
    

    Если установка прошла успешно, то запуск команды mono --version покажет нам заветное и долгожданное:
    root@falco:~/mono-2.10.2# mono --version
    Mono JIT compiler version 2.10.2 (tarball Сбт Июн 11 15:54:39 MSD 2011)
    Copyright (C) 2002-2011 Novell, Inc and Contributors. www.mono-project.com
            TLS:           __thread
            SIGSEGV:       altstack
            Notifications: epoll
            Architecture:  amd64
            Disabled:      none
            Misc:          softdebug
            LLVM:          supported, not enabled.
            GC:            Included Boehm (with typed GC and Parallel Mark)
    

    Теперь установим xsp:
    root@falco:~/xsp-2.10.2# ./configure --prefix=/usr --sysconfdir=/etc/xsp
    root@falco:~/xsp-2.10.2# make && make install
    

    Весь xsp написан на C#, компиляция должна пройти очень быстро. Проверим, что оно нам выдаст:
    root@falco:~# xsp4 --version
    xsp4.exe 2.10.2.0
    Copyright (C) 2002-2011 Novell, Inc.
    Minimalistic web server for testing System.Web
    

    Похоже, все схватилось. Пора переходить к настройке.

    Настройка Xsp

    Создадим директорию нашей будущей странички Hello World:
    root@falco:~# mkdir -p /var/www/asptest
    

    Сразу создадим классический «Hello World» для пробы:
    root@falco:~# cd /var/www/asptest
    root@falco:/var/www/asptest# nano Default.aspx
    

    В файле напишем следующие строки:
    <%@ Page language="C#" %>
    <html>
    	<head>
    		<title>Hello C#</title>
    	</head>
    	<body>
    		<p><% Response.Write("Hello World");%></p>
    	</body>
    </html>
    

    Поскольку xsp изначально задумывался как тестовый сервер, скриптов запуска демона там нет. Будем исправлять такую ситуацию. Создадим файл /etc/default/xsp, и запишем в него переменные по-умолчанию:
    user=www-data
    group=www-data
    
    port=8080
    address=0.0.0.0
    

    Создадим файл /etc/init.d/xsp, дадим ему права на выполнение (chmod +x /etc/init.d/xsp) и в него напишем:
    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides:          xsp
    # Required-Start:    $local_fs $remote_fs $network
    # Required-Stop:     $local_fs $remote_fs $network
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: Asp.Net testing server startup script.
    # Description:       Asp.Net testing server startup script.
    ### END INIT INFO
    
    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    DESC=xsp
    NAME=xsp
    DAEMON=/usr/bin/xsp4
    DEFAULT=/etc/default/$NAME
    DAEMON_ARGS="--nonstop --root /var/www/asptest"
    #DAEMON_ARGS="--nonstop --root /usr/lib/xsp/test"
    MONO_SHARED_DIR=/var/run/$NAME
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME
    
    [ -x "$DAEMON" ] || exit 0
    [ -f "$DEFAULT" ] && . $DEFAULT
    
    . /lib/lsb/init-functions
    
    if [ ! -e $MONO_SHARED_DIR ]; then
            mkdir $MONO_SHARED_DIR
            chown $user:$group $MONO_SHARED_DIR
    fi
    
    chk_start() {
            if [ -f "$PIDFILE" ]; then
                    xpid=`head -1 "$PIDFILE"`
                    xps=`ps -p $xpid | wc -l`
                    if [ "$xps" != "1" ]; then
                            log_action_msg "Xsp is running"
                            return 1
                    fi
            fi
            return 0
    }
    
    do_start()
    {
            export MONO_SHARED_DIR
            start-stop-daemon --start --background --make-pidfile \
                    --quiet --pidfile /var/run/$NAME.pid \
                    --user $user --group $group --chuid $user \
                    --exec $DAEMON -- \
                    --port $port --address $address \
                    $DAEMON_ARGS
    }
    
    do_stop()
    {
            if [ -e "$PIDFILE" ] ; then
                    kill -9 `head -1 "$PIDFILE"` 1>/dev/null 2>&1
                    rm -f "$PIDFILE"
            fi
    }
    
    case "$1" in
      start)
            if chk_start ; then
                    log_daemon_msg "Starting $DESC" "$NAME"
                    do_start
                    log_end_msg $?
            fi
            ;;
      stop)
            log_daemon_msg "Stopping $DESC" "$NAME"
            do_stop
            log_end_msg $?
            ;;
      status)
           ;;
      restart|force-reload)
            log_daemon_msg "Restarting $DESC" "$NAME"
            do_stop
            do_start
            log_end_msg $?
            ;;
      *)
            echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
            exit 3
            ;;
    esac
    
    :
    

    В скрипте запуска так же имеется закомментированная строка для папки с тестами из дистрибутива xsp, для более полноценной картины.

    Добавим его в автозапуск с дефолтными уровнями запуска (поправить по надобности) и запустим наш новый демон:
    root@falco:~# update-rc.d xsp defaults
    root@falco:~# /etc/init.d/xsp start
    

    По-умолчанию, сервер слушает на всех интерфейсах, проверить легко:
    root@falco:~# netstat -nlp | grep 8080
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      20839/mono
    

    Если перейти по http://serveraddr:8080/ можно увидеть долгожданное «Hello World»:


    А если вы переключите на тестовую страницу xsp, то:


    Настройка nginx

    Суть настройки nginx в проксировании обращений только для asp-файлов. Остальные статические файлы должен раздавать nginx. Не мудрствуя особо сильно, возьмем конфигурацию, которую предложил Максим Крентовский в своей статье и чуть-чуть изменим под наш случай:
    server {
            listen 80;
            server_name  serveraddr.ru;
            location / {
                    root /var/www/asptest
                    #root /usr/lib/xsp/test;
                    index index.html index.htm index.aspx default.aspx Default.aspx;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                    root   html;
            }
            location ~ \.(aspx|asmx|ashx|axd|asax|ascx|soap|rem|axd|cs|config|dll)$ {
                    root /var/www/asptest
                    #root /usr/lib/xsp/test;
                    proxy_pass   http://127.0.0.1:8080;
            }
    }
    

    Как управлять виртуальными хостами nginx лучше всего знает гугл.

    Открыв http://serveraddr.ru/ получаем долгожданное «Hello World»:


    Или, для тестовых настроек:


    Вот и все. Повторюсь, что в wiki Mono ясно указано, что xsp лучше использовать для тестов!

    Это мой первый пост на хабре, прошу не кидать в меня кирпичи и другие булыжники… Буду очень рад любой критике, как по содержанию статьи, так и по орфографии с пунктуацией. И да, я мог ошибиться с выбором блога. Если так — скажите куда лучше поместить.

    P.S. Сам я, хоть и люблю .Net/C#, с Asp.Net совершенно не знаком, даже Hello World из статьи писал с помощью Гугла. Так что задавать вопросы по Asp.Net и Asp.Net MVC мне бесполезно. :-)
    Поделиться публикацией

    Комментарии 36

      +3
      Повторюсь, что в wiki Mono ясно указано, что xsp лучше использовать для тестов
      Да ладно, месяцами стабильно и шустро работает, чего нельзя сказать про их реализацию FastCGI.
        0
        именно, поэтому своим друзьям я настроил именно так. FastCGI, к сожалению, пока неудел.
          +4
          Скрыть панель вкладок Ctrl + Shift + B. А скрыть кнопку расширения ПКМ -> Спрятать кнопку.
          Это что бы не портили скриншоты в дальнейшем или используйте инкогнито (Ctrl + Shift + N)
            0
            в инкогнито все-равно висит, я попробовал. ;-)
            спасибо за горячие клавиши, учту.
        +2
        <тонко>
        > root@falco:~/mono-2.10.2# ./configure --prefix=/usr --sysconfdir=/etc/mono
        > root@falco:~/mono-2.10.2# make && make install
        > 12 июня 2011, 01:27
        > 2011

        </тонко>

        <толсто>собрать свой пакет слабо?</толсто>
          +2
          Для Mono таких удобств с репозиториями нет…

          Как это нет? А это?

            –1
            Да, вы правы, можно подключить экспериментальную ветку и через Pin настроить обновление Mono и Xsp оттуда.
            При этом, именно экспериментальную, т.к. в других используется lts-версия 2.6.*, которая не поддерживает .net 4 и точно не работает с MVC 3.
              0
              Что мешает выкачать пакет исходного кода из experimental, собрать у себя и поднять отдельную репу?
                –1
                по-моему, через pining как-то… быстрее что-ли.
                а если собирать пакет, то тогда уж лучше из исходников, т.к. свежая версия — 2.10.2, против 2.10.1 в experimental. у меня xsp работает только на одном виртуальном сервере, там всего два сайта, я не видел смысла собирать для этого пакет. если вечером будет свободное время — попробую собрать.
          –1
          А меня в прошлой теме «сервер за 2000» за совет перейти на бздю+mono заминусовали :o что то тут не чисто…
            +3
            Наверное потому, что та тема была про сервер баз данных.
            0
            Можно чуть-чуть подкорректирую?
              0
              Блин!!! Отправилось :(
              root@falco:~# echo «deb packages.dotdeb.org stable all» >> /etc/apt/sources.list
              лучше, имхо, использовать /etc/apt/sources.list.d/dotdeb.list, куда просто через > сложить

              опечатка про «mininal»

              Очень напрягает, что xsp будет запущен от рута. Это так и задумано? Как с безопасностью в этом плане? Может, стоит добавить переключение на юзера www-data или там xsp?

                0
                насчет sources.list — это дело на любителя ;)
                опечатку поправил.
                Очень напрягает, что xsp будет запущен от рута. Это так и задумано? Как с безопасностью в этом плане? Может, стоит добавить переключение на юзера www-data или там xsp?
                я переписал это место статьи, посмотрите пожалуйста.
                  0
                  --root я бы тоже вынес в конфиг.
                  о, еще и start-stop-daemon, теперь совсем кошерно :)
              0
              Как потребление ресурсов (память\проц) xsp частью?
                –1
                я, к сожалению, не могу ответить вам по каким-то реальным цифрам. у меня хостятся две домашние поделки, на которые никто кроме авторов не ходит — там нагрузки нет вообще никакой…
                  0
                  Я на xsp держу hivemind.me. Нагрузка на проц вообще не чувствуется, памяти вместе со всеми кэшами кушает что-то около 80-90 мегабайт.
                  +3
                  Не сочтите за рекламу, но может кому-то поможет, недавно запускал тестовую страничку на моно и законспектировал телодвижения.

                  Установка тоже из исходников, запуск через fastcgi, ставилось на убунту.
                    +3
                    покупать лицензию на Windows Server, а потом и арендовывать достаточно мощный выделенный/виртуальный сервер
                    лицензию покупать не обязательно, можно ее тоже арендовать (ну или бесплатно получить, если вы студент или по bizspark). Также как необязательно и арендовать сервер, можно купить :)

                    Я, кстати, плачу ~500 руб в месяц за лицензию Windows Server 2008 R2 для своего выделенного сервера с 12 Гб оперативки + 1,5Тб хард. Не очень большие деньги, можно себе позволить, чтобы запускать стафф на нативной среде.

                    Хотя за статью спасибо. Интересны баги, насколько хорошо работает это дело, есть реальные проекты, которые хостятся на mono?
                      –2
                      Согласен.
                      Но хотел бы расширить этот вопрос и отметить, что к выбору между хостингом на MS Windows (подразумевается IIS) и Linux (подразумевается xsp2) стоит подходить с учетом всех особенностей.
                      Хоть я и не знаком с результатами специальных тестов, но что то мне подсказывает, что хостинг на Windows будет более производительным и надежным, но! Не всегда это нужно. Например, корпоративное приложение, которое «смотрит» в Intranet с общим количеством пользователей около нескольких десятков, с частотой посещения один пользователь в день — использование xsp2 может быть вполне оправдано. Так же использование xsp2 может быть оправдано в том случае, если предпологается разворачивание сервера на виртуальной машине (сервер развернутый под Linux в общем случае будет менее требователен к системным ресурсам).
                      А если речь идет о создании электронного магазина, который должен в течении месяца должен завоевать весь рынок, то пожалуй, я бы воздержался от использования xsp2.

                      Я это к тому, что дело тут не только в стоимости, как таковой.
                        +1
                        Согласен. Все задачи надо решать в разумных пределах. Скажем, на моей бывшей работе была специальная система trouble ticket'ов для трех человек из тех.поддержки. Хостилась прямо на XP-тачке одного из чуваков. Этого было более, чем достаточно.
                          +1
                          Спасибо!
                          хостинг на Windows будет более производительным и надежным
                          Вот надежность тоже сыграла свою роль. Я в администрировании Windows просто профан, вообще ни черта не понимаю. В linux вроде кое-что знаю и умею, в конце концов есть друзья, которые умеют в нем еще больше. С Windows, в этом смысле, очень туго. Не стал об этом писать в статье, как-то стыдно что ли… :)
                          0
                          да я вообще сначала хотел встать в позу, чтобы на руби, пиэйчпи или еще чём-то переделали! :)
                          проблема с лицензией решилась через месяц, когда появилась подписка MSDN. но за отдельную железяку, для некоммерческих проектов, которые вообще денег не приносят, платить все-равно жаааалко. даже если арендовывать в хетзнере. а виртуалка с linux уже была и окупалась, вот и решение пришлось найти.

                          баги и работоспособность — это интересный момент.
                          касательно работоспособности asp.net: чтобы успешно запустить сайты на asp.net mvc3 надо внимально почитать вот это. о багах я ничего не знаю.
                          касательно mono в целом (как раз пишем тут приложение-сервер, которое и под моно должно работать и под .net): бо́льшая часть проблем — из-за изначальной криворукостизабывчивости и решается очень просто, скажем, .net понимает
                          private static string[,] _objTables = {};
                          , а для того, чтобы mono понял нужно написать явно:
                          private static string[,] _objTables = {{}};
                          иначе будет Invalid IL code in Namespace.SampleClass:.cctor (): IL_0015: newobj

                          часто сталкиваешься с тем, что сторонние библиотеки на mono не тестируют. например, nlog 2, якобы работающий под mono — имеет неприятный баг, который тянется еще с mono 2.8, а его никак не поправят. приходится самому искать костыли или поправлять. или вообще искать замену… получается, что во время разработки приходится тратить много времени на адаптацию того, что на .Net работает как часы.

                          поплясав так 1-2 раза уже набиваешь руку и запоминаешь тонкости.

                          еще есть проблема с обфускацией и защитой программ. мы пока так и не нашли подходящего обфускатора, чтобы полученный результат работал на .Net так и на Mono одинаково. надвигается страшный момент осознания того, что, возможно, придется писать свой… :(
                            0
                            Дотфускатор вполне неплохо справляется. Бинарь работает как под .NET, так и на Mono 2.6+
                              –1
                              да, но цена у него кусачая до ужаса… надо попробовать подцепить триал к агентам в teamcity.
                              спасибо!
                          –3
                          Да… Батенька знает толк в извращениях…

                          Если серьезно — технически, конечно, интересное и нестандартное решение, но врядли кто-то будет держать Production на связке Linux и ASP.NET.
                            +4
                            Я год почти держу на этой связке биллинг. Падало два раза из-за моей собственной криворукости.
                              +1
                              Прецеденты есть. Особенно это актуально, если есть большой штат .net разработчиков и не хочется платить сторонним. По крайней мере, немалый процент мелкомягких разрабов редко кодят на разных платформах…
                              0
                              Эх, вашу бы статью да пол годика назад, а то пришлось все крутить в авальном режиме вкривь и вкось. Хотя, говорят, до сих пор работает) В любом случае — в закладки)
                                0
                                Что можете сказать о производительности этой связки?
                                  +1
                                  А как быть с MS SQL под который заточены ASP .Net приложения? Он-то под linux работать не хочет.
                                    +1
                                    Oracle/Mysql/Sqlite/PostgreSql Выбирайте, еще есть и другие
                                    Asp.net не заточены под MS SQL, на сколько я знаю в Asp.net есть драйвер для работы с бд, но это не значит обязательно MS SQL
                                      +2
                                      Все верно, но львиная доля ASP .Net проектов под MS SQL :)
                                        +2
                                        Если мне заказали проект, и я его делаю, то мне всеравно куда смотрил львинная доля =)
                                      0
                                      Есть вундервафля, изображающая из себя MS SQL и использующая PostgreSQL в качестве хранилища.

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое