Запуск CppCMS с Web-серверами
Введение
Существует множество способов соединить приложение CppCMS с web-сервером:
Протокол: можно использовать протоколы FastCGI или SCGI, а также запускать по HTTP-протоколу через прокси.
Рекомендация: используйте FastCGI, как лучше поддерживаемый в множестве web-серверов.
Запуск приложения: может стартовать и контролироваться web-сервером или запускаться независимым сервисом в последующем присоединеняющимся web-сервером.
Метод обмена данными: можно использовать доменные сокеты Unix или сокеты TCP/IP. Для локального обмена предпочтительней Unix-сокеты.
Обращаем Ваше внимание на то, что это руководство предназначено для запуска систем, основанных на CppCMS в рабочем окружении.
Это менее удобно для отладки. Если хотите отладить
приложение под веб-сервером, используйте утилиту cppcms_run
,
позволяющую автоматически подготовить конфигурации web-сервера
и запустить его.
Утилита позволяет запускать Ваши web-приложения под 3-мя наиболее популярными web-серверами: Apache, Lighttpd и Nginx с применением протоколов FastCGI, SCGI или используя их как Reverse HTTP Proxy.
Использование протокола HTTP
CppCMS обеспечивает базовую реализацию протокола HTTP и потому может работать под Reverse HTTP Proxy или использоваться во встраиваемых окружениях. Эта опция не рекомендуется в рабочем окружении, т.к. у внутреннего web-сервера довольно слабая производительность предоставления статических файлов и очень ограниченные возможности по сравнению с широко используемыми web-серверами.
Assumptions
Во всех наших примерах предполагается:
- Запускаемый файл приложения расположен в
/opt/app/bin/hello
- Конфигурационный файл расположен в
/opt/app/etc/config.js
- Корень документов -
/var/www
- URL приложения (скрипт) -
/hello
Lighttpd
Lighttpd поддерживает оба протокола fastcgi/scgi через сокеты unix и tcp/ip. Он может как запустить приложение самостоятельно, так и использовать внешнее приложение FastCGI/SCGI.
Lighttpd, FastCGI
Lighttpd, FastCGI, запуск Web-сервером
Вы должны включить mod-fastcgi и затем использовать этот конфигурационный файл:
fastcgi.server = ( ## Имя скрипта приложения "/hello" => (( ## Командная строка для запуска "bin-path" => "/opt/app/bin/hello -c /opt/app/etc/config.js", "socket" => "/tmp/hello-fcgi-socket", ## Важно - должен запускаться только 1 процесс "max-procs" => 1, "check-local" => "disable" )) )
Конфигурация CppCMS:
{ "service" : { "api" : "fastcgi", "socket" : "stdin" // использовать сокет сервера } }
Lighttpd, FastCGI, внешний запуск
Вы должны включить mod-fastcgi и затем использовать этот конфигурационный файл:
fastcgi.server = ( ## Имя скрипта приложения "/hello" => (( "socket" => "/tmp/hello-fastcgi-socket", ## Важно - должен запускаться только 1 процесс "max-procs" => 1, "check-local" => "disable" )) )
Конфигурация CppCMS:
{ "service" : { "api" : "fastcgi", "socket" : "/tmp/hello-fastcgi-socket" } }
Если хотите использовать TCP/IP вместо Unix-сокетов, замените
- В конфигурации lighttpd:
"socket" => "/tmp/hello-fastcgi-socket",
на"host" => "127.0.0.1", "port" => 8081,
- В конфигурации cppcms:
"socket" : "/tmp/hello-fastcgi-socket"
, на"ip": "127.0.0.1" , "port" : 8081,
Lighttpd, SCGI
Lighttpd, SCGI, запуск Web-сервером (lighttpd >=1.4.23)
Вы должны включить mod-fastcgi и затем использовать этот конфигурационный файл:
scgi.server = ( ## Имя скрипта приложения "/hello" => (( ## Командная строка для запуска "bin-path" => "/opt/app/bin/hello -c /opt/app/etc/config.js", "socket" => "/tmp/hello-fcgi-socket", ## Важно - должен запускаться только 1 процесс "max-procs" => 1, "check-local" => "disable" )) )
Конфигурация CppCMS:
{ "service" : { "api" : "scgi", "socket" : "stdin" // использовать сокет сервера } }
Lighttpd, SCGI, внешний старт
Вы должны включить mod-fastcgi и затем использовать этот конфигурационный файл:
scgi.server = ( ## Имя скрипта приложения "/hello" => (( "socket" => "/tmp/hello-scgi-socket", ## Важно - должен запускаться только 1 процесс "max-procs" => 1, "check-local" => "disable" )) )
Конфигурация CppCMS:
{ "service" : { "api" : "scgi", "socket" : "/tmp/hello-scgi-socket" // использовать сокет сервера } }
Если хотите использовать TCP/IP вместо Unix-сокетов, замените
- В конфигурации lighttpd:
"socket" => "/tmp/hello-scgi-socket",
на"host" => "127.0.0.1", "port" => 8081,
- В конфигурации cppcms:
"socket" : "/tmp/hello-scgi-socket"
, на"ip": "127.0.0.1" , "port" : 8081,
Apache
Apache, FastCGI
Вы должны включить как минимум два модуля: mod_fastcgi
и mod_alias
В каждом случае подготавливаем конфигурационный файл mod_fastcgi
и config.js.
Примечание: ниже представлен пример конфигурации fastcgi.conf. Учтите, что эти настройки влияют на весь web-сервер.
Если вместо этого Вы хотите установить это для влияния только на одинконкретный виртуальный хост, нужно поместить эти настройки в Ваш конфигурационный файл виртуального хоста (например, в /etc/apache2/sites-available
системы Debian).
Уточните детали в официальной документации Apache.
Apache, FastCGI, запуск Web-сервером
Конфигурация Apache:
FastCgiIpcDir /var/lib/apache2/fastcgi # Обычно это приведено в fastcgi.conf по-умолчанию FastCgiServer /opt/app/bin/hello -initial-env CPPCMS_CONFIG=/opt/app/etc/config.js -socket /tmp/hello-fcgi-socket # CPPCMS_CONFIG должен хранить путь к конфигурационному файлу. # Примечание: Вы не можете передать параметр командной строки, # поэтому передаете нахождение конфигурационного файла # через переменную окружения CPPCMS_CONFIG FastCGIConfig -maxProcesses 1 -processSlack 1 # Это важно - мы хотим чтобы apache использовал # только 1 процесс, т.к. наши кеш и многие другие # вкусности обрабатываются самостоятельно ScriptAliasMatch ^/hello(.*)$ /opt/app/bin/hello$1 # Отображаем скрипт "/hello" на наше приложение AddHandler fastcgi-script /opt/app/bin/hello
Конфигурация CppCMS:
{ "service" : { "api" : "fastcgi", "socket": "stdin" // используем сокет, предоставленный сервером } }
Apache, FastCGI, независимый старт
Конфигурация Apache:
FastCgiIpcDir /var/lib/apache2/fastcgi # Обычно это приведено в fastcgi.conf по-умолчанию FastCgiExternalServer /opt/app/bin/hello -socket /tmp/hello-fcgi-socket # Предоставляем сокет, на котором слушает приложение. ScriptAliasMatch ^/hello(.*)$ /opt/app/bin/hello$1 # Отображаем скрипт "/hello" на наше приложение AddHandler fastcgi-script /opt/app/bin/hello
Конфигурация CppCMS:
{ "service" : { "api" : "fastcgi", "socket": "/tmp/hello-fcgi-socket" // Так же, как и в конфигурации apache } }
Теперь Вам необходимо запустить приложение CppCMS независимо,
как /opt/app/bin/hello -c /opt/app/etc/config.js
Если хотите использовать сокеты TCP/IP вместо Unix-ных, замените
- в
FastCgiExternalServer
строковый параметр-socket
на-host 127.0.0.1:8081
- в конфигурации CppCMS замените
"socket": "/tmp/hello-fcgi-socket"
на"ip" : "127.0.0.1", "port" : 8081
Apache, SCGI
Apache-вский mod_scgi
поддерживает только независимый/внешний старт и работает только через сокеты TCP/IP, поэтому конфигурация довольно проста:
Конфигурация модуля Apache:
SCGIMount /hello 127.0.0.1:8081
Передадим имя скрипта как точку монтирования и ip:port как точку присоединения к приложению cppcms.
Конфигурация CppCMS:
{ "service" : { "api" : "scgi", "ip" : "127.0.0.1", "port" : 8081 } }
Теперь нужно запустить приложение CppCMS независимо
как /opt/app/bin/hello -c /opt/app/etc/config.js
и Apache должен соединиться с ним.
Nginx
Nginx поддерживает только протокол FastCGI с внешним стартом приложения.
Примечание: Модуль SCGI Nginx'а SCGI не работает, т.к. не удовлетворяет спецификациям SCGI: он требует скорее HTTP-ответ, чем CGI. Он вообще не генерирует переменные SCRIPT_NAME
и PATH_INFO
. Не используйте его!
Также модуль fastcgi Nginx'а т ребует ручной генерации
переменных SCRIPT_NAME
и PATH_INFO
.
Nginx, FastCGI
Конфигурация Web-сервера в секции server
:
# Нужно вручную создать переменую PATH_INFO # используя перезапись URL set $path_info ""; if ( $fastcgi_script_name ~ ^/hello(.*)$ ) { set $path_info $1; } # Указываем URL для совпадения location ~ ^/hello.*$ { # Сокет для обмена данными fastcgi_pass unix:/tmp/hello-fcgi-socket; # Все поддерживаемые переменные CGI fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME /hello; fastcgi_param PATH_INFO $path_info; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; }
И обычная конфигурация CppCMS:
{ "service" : { "api" : "fastcgi", "socket" : "/tmp/hello-fcgi-socket" } }
Конечно, сервис CppCMS должен запускаться независимо.
Для использования протокола TCP/IP замените:
- В конфигурации nginx строку
fastcgi_pass unix:/tmp/hello-fcgi-socket;
наfastcgi_pass 127.0.0.1:8081;
- В конфигурации CppCMS как обычно:
"socket" : "/tmp/hello-fcgi-socket"
, на"ip": "127.0.0.1" , "port" : 8081,
IIS
Перед тем, как пытаться использовать IIS поверх CppCMS, я бы рекомендовал выбрать другой web-сервер, более дружественный для web-разработчиков, использующих независимое API web-сервера, такое как FastCGI.
Лучший подход
Сконфигурируйте CppCMS с каким-нибудь другим хорошим web-сервером типа Apache или Nginx и перенаправьте к нему запросы из IIS.
Соединяемость HTTP
Это, пожалуй, наиболее надежный вариант. Перенаправляя все запросы относящиеся к web-приложению на внутренний web-сервер CppCMS - используйте IIS как обратный прокси.
Примечание: дайте IIS работу по предоставлению статических файлов. Он, скорее всего сделает ее лучше, чем внутренний web-сервер CppCMS.
Соединяемость FastCGI
FastCGI - не используйте его, он был создан для запуска PHP и ничего более.
Реализация FastCGI в IIS не работает и не поддерживает многопоточные приложения FastCGI.
Она также не предусматривает опцию для настройки конкретного порта, делая еще более невозможным использование приложений CppCMS с IIS.
Соединяемость SCGI
Использование с ISAPI SCGI.
Есть расширение SCGI ISAPI, позволяющее использовать внешние приложения SCGI: isapi_scgi
Однако, у него есть два больших ограничения:
Оно не поддерживает реальный ответ CGI от клиента и ожидает HTTP-ответа.
Начиная с CppCMS 0.99.10 возможно установить опцию
service.generate_http_headers
вtrue
. Эта опция говорит CppCMS генерировать заголовки ответа HTTP вместо CGI.Используя эту опцию возможно успешно запустить приложение CppCMS с IIS.
Оно поддерживает только предустановленный набор HTTP-заголовков, поэтому, если потребуется получить пользовательские заголовки, например из AJAX-ответов, придется изменять исходники
isapi_scgi
.
Чтобы сконфигурировать расширение ISAPI, следуйте инструкциям на этом web-сайте.
Конфигурация CppCMS должна быть сходна с этой:
{ "service" : { "api" : "scgi", "ip" : "127.0.0.1", "port" : 9999, "generate_http_headers" : true } }
Поиск неисправностей расширения ISAPI SCGI.
Прежде всего, Вы можете получить исходники isapi_scgi.dll
здесь:
http://twapi.cvs.sourceforge.net/viewvc/twapi/isapi/
Просто кликните Download GNU Tarball
.
Есть несколько причин его сборки самостоятельно:
Сейчас проект предусматривает только 32-битные сборки этого dll, если требуются 64-битные - нужно его собрать вручную.
Если требуется поддержка пользовательских заголовков HTTP, нужно добавить их в scgi.c.
Если хотите собрать его с gcc, нужно применить следующие изменения:
--- scgi_old.h 2011-08-17 10:48:32.109547500 +0300 +++ scgi.h 2011-08-17 10:50:26.184022000 +0300 @@ -37,3 +37,3 @@ */ -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__GNUC__) # define COPY_MEMORY(d, s, n) memcpy((d), (s), (n)) @@ -48,3 +48,3 @@ ZLINK_CREATE_TYPEDEFS(context_t); -typedef struct context { +struct context { OVERLAPPED ovl; /* Must be first structure */ @@ -81,3 +81,3 @@ buffer_t buf; /* Data buffer */ -} context_t; +};
И будет доступна сборка DLL как:
gcc -O2 -shared buffer.c scgi.c logger.c -lws2_32 -o isapi_scgi.dll
Конфигурирование других Web-серверов
Говоря о конфигурации web-серверов не упомянутых выше, Вы должны учитывать следующие моменты:
Если web-сервер позволяет запускать приложение, удостоверьтесь, что он запускает только один процесс.
Иначе можете столкнуться с проблемами с инвалидацией кеша, управлением сессиями и асинхронные приложения, скорее всего, не будут работать, т.к. не разделяют один и тот же процесс.
Удостоверьтесь, что поддержка FastCGI или SCGI удовлетворяет стандартам. Например: SCGI-коннекторы Nginx не обрабатывают HTTP-заголовок
Status
и создают некорректный ответ; SCGI-модуль IIS вообще не отсылает строку статуса HTTP и ожидает такого же вывода HTTP как и CGI.По возможности предпочтите протокол FastCGI, т.к. у реализаций SCGI обычно более низкое качество.
Именованные каналы не поддерживаются в платформе Microsoft Windows, должны использоваться только соединения TCP/IP.
Примечания: именованные каналы в Windows часто используются как замена Unix-сокетам, они не поддерживаются из-за очень различного поведения.
Удостоверьтесь, что CGI-переменные
SCRIPT_NAME
иPATH_INFO
установлены корректно. В нашем случае, для переданного URL/hello/you
SCRIPT_NAME
должен быть/hello
иPATH_INFO
должно быть/you
Примечание для пользователей CppCMS 0.0.x
Настройка web-сервера CppCMS 0.0.x аналогична CppCMS 1.x.x, т.к. они оба поддерживают протоколы FastCGI и SCGI, однако конфигурационный файл версии 0.0.x сильно отличается.
См.:
Протокол указывается как "service.api" с возможными опциями "fastcgi" и "scgi".
Однако, передача данных различна.
Доменный Unix-сокет определяется как:
service.socket = "/path/to/socket"
TCP/IP-сокет определяется как:
service.socket = "IP:PORT"
Сокет, взятый из стандартного ввода - просто удостоверьтесь, что
service.socket
не определен.
Например:
FastCGI, TCP/IP
CppCMS 1.x.x
{ "service" : { "api" : "fastcgi", "ip" : "127.0.0.1", "port" : 6000 } }
CppCMS 0.0.x
service.api = "fastcgi" service.socket = "127.0.0.1:6000"
SCGI, Unix-сокет
CppCMS 1.x.x
{ "service" : { "api" : "scgi", "socket" : "/tmp/app.sock", } }
CppCMS 0.0.x
service.api = "scgi" service.socket = "/tmp/app.sock"
FastCGI, стандартный ввод (запускается web-сервером)
CppCMS 1.x.x
{ "service" : { "api" : "fastcgi", "socket" : "stdin", } }
CppCMS 0.0.x
service.api = "fastcgi" # service.socket - не определен