Ключевые слова:apache, web, java, tomcat, xml, virtual, solaris, (найти похожие документы)
Date: 6 Sep 2002
From: Александр Владыкин <vladykin@freemail.ru>
Subject: Как сделать вебхостинг Apache + Tomcat4
Как сделать вебхостинг Apache + Tomcat4
-------------------
Автор: Glenn Nielsen
Перевод: Александр Владыкин <vladykin@freemail.ru>
Оригинал статьи: http://www.mail-archive.com/tomcat-user@jakarta.apache.org/msg61789.html
Обзор
=====
Существует множество проблем конфигурации и безопасности. которые разрешаются
при правильной установке Apache и TomCat 4 для виртуального хостинга.
Главные проблемы:
1. Выдача неблагонадежным покупателям хостинга прав на запуск их приложений
без страха за нарушение безопасности на сервере;
2. Конфигурирование Apache и Tomcat для виртуального хостинга;
3. Выживание плохо написанных веб-приложений, проинсталлированных покупателями.
Эта проблема включает в себя устойчивость к сбоям и идентификацию приложения,
которое вызвало проблемы;
4. Минимизация количества настраиваемых руками параметров, которые системные ад-
министраторы должны делать
Эта статья написана основываясь на моем опыте установки такого типа программного
обеспечения для хостинга на операционную систему Sun Solaris. Некоторые из настроек
специфичны только для Solaris, но в основном подойдут практически для любой юниксоподобной
операционной системы.
Аккаунты и группы пользователей Юникс
Пользователь "tomcat" создан для запуска tomcat, он играет
ту же роль, что и пользователь "nobody" для запуска apache.
Пользователь "tomcat" связан с группой "tomcat". Пользователь
"tomcat" является также членом группы "user".
Группа "tomcat" создана как группа. с которой связан пользователь
"tomcat".
Группа "user" создана, как группа для покупателей хостинга, с ней
связаны пользователи, которые имеют аккаунты ftp для сервера.
Каждый покупатель имеет свой собственный ftp-аккаунт, который принадлежит
группе "user".
Также существует администратор - пользователь "webmaster", который
имеет доступ к оболочке. Пользователь "webmaster" принадлежит к
группе "user" и также состоит членом в группе "tomcat".
Расположение директорий
Расположение директорий сделано таким образом, чтобы быть
максимально удобным покупателю для управления содержанием
веб-сайта и приложений.
Вот пример, как я сделал это:
Покупатель имеет FTP аккаунт, который имеет полные права на
чтение и запись в директории своего виртуального хоста.
Например, покупателя можно связать с директорией:
/export/home/www.customer.com root:other 755
--------------------------------------------
В этой директории и ее поддиректориях пользователь имеет право
на чтение и запись. Посмотрим на директории, которые здесь на-
ходятся:
www webmaster:user 2775
-----------------------
Это корневая директория для Apache. Покупатели и tomcat могут
читать и писать в эту директорию.
logs root:other 755
-------------------
директория, где расположены файлы логов Apache - access_log и
error_log. Мы также перемещаем эти файлы каждую неделю, и, ис-
пользуя bzip2 архивируем те, у которых давность превышает 5 не-
дель. Файлы логов, давность которых не превышает 5 недель остаются
все еще не заархивированными, и, таким образом, могут быть обработаны
программами ведения статистики, такими как Analog. Покупатели
могут читать файлы из это директории, но не имеют права записи в нее.
tomcat tomcat:tomcat 755
------------------------
директория, используемая для работы tomcat и логов виртуального хоста
tomcat. Только tomcat может писать в эту директорию. Покупатели могут
читать файлы из этой директории.
tomcat/work tomcat:tomcat 755
-----------------------------
Рабочая директория Tomcat для виртуального хоста. Только tomcat может
записывать сюда файлы. Покупатели могут читать файлы. Это дает покупателю
возможность видеть исходники, генерируемые компилятором JSP.
tomcat/logs tomcat:tomcat 755
------------------------------
Директория для логов Tomcat. Только tomcat иожет записывать сюда файлы.
Покупатели могут читать файлы. Это позволяет покупателю видеть логи,
оставленные их приложениями.
reports webmaster:tomcat 2775
-----------------------------
Директория, в которую я помещаю информацию, для покупателя.
Она внедрена в пространство пользователя и может быть запаролирована
при помощи файла .htaccess.
Конфигурирование виртуальных хостов Apache
Мы используем Apache 1.3.26.
конфигурирование mod_jk
-----------------------
# Загружаем Tomcat mod_jk 1.2
LoadModule jk_module libexec/mod_jk.so
JkWorkersFile /usr/local/apache/conf/workers.properties
JkLogFile /usr/local/apache/logs/mod_jk.log
JkLogLevel error
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
Я также использую скрипт, для перемещения mod_jk.log еженедельно.
конфигурирование виртуальных хостов
-----------------------------------
<VirtualHost XXX.XXX.XXX.XXX:80>
ServerAdmin customer@customer.com
DocumentRoot /export/home/www.customer.com/www
ServerName www.customer.com
DirectoryIndex index.html index.htm index.shtml index.shtm index.jsp
# Альяс для административных сообщений в вебпространство
# Файлы размещены вне пространства покупателя, таким образом,
# только файлы, которыми владеет он, находятся в его пространстве.
# Это предотвращает конфликты и проблемы с программами публикаций.
Alias /reports/ /export/home/www.customer.com/reports/
# Поместите виртуальный хост appBase в пространство покупателя.
# Это делает более легким для покупателей управлять смесью из статического и
# динамического содержания, делая пути к директориям относительными к текущей
# директории
# JkAutoAlias позволит apache обслуживать статическое содержание.
# JkAutoAlias также предотвращает обслуживание apache любого файла, находящегося
# в директории веб приложений /WEB-INF/.
JkAutoAlias /export/home/www.customer.com/www
# Предоставляет лог запросов, включая возможные ошибки.
# Это может быть удобно для генерации графических отчетов покупателю, включая время выполнения запросов,
# которые показывают какие результаты по времени получаются при выполнении различных запросов JSP/Сервлетов.
JkRequestLogFormat "%w %v \"%r\" %U %s %T"
# Передаем Tomcat все запросы к файлам *.jsp
JkMount /*.jsp ajp13
# Передаем Tomcat все запросы к /servlet/*
JkMount /servlet/* ajp13
# Передаем Tomcat все /*.do
JkMount /*.do ajp13
# Монтируем управляющее приложение
JkMount /manager/* ajp13
# Помещаем логи apache в директорию логов виртуального хоста
ErrorLog /export/home/www.customer.com/logs/error_log
CustomLog /export/home/www.customer.com/logs/access_log combined
</VirtualHost>
Конфигурация Tomcat 4.1.x
Конфигурирование server.xml
---------------------------
<!--
appBase установлено на корневую директорию apache для вебсайта покупателя
workDir установлено в поддиректорию tomcat/work директории виртуального
хоста покупателя
unpackWARS установлено в true, таким образом покупатели могут изменять отдельные JSP страницы
в нераспакованных веб приложениях без их изменения
liveDeploy установлено в false для того, чтобы уменьшить издержки и усилия покупателей из-за
установки новых приложений. Это необходимо сделать, потому что
корневая директория apache и appBase одинаковы.
Мы не хотим, чтобы tomcat проверял все директории в директории покупателя
каждые несколько минут.
deployXML установлено в false, позволяет приложениям запускаться с правами
catalina, установка данного параметра в true может отразиться на безопасности
вашего сервера.
-->
<Host name="www.customer.com" debug="0"
appBase="/export/home/www.customer.com/www"
workDir="/export/home/www.customer.com/tomcat/work"
unpackWARs="true" autoDeploy="true" liveDeploy="false" deployXML="false">
<!-- Отдельная сфера (realm) необходима каждому покупателю для управления
Мы установили права пользователей к нашей бд MySQL database таким образом, чтобы покупатель
мог администрировать пользователей и роли в своей сфере (realm).
-->
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="0"
driverName="org.gjt.mm.mysql.Driver"
connectionURL="jdbc:mysql://localhost/www_customer_com_realm?autoReconnect=true"
connectionName="customer" connectionPassword="password"
userTable="users" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="user_roles" roleNameCol="role_name" digest="MD5" />
<!-- Помещаем контекстные логи туда, где покупатель их сможет увидеть -->
<Logger className="org.apache.catalina.logger.FileLogger"
directory="/export/home/www.customer.com/tomcat/logs"
prefix="tomcat_log-" suffix=".txt"
timestamp="true"/>
<!-- Некоторые ресурсы JNDI установлены для покупателя, таким образом
их веб-приложения более переносимы между их средой разработки и tomcat.
-->
<DefaultContext debug="0" reloadable="false">
<!-- именованный ресурс JNDI для посылки email -->
<Resource name="mail/send" auth="CONTAINER"
type="javax.mail.internet.MimePartDataSource"/>
<ResourceParams name="mail/send">
<parameter><name>factory</name>
<value>org.apache.naming.factory.SendMailFactory</value>
</parameter>
<parameter><name>mail.smtp.host</name>
<value>localhost</value>
</parameter>
<parameter><name>mail.smtp.user</name>
<value>customer</value>
</parameter>
<parameter><name>mail.from</name>
<value>customer@customer.com</value>
</parameter>
</ResourceParams>
<!-- JNDI ресурс доступа к базе данных JDBC для использования MySQL.
Каждому покупателю предоставляется своя бд для использования
в веб приложениях.
-->
<Resource name="jdbc/data" auth="CONTAINER"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/data">
<parameter>
<name>factory</name>
<value>org.apache.naming.factory.DbcpDataSourceFactory</value>
</parameter>
<parameter><name>user</name><value>customer</value></parameter>
<parameter><name>password</name><value>password</value></parameter>
<parameter>
<name>driverClassName</name>
<value>org.gjt.mm.mysql.Driver</value></parameter>
<parameter>
<name>driverName</name>
<value>jdbc:mysql://localhost/customer_data?autoReconnect=true</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>50</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>200</value>
</parameter>
<!-- maxWait должен быть установлен в достаточно большое значение, достаточное для выживания JVM во время сборки мусора -->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<!-- Отстреливаем соединения с базой данных, критичные для надежности -->
<parameter>
<name>logAbandoned</name>
<value>true</value>
</parameter>
<parameter>
<name>removeAbandoned</name>
<value>true</value>
</parameter>
<parameter>
<name>removeAbandonedTimeout</name>
<value>300</value>
</parameter>
</ResourceParams>
</DefaultContext>
<!-- Настройте менеджер для покупателя - разрешение покупателю размещать файлы context.xml является небезопасным.
-->
<Context path="/manager"
docBase="/usr/local/tomcat/server/webapps/manager"
debug="0" privileged="true">
</Context>
</Host>
Компилятор Jasper
-----------------
Существует несколько проблем при использовании javac из JVM для страниц JSP.
Первая - это изветная утечка памяти. Вторая - javac создает много объектов
во время компиляции. Используя внешний компилятор страниц, такой как jikes
уменьшает память. занимаемую tomcat и не вызывает дополнительные сборщики
мусора для чистки, как javac.
Возьмите исходники jikes, скомпилируйте и установите его.
Отредактируйте $CATALINA_HOME/bin/catalina.sh и добавьте $JAVA_HOME/jre/lib/rt.jar
в CLASSPATH.
CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:$JAVA_HOME/jre/lib/rt.jar
Отредактируйте $CATALINA_HOME/conf/web.xml, чтобы включить использование jikes
как компилятора страниц JSP.
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<!-- Раскоментируйте, чтобы испрользовать jikes для компиляции страниц JSP -->
<init-param>
<param-name>jspCompilerPlugin</param-name>
<param-value>org.apache.jasper.compiler.JikesJavaCompiler</param-value>
</init-param>
<init-param>
<param-name>jspCompilerPath</param-name>
<param-value>/usr/local/bin/jikes</param-value>
</init-param>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>ERROR</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
Добавьте следующую переменную оболочки в стартовый скрипт, который
вы используете для Tomcat, если вы отинсталировали расширения JVM.
$EXTDIRS=$JAVA_HOME/jre/lib/ext
server.xml Установка коннектора
-------------------------------
При помощи mod_jk и Tomcat возможно связывание httpd процесса apache
и AjpConnector в соотношении 1 к 1. Вы должны установить переменную
maxProcessors в значение, большее, чем MaxClients apache.
Установите minProcessors достаточно большим, чтобы уменьшить среднюю
загрузку. Tomcat не принимает запросы, пока они не созданы.
Не увеличивайте acceptCount, если он будет достаточно большим,
JVM будет зависать из-за сборщика мусора, большое acceptCount
может переполнить tomcat запросами. Это может иметь эффект каскада,
который может привести к проблемам.
<Connector className="org.apache.ajp.tomcat4.Ajp13Connector"
port="8009" minProcessors="50" maxProcessors="375"
acceptCount="10" connectionTimeout="0" debug="0"/>
Tomcat JVM и сервер
-------------------
Критично, если память, используемая JVM не записывается на диск.
Если некоторая часть памяти JVM запишется на диск, то время, которое
занимает сборка мусора может быть очень длительным. Я видел, как это
занимало 2-3 минуты. И все это время tomcat не отвечал на запросы. Я
рекомендую устанавливать tomcat на сервер сам по себ, таким образом
вы получите гарантию, что стек JVM не запишется на диск.
Запускайте Tomcat используя JVM 1.3.1 или более высокой версии. Используйте
опцию -server, таким образом профилирование и оптимизация включены.
Знания о том, как конфигурировать использование памяти и сборщик мусора
для JVM очень важны. Ваши установки JVM могут значительно увеличить производительность
Tomcat.
Как минимум, я рекомендую использовать опцию GC -Xincgc и вывод логов
GC -verbose:gc, таким образом вы можете получить данные и сделать выводы о том,
как изменение параметров JVM сказывается на использовании памяти.
Я приведу пример моих опций JVM для tomcat, запущенного на Sun 250 с ОЗУ - 256Мб.
CATALINA_OPTS="-server -verbose:gc -Xms160m -Xmx160m -Xss128k -Xincgc
-XX:+UseLWPSynchronization"
В идеале, не нужно использовать сборщик мусора, который занимает время
более 10 секунд.
Мой хостинг базируется на том, что все клиенты пользуются одним экземпляром
сервером Tomcat, но у меня очень мало клиентов сейчас. Базируясь
на опыте вам может показаться полезным использовать множество экземпляров Tomcat.
Или, даже по одному для каждого покупателя, если вы можете предоставить
столько ресурсов.
Версия Tomcat
=============
Я рекомендую использовать последние Tomcat 4.1.X, они имеют несколько
возможностей, которые я использовал, чтобы сделать виртуальный хостинг
более легким способом, чем в Tomcat 4.0.X.
Безопасность Tomcat
Если у вас есть неблагонадежные пользователи, помещающие свои веб-приложения
или изменяющие JSP-страницы, вы должны запустить Tomcat с SecurityManager.
Ваша конфигурация файла catalina.policy для пользовательских веб-приложений
должна быть достаточно строгой, чтобы защитить безопасность сервера и защитить
одного покупателя от другого. Так как по умолчанию установлено достаточно разрешений,
вы можете не изменять файл catalina.policy.
Сейчас вы еще не можете делегировать покупателям установки для безопасности.
Но, когда веб приложение стартовало, catalina.policy перегружается. Таким образом, если
вы хотите распространить разрешения только на определенное приложение покупателя, вы
можете изменить catalina.policy, и затем перегрузить веб-приложение.
Я работаю над изменениями в представлении SecurityManager в Tomcat,
который позволяет безопасно делегировать покупателям администрировать
свою собственную политику безопасности, без ущерба для сервера.
Недостатки
==========
Есть несколько недостатков, которые необходимо исправить разработчикам Tomcat:
1. Автоматически остановить длительный запрос, потому что плохо написанное
покупателем приложение может повесить tomcat;
2. В соответствии сокетов mod_jk <-> AjpConnector удалить связь 1 к 1.
3. Проблемы со остановкой/запуском в менеджере. Я знаю несколько случаев, когда
покупатель останавливал/запускал сервер, или перезагружал приложение, и это вызывало
проблемы.
Выводы
======
Я думаю это все рекомендации, которые я использовал, когда устанавливал
apache и tomcat для виртуального хостинга покупателей веб хостинга. Я мог
пропустить некоторые вещи.