跳轉到內容

OpenClinica 使用者手冊/使用反向代理

來自華夏公益教科書

使用安全的反向代理來訪問 OpenClinica

[編輯 | 編輯原始碼]

開箱即用的 OpenClinica 由 Apache Tomcat 提供服務,雖然這工作得很好,但如果我們在等式中新增一個"反向代理",我們可以獲得性能提升。反向代理伺服器將減輕 Tomcat 伺服器的負擔。它可以傳送靜態檔案(如 CSS、javascript 和影像),而不必麻煩 Tomcat。Tomcat 只需要提供動態的研究內容,即使用我們的研究資料生成的頁面。此外,反向代理允許我們傳送壓縮的響應,或者告訴客戶端檔案在很長一段時間內不會改變,因此可以使用已經下載的檔案,而不是再次從伺服器下載。這些修改減少了頻寬使用量。反向代理也可以用於 SSL 加密,再次減輕 Tomcat 的工作量。

本頁面的主體是一個使用 Nginx(發音:Engine X)的教程。Nginx 不僅速度很快,更重要的是它非常容易安裝和配置。Nginx 是在 "2-條款 BSD 許可證" 下開源的。

Nginx 在 Windows 上只處於 Beta 版本

[編輯 | 編輯原始碼]

雖然 Nginx 針對 Linux/BSD 釋出了版本,但它在 Windows 作業系統上只處於 Beta 版本(參見 適用於 Windows 的 nginx 頁面)。其他的 Windows 代理軟體包括 Apache HTTP Server(在下面詳細介紹)和 SQUID。

另一種選擇 - 不使用代理,而是設定 Tomcat 來進行壓縮和 SSL 加密

[編輯 | 編輯原始碼]

如果你只是想讓你的頁面被加密和壓縮,但不需要像 Nginx 這樣的反向代理的快取效果,Tomcat 可以透過遵循 SSL 配置 HOW-TO 來設定 SSL 加密,並且 壓縮 也可以在 Tomcat 中設定。 這個執行緒 建議設定 Tomcat 來進行 SSL 加密和壓縮,而不是使用代理,因為當配置最佳時,OpenClinica 主要受 Postgres 快取效能的限制(參見有關 效能 的頁面)。

安裝 Nginx

[編輯 | 編輯原始碼]

先決條件

[編輯 | 編輯原始碼]

首先使用你的包管理器 (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

下載和安裝 Nginx

[編輯 | 編輯原始碼]

http://wiki.nginx.org/Install#Source_Releases 下載穩定版原始碼。
在撰寫本文時,版本為:1.0.5。
下載完成後,解壓縮 Nginx。使用 ssl 支援和 gzip 壓縮配置 Nginx。構建它。
以下是步驟

  $ wget http://nginx.org/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/ 中。

安裝 init 指令碼

[編輯 | 編輯原始碼]

RedHat/CentOS

[編輯 | 編輯原始碼]

從這裡獲取 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"

Debian/Ubuntu

[編輯 | 編輯原始碼]

從這裡獲取 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:// 時,你應該會看到訊息 `歡迎使用 Nginx`。

安全連線

[編輯 | 編輯原始碼]

我們希望建立到我們研究系統的安全連線。如果你還沒有安全證書,請使用這個關於建立自簽名證書的優秀指南:http://www.akadia.com/services/ssh_test_certificate.html。按照這個指南進行操作,直到第 4 步。假設你的安全檔名為 `my-server.crt` 和 `my-server.key`。建立一個名為 ssl 的目錄,位於 /usr/local/ 中。將這兩個檔案複製到 /usr/local/ssl/ 資料夾中。你將在配置檔案中再次看到這些檔名。
現在我們可以配置 Nginx 了。

配置 Nginx

[編輯 | 編輯原始碼]

主配置檔案位於 /usr/local/nginx/conf/nginx.conf。

這是一個示例配置檔案,它提供了壓縮、加密、過期標頭以及到 OpenClinica 安裝的代理。請閱讀檔案中的註釋以瞭解說明。將此複製到您的 nginx.conf 檔案中。
請注意,OpenClinica 是作為名為“studies”的 Web 應用程式安裝的。這就是您在配置檔案中會看到諸如 https://:8080/studies 之類的 URL 的原因。此配置還將“includes”和“images”目錄的位置硬編碼為本地目錄。

Nginx 配置檔案

[編輯 | 編輯原始碼]
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:///studies/ 來嘗試新的配置。

多個 OpenClinica 安裝的代理

[編輯 | 編輯原始碼]

負責將請求傳遞到 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

[編輯 | 編輯原始碼]

確保 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”頁面的示例


最佳化前: YSlow 統計資訊(之前)


最佳化後: YSlow 統計資訊(之後)



說明:在左側,我們看到了頁面的結構。要載入此頁面,瀏覽器會向伺服器傳送不少於 76 個請求。這些請求導致總下載量為 462.7k。如果我們新增 gzip 壓縮,大小將縮減為 162.6K。第一次與 OpenClinica 伺服器聯絡時,所有靜態內容(如影像、JavaScript 和 CSS 檔案)都將快取在客戶端計算機上。在右側,我們看到了快取的效果:從伺服器下載的資料量大大減少。“expires max”告訴瀏覽器很長時間內不應檢查伺服器是否有檔案的更新版本。這就是我們在最佳化後的情況下只訪問伺服器兩次的原因。這是一個重大改進,尤其是在頻寬有限且延遲較高的環境中。在這種情況下,請求數量甚至可以減少到一次,因為我們沒有為 favicon 檔案設定“expires max”。

將 Apache HTTP 伺服器設定為反向代理

[編輯 | 編輯原始碼]

透過將 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://:8080/ timeout=1800
ProxyPassReverse / https://: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、內容壓縮和客戶端上的快取。我們已經看到,最佳化可以減少頻寬使用量,並減少傳送到伺服器的請求數量。這提高了應用程式的響應能力,尤其是在延遲較高且頻寬較低的網路中。

華夏公益教科書