OpenClinica 用户手册/使用反向代理
开箱即用的 OpenClinica 由 Apache Tomcat 提供服务,虽然这工作得很好,但如果我们在等式中添加一个"反向代理",我们可以获得性能提升。反向代理服务器将减轻 Tomcat 服务器的负担。它可以发送静态文件(如 CSS、javascript 和图像),而不必麻烦 Tomcat。Tomcat 只需要提供动态的研究内容,即使用我们的研究数据生成的页面。此外,反向代理允许我们发送压缩的响应,或者告诉客户端文件在很长一段时间内不会改变,因此可以使用已经下载的文件,而不是再次从服务器下载。这些修改减少了带宽使用量。反向代理也可以用于 SSL 加密,再次减轻 Tomcat 的工作量。
本页面的主体是一个使用 Nginx(发音:Engine X)的教程。Nginx 不仅速度很快,更重要的是它非常容易安装和配置。Nginx 是在 "2-条款 BSD 许可证" 下开源的。
虽然 Nginx 针对 Linux/BSD 发布了版本,但它在 Windows 操作系统上只处于 Beta 版本(参见 适用于 Windows 的 nginx 页面)。其他的 Windows 代理软件包括 Apache HTTP Server(在下面详细介绍)和 SQUID。
如果你只是想让你的页面被加密和压缩,但不需要像 Nginx 这样的反向代理的缓存效果,Tomcat 可以通过遵循 SSL 配置 HOW-TO 来设置 SSL 加密,并且 压缩 也可以在 Tomcat 中设置。 这个线程 建议设置 Tomcat 来进行 SSL 加密和压缩,而不是使用代理,因为当配置最佳时,OpenClinica 主要受 Postgres 缓存性能的限制(参见有关 性能 的页面)。
首先使用你的包管理器 (apt-get、yum) 检查你的系统上是否安装了以下库。还要确保这些库的开发文件可用,这些文件的后缀为 '-dev' 或 '-devel',具体取决于你的系统。
- zlib 库(用于 gzip 模块)
- pcre 库(用于重写模块)
- openssl 库(用于 ssl 支持)
RedHat/CentOS 示例
$ sudo yum install zlib zlib-devel pcre pcre-devel openssl openssl-devel
Debian/Ubuntu 示例
$ sudo apt-get install zlib zlib-dev pcre pcre-dev openssl openssl-dev
因为我们要编译源代码,所以需要安装你系统的开发工具和开发库。
RedHat/CentOS 示例
$ sudo yum groupinstall "Development Tools"
$ sudo yum groupinstall "Development Libraries"
Debian/Ubuntu 示例
$ sudo apt-get install build-essential
从 http://wiki.nginx.org/Install#Source_Releases 下载稳定版源代码。
在撰写本文时,版本为:1.0.5。
下载完成后,解压缩 Nginx。使用 ssl 支持和 gzip 压缩配置 Nginx。构建它。
以下是步骤
$ wget https://nginxserver.cn/download/nginx-1.0.5.tar.gz
$ tar xvfz nginx-1.0.5.tar.gz
$ cd nginx-1.0.5
$ ./configure --with-http_ssl_module --with-http_gzip_static_module
$ make
$ sudo make install
如果一切顺利,Nginx 现在安装在 /usr/local/nginx/ 中。
从这里获取 RedHat/CentOS 的 init 脚本:http://wiki.nginx.org/RedHatNginxInitScript
我们需要稍微修改一下这个文件,才能让它与我们的安装一起使用。
将:nginx="/usr/sbin/nginx" 更改为:nginx="/usr/local/nginx/sbin/nginx"
将:NGINX_CONF_FILE="/etc/nginx/nginx.conf" 更改为:NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
从这里获取 init 脚本:http://wiki.nginx.org/Nginx-init-ubuntu
将:DAEMON=/usr/local/sbin/nginx 更改为 DAEMON=/usr/local/nginx/sbin/nginx
当你修改完文件以满足你的需求后,将 init 脚本 `nginx` 复制到 /etc/init.d/。通过运行以下命令确保它自动启动
$ sudo chkconfig --del nginx
$ sudo chkconfig --level 2345 nginx on
在启动服务器之前,请确保没有其他 Web 服务器在使用端口 80。检查是否一切正常,方法是启动服务器。
$ sudo /etc/init.d/nginx start
当你浏览到 https://127.0.0.1 时,你应该会看到消息 `欢迎使用 Nginx`。
我们希望创建到我们研究系统的安全连接。如果你还没有安全证书,请使用这个关于创建自签名证书的优秀指南:http://www.akadia.com/services/ssh_test_certificate.html。按照这个指南进行操作,直到第 4 步。假设你的安全文件名为 `my-server.crt` 和 `my-server.key`。创建一个名为 ssl 的目录,位于 /usr/local/ 中。将这两个文件复制到 /usr/local/ssl/ 文件夹中。你将在配置文件中再次看到这些文件名。
现在我们可以配置 Nginx 了。
主配置文件位于 /usr/local/nginx/conf/nginx.conf。
这是一个示例配置文件,它提供了压缩、加密、过期标头以及到 OpenClinica 安装的代理。请阅读文件中的注释以了解说明。将此复制到您的 nginx.conf 文件中。
请注意,OpenClinica 是作为名为“studies”的 Web 应用程序安装的。这就是您在配置文件中会看到诸如 https://127.0.0.1:8080/studies 之类的 URL 的原因。此配置还将“includes”和“images”目录的位置硬编码为本地目录。
user nobody;
# the number of worker_processes should at least be equal to the number of CPU cores of the server
worker_processes 2;
error_log logs/error.log;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
# set max upload size
client_max_body_size 3M;
include mime.types;
default_type application/octet-stream;
# set log file format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
# enable compression
gzip on;
gzip_static on;
gzip_http_version 1.1;
gzip_disable "MSIE [1-6]\.";
# specify what data will be compressed
gzip_types text/plain text/html text/css text/javascript image/png image/x-icon application/x-javascript application/xml;
# optimization for ssl sessions:
# the ssl_session_cache reuses connections per client therefore minimizing the burden of the computationally expensive SSL handshakes
# one megabyte of the cache (shared:SSL:1m;) contains about 4000 sessions. 100k about 400
ssl_session_cache shared:SSL:100k;
# reuse SSL session parameters to avoid SSL handshakes, time in minutes
ssl_session_timeout 10m;
# set keepalive connections to send several requests via one connection, time in seconds
keepalive_timeout 120;
# set the time that nginx will wait for the proxy connection
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
# HTTP server
# define server on port 80 (http)
server {
listen 80;
server_name my-server.org;
access_log logs/host.access.log main;
# force the client to use a secure connection
location /studies {
rewrite ^/(.*)$ https://my-server.org/$1 redirect;
}
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
# HTTPS server
# define server on port 443 (https)
server {
listen 443;
server_name my-server.org;
# turn on data encryption for secure connections
ssl on;
ssl_certificate /usr/local/ssl/my-server.crt;
ssl_certificate_key /usr/local/ssl/my-server.key;
# directly serve the static files in the `includes` directory
location ~ ^/studies/includes/(.*)$ {
# add future expiry date to force caching of the file on the client
expires max;
add_header Cache-Control "public";
alias /usr/local/tomcat/webapps/studies/includes/$1;
}
# directly serve the static files in the `images` directory
location ~ ^/studies/images/(.*)$ {
# add future expiry date to force caching of the file on the client
expires max;
add_header Cache-Control "public";
alias /usr/local/tomcat/webapps/studies/images/$1;
}
# pass all other requests to Tomcat
location /studies {
proxy_pass http://127.0.0.1:8080/studies;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
对配置文件进行更改后,我们必须像这样重新启动 nginx。
$ sudo /etc/init.d/nginx restart
通过访问 https://127.0.0.1/studies/ 来尝试新的配置。
负责将请求传递到 OpenClinica 的部分是
location /studies { proxy_pass http://127.0.0.1:8080/studies; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
如果您安装了多个 OpenClinica,您仍然可以拥有一个访问点,但可以拥有任意多个后端。
例如,请考虑以下配置
location /study_1 { proxy_pass http://127.0.0.1:8080/OpenClinica_1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /study_2 { proxy_pass http://192.168.1.100:8080/OpenClinica_2; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /study_3 { proxy_pass http://192.168.1.101:8080/OpenClinica_3; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
在此配置中,一个 Nginx 服务器是三个 OpenClinica 服务器的代理,这些服务器可以是真实服务器或虚拟服务器。如您所见,第一个服务器与 Nginx 服务器运行在同一台机器上。另外两个服务器是本地域中的服务器。
大多数情况下,数据只会在有限的已知位置输入。我们可以指示 Nginx 仅允许从这些位置(根据其公共 IP 地址)访问我们的服务器。所有其他 IP 地址将被阻止。请查看此代码片段
location /studies {
# grant access to the following ip addresses
allow 80.78.17.10; #gabon satellite
allow 41.211.145.61; #gabon adsl
allow 41.220.12.34; #uganda office
# disallow all other ip addresses
deny all;
proxy_pass http://127.0.0.1:8080/studies;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
来自未经授权的 IP 地址的连接将收到 403 错误。我们可以捕获此错误并将更有意义的消息发送到客户端。为此,请在 /usr/local/nginx/html/ 文件夹中创建一个名为 403.html 的文件。将类似于以下内容添加到该文件
<html>
<head>
<title>Error 403 - IP Address Blocked</title>
</head>
<body>
<h2>Your IP Address is not registered, therefore you do not have access to this site.</h2>
</body>
</html>
将下一行添加到 Nginx 配置文件的 http 部分。
error_page 403 http://my-server.org/403.html;
现在,未经授权的客户端在尝试访问我们的研究系统时将收到一条信息量很大的消息。
确保 OpenClinica 的 sysURL 设置(在 OpenClinica/WEB-INF/classes/datainfo.properties 文件中)设置为系统的公共 URL,例如
sysURL=https://my-server.org/${WEBAPP}/MainMenu
这确保了系统电子邮件和某些内部消息中的 URL 正确地指向代理,而不是指向其他任何地方。
当您安装并运行 Firefox 扩展 YSlow 时,您可以看到反向代理相对于标准 OpenClinica 安装的改进。使用端口 8080 跳过代理。以下是从 OC 3.0.4.1 的“Notes & Discrepancies”页面的示例
说明:在左侧,我们看到了页面的结构。要加载此页面,浏览器会向服务器发送不少于 76 个请求。这些请求导致总下载量为 462.7k。如果我们添加 gzip 压缩,大小将缩减为 162.6K。第一次与 OpenClinica 服务器联系时,所有静态内容(如图像、JavaScript 和 CSS 文件)都将缓存在客户端计算机上。在右侧,我们看到了缓存的效果:从服务器下载的数据量大大减少。“expires max”告诉浏览器很长时间内不应检查服务器是否有文件的更新版本。这就是我们在优化后的情况下只访问服务器两次的原因。这是一个重大改进,尤其是在带宽有限且延迟较高的环境中。在这种情况下,请求数量甚至可以减少到一次,因为我们没有为 favicon 文件设置“expires max”。
通过将 Apache HTTP 服务器 用作反向代理,可以实现类似的结果。请注意,下面的配置尚未包含 SSL
#Ensure correct modules are uncommented
LoadModule deflate_module modules/mod_deflate.so
LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<IfModule proxy_module>
# Disable forward proxy requests
ProxyRequests Off
# Allow requests from selected hosts or domains
<Proxy *>
Order Allow,Deny
Allow from all
</Proxy>
# Configure reverse proxy requests for OpenClinica with a long timeout for lots of data
ProxyPass / https://127.0.0.1:8080/ timeout=1800
ProxyPassReverse / https://127.0.0.1:8080/
</IfModule>
<IfModule expires_module>
<IfModule headers_module>
# Add long expires headers and caching for images and includes (javascript) directories
# based on http://cjohansen.no/en/apache/using_a_far_future_expires_header
<LocationMatch "/.*/images/.*$">
ExpiresActive On
ExpiresDefault "access plus 1 year"
Header set Cache-Control "public"
</LocationMatch>
<LocationMatch "/.*/includes/.*$">
ExpiresActive On
ExpiresDefault "access plus 1 year"
Header set Cache-Control "public"
</LocationMatch>
</IfModule>
</IfModule>
#compress output to relevant browsers
<IfModule deflate_module>
<Location />
# Insert filter
SetOutputFilter DEFLATE
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Don't compress images
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
#SetEnvIfNoCase Request_URI \
#"/.*/CreateCRFVersion.*$" no-gzip dont-vary
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</Location>
</IfModule>
<IfModule headers_module>
#Optional section to avoid issues with OpenClinica 3.1.2 (and possibly later) and Microsoft's TMG
#Delete this whole section if you aren't using TMG:
<LocationMatch "/.*/AdministrativeEditing.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/CreateCRFVersion.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/DataEntry.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/DoubleDataEntry.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/InitialDataEntry.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/PrintCRF.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/PrintDataEntry.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/PrintEventCRF.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/PrintAllEventCRF.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/PrintAllSiteEventCRF.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/SectionPreview.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
<LocationMatch "/.*/ViewSectionDataEntry.*$" >
RequestHeader unset Accept-Encoding
Header unset Content-Encoding
</LocationMatch>
</IfModule>
安装和配置反向代理并不困难。使用反向代理,我们可以让 Tomcat 做它最擅长的:提供动态内容。反向代理处理所有其他请求,包括 SSL、内容压缩和客户端上的缓存。我们已经看到,优化可以减少带宽使用量,并减少发送到服务器的请求数量。这提高了应用程序的响应能力,尤其是在延迟较高且带宽较低的网络中。