Skip to content. | Skip to navigation

Personal tools

Navigation

You are here: Home / Tips / Deployment

Deployment

系統自動啟動與佈署設定,包括網站伺服器管理、快取伺服器管理、WSGI、ZEO、SSL 等設定。

上路之前,值得先閱讀 Web Architecture Developer Manual預備知識,再依照實際部屬的工具,動手進行設定。

每個 Framework 都自帶 Web Server 了,在 Reverse Proxy 或 Load Balance 場合,再把 Nginx 放在前面。

Solid Python Deployments for Everybody DevOps vs SRE

新增 @@okay View

比較: Apache vs Cherokee vs Nginx Different Flavors of Nginx for Debian / Ubuntu Severless Monitoring An Introduction to NGINX for Developers

zps

$ sudo apt-get install python-psutil
$ sudo easy_install rt.zps

顯示 Zope 同時執行數個 Plone Instance 列表

haufe.requestmonitoring for checking connection time out

psutil 可以能只支援 Python2

SSL Support

Hynek: The Sorry State of SSL kenduest: ssllabs 網站可以檢測 SSL 設定是否有足夠的安全性,一般設定大多只要到 A 等級就夠,若要提升到 A+ 則是取捨考量,因為可能會被客戶投訴網站連不上,尤其使用比較舊的作業系統與瀏覽器情況。另外 DNS RR 記錄內也有提供 CAA 可以設定 SSL 簽署單位,若瀏覽器支援檢查的話也可以減少被一些詐騙釣魚的情況。根據測試結果 HSTS 一定要開且 mag age 要超過半年,否則四個大項目都拿滿分也是只有 A。要用 openssl 手動產生一份長度至少 2048 bit 的 Diffie-Hellman 憑證,一般 Linux 預設產生的只有 1024 bit,會有 Logjam Attack 弱點。四個項目都拿到滿分 A+ 沒有實用意義,應追求以最低分最大 client 相容性得到 A+。

步驟概要: 最後再把 HTTP (port 80) 封包轉到 HTTPS (port 443)

  • install system packages for SSL (often this is the package called openssl)
  • ensure Nginx includes SSL support
  • purchase or create SSL certificates and put them somewhere on your server
  • configure Nginx to use those SSL certificates

Apache SSL ProxyPass Gives Unsecured Content for Zope

Apache XAMPP example

SSL Nginx

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /your_cert_path/yourcertname+5.pem;
    ssl_certificate_key /your_cert_path/yourcertname+5-key.pem;
    server_name YOUR_SERVER_NAME;
}

Apache

Rewrite 入門說明

搭配 Apache 的 Proxy Configuration 來佈署 Plone 是常見的方式。首先要把 proxy_http、rewrite 等模組啟用:

$ sudo a2enmod proxy_http rewrite
Considering dependency proxy for proxy_http:
Enabling module proxy.
Enabling module proxy_http.
Enabling module rewrite.
To activate the new configuration, you need to run:
  service apache2 restart

$ ls /etc/apache2/mods-enabled
... rewrite.load  proxy.conf  proxy.load  proxy_http.load

編輯設定檔:

$ vim /etc/apache2/sites-available/mysite.mydomain.com
<VirtualHost *:80>
  ServerName mysite.mydomain.com

  ErrorLog /var/log/apache2/mysite_error.log
  CustomLog /var/log/apache2/mysite_access.log combined
  LogLevel warn

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteLog /var/log/apache2/mysite_rewrite.log
  RewriteLogLevel 5
  RewriteRule ^($|/.*) http://localhost:8080/VirtualHostBase/http/mysite.mydomain.com:80/Plone/VirtualHostRoot$1 [L,P]
</IfModule>

   ProxyPass / http://localhost:8080/VirtualHostBase/http/mysite.mydomain.com:80/Plone/VirtualHostRoot/
   ProxyPassReverse / http://localhost:8080/VirtualHostBase/http/mysite.mydomain.com:80/Plone/VirtualHostRoot/

</VirtualHost>

讓設定檔生效:

$ sudo a2ensite mysite.mydomain.com
Enabling site mysite.mydomain.com.
To activate the new configuration, you need to run:
  service apache2 reload

Apache 2.2 版本之後,安全設定有所調整

[error] (13)Permission denied: proxy: HTTP: attempt to connect to 127.0.0.1:8080 (*) failed

要在設定檔後面增加下列內容:

<IfModule mod_proxy.c>
  <Proxy proxy:http://127.0.0.1:8080/>
    Order deny,allow
    Allow from localhost
  </Proxy>
</IfModule>

ProxyPass 的 Keepalive 設定

proxy: Error reading from remote server returned by ...
ProxyPass / http://www.mysite.com:8080/ retry=1 acquire=3000 timeout=600 Keepalive=On

virtual hosting vs plone.app.content/folder_contents get_top_site_from_url

RewriteRule ^/mysite(.*)  http://127.0.0.1:7070/VirtualHostBase/http/www.my-domain.de:80/Plone/VirtualHostRoot/_vh_mysite$1

Not Sure? ProxyPassReverse is unnecessary as Plone already takes care of fixing up any self-referential urls?

ProxyPass /static !
ProxyPass / http://localhost:8080/VirtualHostBase/http/server:80/Plone/VirtualHostRoot/
ProxyPassReverse / http://localhost:8080/VirtualHostBase/http/server:80/Plone/VirtualHostRoot/

.htaccess example

htaccess Redirect

non-www

Forcing SSL Across Apache Proxy

和 PHP 共存的範例:

<VirtualHost *:80>
    ServerName www.mysite.org
    ServerAdmin webmaster@gmail.com

    ErrorLog /var/log/apache2/mysite_error.log
    CustomLog /var/log/apache2/mysite_access.log combined
    LogLevel warn

    Alias /phpfolder/ "/var/www/phpfolder/"
    <Directory "/var/www/phpfolder/">
          Options Indexes MultiViews FollowSymLinks
          AllowOverride All
          Order allow,deny
          Allow from all
    </Directory>

     ProxyPass /phpfolder !
     ProxyPass /imgfolder !

     ProxyPass / http://localhost:9999/mysite
     ProxyPassReverse / http://localhost:9999/mysite

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteLog /var/log/apache2/mysite_rewrite.log
    RewriteLogLevel 5

    RewriteCond %{REQUEST_URI} !^/(phpfolder|imgfolder)/(.*)

    RewriteRule ^(.*) http://127.0.0.1:9999/VirtualHostBase/http/www.mysite.org:80/mysite/VirtualHostRoot$1 [L,P]
  </IfModule>

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

</VirtualHost>

moved folders Need No DocumentRoot

SSL secure login

RewriteRule vs ProxyPassReverse ProxyPass Keepalive: proxy: Error reading from remote server returned by

Custom 404 Error Page

Nginx

web guide Load Balance regis_huang 有 PHP 參數調整經驗

video plone-org-nginx

Rewrite Example:

rewrite ^/(.*)$ /VirtualHostBase/http/example.org:80/Plone/VirtualHostRoot/$1 break;

^/(.*)$ 代表所有的 inbound path 都會被儲存在 $1 變數,接著會被加在網址最後方。 The path is then changed to contain the token VirtualHostBase, followed by the protocol, the public-facing host name and port, the Plone site ID, and the end token VirtualHostRoot, before the original path segment. Hence, if a request is received for http://example.org/front-page and is to be proxied to Zope on localhost:8080, it will be translated to http:// localhost:8080/VirtualHostBase/http/example.org:80/Plone/ VirtualHostRoot/front-page by the rewrite rule. Zope will then traverse to Plone/front-page as if we had accessed http://localhost:8080/Plone/frontpage, but when rendering external links (for example, in Plone's navigation tabs), it will use the public hostname (http://example.org/) and skip the Plone/ prefix.

Minimal Configurarion

# This specifies which IP and port Plone is running on.
# The default is 127.0.0.1:8080
#upstream plone {
#    server 127.0.0.1:6544;
#}

# Redirect all www-less traffic to the www.site.com domain
# (you could also do the opposite www -> non-www domain)
server {
    listen 80;
    server_name carer.org.tw;
    rewrite ^/(.*) http://www.carer.org.tw/$1 permanent;
}

server {

    listen 80;
    server_name www.carer.org.tw;
    access_log /var/log/nginx/www-carer-org-tw.access.log;
    error_log /var/log/nginx/www-carer-org-tw.error.log;

    # Note that domain name spelling in VirtualHostBase URL matters
    # -> this is what Plone sees as the "real" HTTP request URL.
    # "Plone" in the URL is your site id (case sensitive)
    location / {
          proxy_pass http://localhost:8092/VirtualHostBase/http/www.carer.org.tw:80/carer/VirtualHostRoot/;
          include    /etc/nginx/proxy.conf;
    }
}
# proxy.conf

proxy_redirect          off;
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   60;
proxy_send_timeout      60;
proxy_read_timeout      60;
proxy_buffers           32 4k;

Temporary or Permanet 實例 diazo.mydoctor.tw 換成 cgis.rchss.sinica.edu.tw 在 server_name 底下使用 rewrite ^/(.*) http://cgis.rchss.sinica.edu.tw/$1 permanent; 語法

Redirect Single URL:

location /old-link.html {
    rewrite ^/.* http://www.google.com/ permanent;
}
location ~ ^/crgis_tw/(.*) {
    root /var/www/html;
}

Debian Wheezy Example:

server {
  server_name your-domain.com;
  listen 80;

  location / {
    rewrite ^/(.*)$ /VirtualHostBase/http/your-domain.com:80/Plone/VirtualHostRoot/$1 break;
    proxy_pass http://127.0.0.1:8080;
  }
  location ~* manage_ {
    deny all;
  }
}

server {
  server_name your-domain.com;
  listen 80;
  access_log off;
  rewrite ^(/.*)$  http://your-domain.com$1 permanent;
}

Static Resource (Image, PDF ...) 在 /var/www/html 建立 static 目錄後,就可以在 static 目錄裡放置資源檔案,透過 http://site.com/static/myfile.jpg 存取。

    location /static/ {
          root /var/www/html;
    }

Philip Bauer: The cookie-regex explained (thanks to Hanno Schulz and Vlad Vorobiev for their wisdom): $http_cookie (which is a string) is searched for anything containing '__ac=' followed by 1 or more characters which is not ';' (which would mean the cookie has no value), followed by either an ';' (signaling the beginning of another cookie) or the end of the line. If you are as ignorant of regex as me you might consider keeping this regex-cheatsheet close.

upstream myzope {
 server localhost:8080;
}

ssl_certificate      /home/starzel/nginx/starzel.crt;
ssl_certificate_key  /home/starzel/nginx/starzel.key;

# http
server {
 listen myserver.com:80;
 server_name www.mysite.com;
 access_log /var/log/nginx/mysite.com_access.log;
 rewrite ^(.*)(/login_|/require_login|/failsafe_login_form)(.*) https://$server_name$1$2$3 redirect;
 if ($http_cookie ~* "__ac=([^;]+)(?:;|$)" ) {
     rewrite ^(.*) https://$host/$1 redirect;
 }

 location / {
     proxy_pass http://myzope/VirtualHostBase/http/www.mysite.com:80/Plone/VirtualHostRoot/;
 }
}

# https
server {
 listen myserver.com:443 default ssl;
 server_name www.mysite.com;
 access_log /var/log/nginx/mysite.com_access.log;
 if ($http_cookie ~* "__ac=([^;]+)(?:;|$)" ) {
     # prevent infinite recursions between http and https
     break; 
 }
 rewrite ^(.*)(/logged_out)(.*) http://$server_name$1$2$3 redirect;
 location / {
     proxy_pass http://myzope/VirtualHostBase/https/www.mysite.com:443/Plone/VirtualHostRoot/;
 }
}

# zmi 
server {
 listen myserver:443 ssl;
 server_name manage.mysite.com;
 access_log /var/log/nginx/heeschmusik_zmi.de_access.log;
 location / {
     proxy_pass http://myzope/VirtualHostBase/https/manage.myserver.com:443/VirtualHostRoot/;
 }
}

另一個範例: 要使用兩個 server 區段,第一個聽取 HTTP 封包並轉給第二個來處理 HTTPS 封包。

# This adds security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
#add_header Content-Security-Policy "default-src 'self'; img-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'";
add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'";

# This specifies which IP and port Plone is running on.
# The default is 127.0.0.1:8080
upstream plone {
 server 127.0.0.1:8080;
}

# this forces all unencrypted HTTP traffic on port 80 to be redirected to encrypted HTTPS
server {
 listen 80;
 server_name yoursite.com;
 location / {
 rewrite ^ https://$server_name$request_uri permanent;
 }
}

server {
 listen 443 default ssl;
 ssl_certificate /etc/ssl/localcerts/yoursite.com.crt;
 ssl_certificate_key /etc/ssl/localcerts/yoursite.com.key;
 server_name yoursite.com;
 access_log /var/log/nginx/yoursite.com.access.log;
 error_log /var/log/nginx/yoursite.com.error.log;

    # Note that domain name spelling in VirtualHostBase URL matters
    # -> this is what Plone sees as the "real" HTTP request URL.
    # "Plone" in the URL is your site ID (case sensitive)
 location / {
 rewrite ^/(.*)$ /VirtualHostBase/$scheme/yoursite.com:443/Plone/VirtualHostRoot/$1 break;

        # this puts the originating request IP address in the logs
 proxy_pass http://127.0.0.1:8080/;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

 }

Developer Manual Rule Convertor

ProxyPreserveHost X-Forwarded-Proto + VHM

example: plone-org

Internal URL vs external URL: collective.z3cform.wizard

For multi-nic (physical or virtual), to host multiple instances on same port, use format <nic-ip>:<port-address> in etc/zope.cfg

nginx buildout.cfg

Redirect: 301 location example

location =  /abc/mm {
    return 301 /cde/;
}
location =  /abc/mm/  {
    return 301 /cde/;
}
server {
  server_name website.com;
  root /var/www/vhosts/website.com/httpdocs/;
  location /storage/ {
    internal;
    alias /var/www/storage/;
  }
  location /documents/ {
    rewrite ^/documents/(.*)$ /storage/$1;
  }
}

Basic Proxy Setting Nginx 的 proxy_pass 中如果沒有給 path,request 會直接往 upstream 送,有 path 的話會自動從 location 的位置截斷,接上 proxy_pass 的 path 才往 upstream 送。

location /abc {
   proxy_pass http://localhost:5984/;
}

Permanent (301) Redirect to External URL

server {
    listen   80;
    server_name pkarl.com;

    location /blog/rss {
      rewrite ^ http://feeds2.feedburner.com/petekarl permanent;
    }
...
}

同時執行數個 Plone Instance 的 Acquisition 問題,可考慮使用 collective.siteisolationAccessRule 來處理。

# http://www.example1.com/example2
# http://www.example2.com/example1
# $Id: 00_default_vhosts.conf 250119 2008-07-26 14:51:31Z oden $
# $HeadURL: svn+ssh://svn.mandriva.com/svn/packages/cooker/apache-conf/current/SOURCES/00_default_vhosts.conf $
# This is an example VirtualHosts configuration.
#
# Since Apache 1.3.19, we modified the setup to include some nice tricks:
#
# - We added the User and Group directives so VirtualHosts now work with
#   suexec directive. If set, Apache will run all cgi scripts under that
#   user and group (provided the uid and gid are > 100 for security). The
#   directories and cgi files *must* belong to that user/group for the
#   feature to work
#
# - We added the Setenv VLOG directive. This works in conjunction with
#   the CustomLog in common.conf. When Setenv VLOG is set, apache will
#   create a /var/log/httpd/VLOG-YYYY-MM-<ServerName>.log instead of logging
#   to access_log. Use this instead of defining a special logfile for
#   each vhost, otherwise you eat up file descriptors.
#
# - You can also specify a path for the VLOG for each Vhost, for example,
#   to place the logs in each user's directory. However, if you want to
#   use the file for accounting, place it in a directory owned by root,

#   otherwise the user will be able to erase it.
#
# - I suggest only including the ErrorLog *only* if the vhost will use
#   cgi scripts. Again, it saves file descriptors!


################# IP-based Virtual Hosts
# <VirtualHost 192.168.2.100>
# User jmdault
# Group jmdault
# DocumentRoot /home/jmdault/public_html
# ServerName test2.com
# Setenv VLOG /home/jmdault/logs
# ErrorLogs /home/jmdault/test2-error_log
# </VirtualHost>

################# Named VirtualHosts
# NameVirtualHost 111.222.33.44
# <VirtualHost 111.222.33.44>
# ServerName www.domain.tld
# ServerPath /domain

# DocumentRoot /web/domain
# </VirtualHost>

#<VirtualHost alice.com>
#    ServerName alice.com
#    # normal vhost configs
#       <IfModule peruser.c>
#           # this must match a Processor line
#           ServerEnvironment alice users /home/alice
#
#           # these are optional - defaults to the values specified above
#           MinSpareProcessors 4
#           MaxProcessors 20
#       </IfModule>
#</VirtualHost>

#<VirtualHost 61.67.7.140:80>
#  ServerName py.sahana.tw
#  ServerAdmin marr.tw@gmail.com
#  DocumentRoot /opt/web2py/applications
#

#  WSGIScriptAlias / /opt/web2py/wsgihandler.py
#  ## Edit the process and the maximum-requests to reflect your RAM
#  WSGIDaemonProcess web2py user=apache group=apache home=/opt/web2py processes=5 maximum-requests=50
#
#  RewriteEngine On
#  RewriteRule ^/$ /eden/ [R]
#
#  ### admin only accessible via SSH Tunnel
#  <Location "/admin">
#    SSLRequireSSL
#  </Location>
#  ### appadmin requires SSL
#  <LocationMatch "^(/[\w_]*/appadmin/.*)">
#    SSLRequireSSL
#  </LocationMatch>
#  ### static files do not need WSGI
#  <LocationMatch "^(/[\w_]*/static/.*)">
#    Order Allow,Deny
#    Allow from all
#  </LocationMatch>

#  ### everything else goes over WSGI
#  <Location "/">
#    Order deny,allow
#    Allow from all
#    WSGIProcessGroup web2py
#  </Location>
#
#  ErrorLog /var/log/httpd/demo_error.log
#  LogLevel warn
#  CustomLog /var/log/httpd/demo_access.log combined
#</VirtualHost>
NameVirtualHost *:80
<VirtualHost *:80>
  ServerName py.sahana.tw
  ServerAdmin marr.tw@gmail.com
        WSGIScriptAlias / /opt/web2py/wsgihandler.py
        WSGIDaemonProcess web2pytw user=eden group=eden home=/opt/web2py processes=5 maximum-requests=50

        RewriteEngine On
        RewriteCond %{REQUEST_URI}    !/eden/(.*)

        RewriteRule /(.*) /eden/$1 [R]

        ### everything else goes over WSGI
        <Location "/">
          Order deny,allow
          Allow from all
          WSGIProcessGroup web2pytw
        </Location>

#RewriteEngine On
#RewriteCond %{REQUEST_URI} ^/$
#rewriterule ^(.*)$ /eden$1 [r=301,nc]

#ProxyRequests Off

#ProxyPass / http://61.67.7.140:8000/
#ProxyPassReverse / http://61.67.7.140:8000/
#ProxyPreserveHost On
#<Proxy *>
#    Order deny,allow
#    Allow from all

#</Proxy>

  ErrorLog /var/log/httpd/demo_error.log
  LogLevel warn
  CustomLog /var/log/httpd/demo_access.log combined
</VirtualHost>
<VirtualHost *:80>
  ServerName test.sahana.tw
  ServerAdmin marr.tw@gmail.com

        WSGIScriptAlias / /home/eden/web2py/wsgihandler.py
        WSGIDaemonProcess web2py user=eden group=eden home=/home/eden/web2py processes=5 maximum-requests=50

        RewriteEngine On
        RewriteCond %{REQUEST_URI}    !/eden/(.*)
        RewriteRule /(.*) /eden/$1 [R]

        ### everything else goes over WSGI
        <Location "/">
          Order deny,allow

          Allow from all
          WSGIProcessGroup web2py
        </Location>


#RewriteEngine On
#RewriteCond %{REQUEST_URI} ^/$
#rewriterule ^(.*)$ /eden$1 [r=301,nc]

#ProxyPass / http://61.67.7.140:8009/
#ProxyPassReverse / http://61.67.7.140:8009/
#ProxyPreserveHost On
#<Proxy *>
#    Order deny,allow
#    Allow from all
#</Proxy>

  ErrorLog /var/log/httpd/test_error.log
  LogLevel warn
  CustomLog /var/log/httpd/test_access.log combined
</VirtualHost>

<VirtualHost *:80>
  ServerName 61.67.7.140
  DocumentRoot /var/www/html
  ErrorLog /var/log/httpd/error.log
  CustomLog /var/log/httpd/access.log combined
</VirtualHost>
<VirtualHost *:80>
     ServerName www.carer.org.tw
  RewriteEngine On
  RewriteRule ^/(.*) http://localhost:6543/VirtualHostBase/http/%{SERVER_NAME}:80/carer/VirtualHostRoot/$1 [L,P]
#  ProxyVia On
#  <LocationMatch "^[^/]">
#    Deny from all
#  </LocationMatch>
     ProxyPass / http://127.0.0.1:6543/carer
     ProxyPassReverse / http://127.0.0.1:6543/carer
     ProxyPreserveHost on
  <Proxy *>
      Order deny,allow
      Allow from all

  </Proxy>
     ErrorLog /var/log/httpd/carer_errors_log
     CustomLog /var/log/httpd/carer_log combined
</VirtualHost>

'User Last Seen Date' functionality on plone site : MongoDB as separate storage for recording user status

plone.recipe.zope2zeoserver

設定值影響登入

proxy_pass http://plone/VirtualHostBase/http/www.investment-economics.in:80/investmenteconomics/VirtualHostRoot/;

試圖隱藏 sitemap 只允許 googlebot

location = /sitemap.xml {
  if ($http_user_agent !~*(Googlebot)) {
    return 403;
  }
  try_files $uri @rewrite;
}

Varnish is popular for cache error

Varnish: Cache Hits, Purge Fails

Purging Varnish cache from Python web application

Reverse Proxy: collective.cover to multiple sites

Apache Proxy Error 202 vs 404 Custom 404

Tiles + plone.subrequest

gzip setting is removed from plone.app.caching cache:ruleset

Contents Delivery Network (CDN) Reduction: AWS CloudFront Sample VCL for Varnish 4.0

# nginx.conf
upstream to_varnish {
    server 127.0.0.1:6081;
}
server {
...
skipped
...
    location / {
        if ($uri ~* \.(jpe?g|png|gif|pdf|gz|tgz|bz2|tbz|zip|tiff|tif)$) {
            set $no_plone A;
        }
        if ($uri ~* /(image|(image_(?:[^/]|(?!view.*).+)))$) {
            set $no_plone A;
        }
        if ($uri ~* \.(svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|flv)$) {
            set $no_plone A;
        }
        if ($uri ~* \.(css|js)$) {
            set $no_plone A;
        }
        if ( $http_user_agent != "Amazon CloudFront" ) {
            set $no_plone "${no_plone}B";
        }
        if ($no_plone = AB) {
            expires 1h;
            rewrite ^ http://YOUR_SUBDOMAIN.cloudfront.net$request_uri? last;
        }
        proxy_pass http://to_varnish/VirtualHostBase/http/YOUR_DOMAIN:80/Plone/VirtualHostRoot/;
    }

Debina8 VPS Example: ln -s /etc/nginx/sites-available/plone /etc/nginx/sites-enabled/

upstream plone {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name your_domain;

    access_log /var/log/nginx/plone.access.log;
    error_log /var/log/nginx/plone.error.log;

    proxy_buffers 16 64k;
    proxy_buffer_size 128k;

    location / {
        proxy_pass http://plone;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect off;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Nginx Reverse Proxy. Multiple Applications on One Domain:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    server_name www.example.com;

    location / {
        try_files $uri $uri/ =404;
    }

    location /wordpress/ {
       proxy_set_header X-Real-IP  $remote_addr;
       proxy_set_header X-Forwarded-For $remote_addr;
       proxy_set_header Host $host;
       proxy_pass http://192.168.1.2:8080;
       }

    location /photoblog/ {
       proxy_set_header X-Real-IP  $remote_addr;
       proxy_set_header X-Forwarded-For $remote_addr;
       proxy_set_header Host $host;
       proxy_pass http://192.168.1.3:8080;
    }

       location /forum/ {
       proxy_set_header X-Real-IP  $remote_addr;
       proxy_set_header X-Forwarded-For $remote_addr;
       proxy_set_header Host $host;
       proxy_pass http://192.168.1.4:8080;
       }
}

Reverse Proxy for Apache + PHP-FPM

Ubuntu 16.04 PHP

Mountain Lion Compiling: error related with the PCRE library

$ curl -O ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.21.tar.gz
$ tar xvfz pcre-8.21.tar.gz
$ cd pcre-8.21
$ ./configure --enable-unicode-properties --enable-utf8
$ make
$ ./configure --with-pcre=../pcre-8.21

Serving uWSGI Apps on a Sub-directory with Nginx uWSGI and Database Lockups with SQLAlchemy uWSGI and libxml2 conflicts

Load Balance: HAProxy

Internet Information Services (IIS)

Includes and Excludes

External Links in a Plone Site Redirect to the Site Itself

.well-known folder

Virtual Host Monster (VHM)

How Magic URL Works 原理 Inside-Out Hosting Serve Plone Sites One Level Down

The Virtual Host Monster adds some magic to the traversal process of Zope. Two special keywords are added (VirtualHostBase and VirtualHostRoot) which allows you to configure the virtual host and the base folder inside your Zope instance. The VHM part of an ordinary rewrite rules looks like this:

^/(.*) \
http://localhost:10080/VirtualHostBase/http/www.example.org:80/example_site/VirtualHostRoot/$1

The address has seven parts:

  • http://localhost:10080
    This is only for apache's mod_proxy module. It configures what server should be accessed including protocol, host and port. In this example mod_proxy is accessing the ZServer at port 100080 on the same host using http.
  • VirtualHostBase
    This is the magic keyword to start virtual hosting. You must not add an object called VirtualHostBase to your zope root!
  • http
    The first path segment after VirtualHostBase defines the protocol of the vhost url.
  • www.example.org:80
    The second segment after VirtualHostBase defines the server and the port. Together with the protocol it's the base part of the url, in this example http://www.example.org:80. Like VirtualHostBase the protocol and server are no real objects. They are just put into the url for configuration purpose and they are stripped of the url after configuring the virtual host for a request.
  • example_site
    Now the real traversal through Zope starts. After setting up the protocol and server part of the new url we are traversing through Zope to the new virtual root for the vhost. You can add zero or more objects here.
  • VirtualHostRoot
    Finally the magic keyword that we have reached the new virtual root for the vhost. Everything after VirtualHostRoot is visible to the browser.
  • $1 and ^/(.*)
    $1 and ^/(.*) are some regex foo. ^/(.*) means "Match everything starting with a / and save every char after the / in the var $1.
  • Special case _vh_foo
    Imagen you want to have http://www.example.org/foo/ as the root url of your virtual url. You can get the effect by using the special _vh_ declaration. Any path segment starting with _vh_ is stripped of the url for traversal through zope and readded without _vh_ after traversal. Example:
    ^/foo/(.*) \
    http://localhost:10080/VirtualHostBase/http/www.example.org:80/example_site/VirtualHostRoot/_vh_foo/$1

Note: You are neither allowed to create an object called VirtualHostBase or VirtualHostRoot in your zope nor should you add an object with the same id of your VHM. It may work but it may also break your site.

傳給 VirtualHostMonster 的 URL 和 portal_url 或 absolute_url() 一致,如果遇到網站讀得到內容,卻讀不到 CSS 檔案,原因可能是 VirtualHostMonster 設定錯誤。

帳號登入日誌

Plone 本身有記錄,Apache / Nginx 也會有記錄。

var/client1/Z2.log

/var/log/apache2/mysite_access.log

140.119.101.100 - - [22/Aug/2018:11:45:41 +0800] "GET /passwordreset/501c7b09f76f464f82ea06df9019c413 HTTP/1.1" 200 6341 "http://mysite.com/login?__ac_name=myacct"

ZEO

$ bin/zeoserver start
$ bin/client1 start
$ bin/client2 debug

Rread-only for Visitors but Update via Console

Adding ZEO to an existing Pyramid ZODB project

Genweb Architecture

Sticky Session

Define Database Location with Unified Installation

plone.recipe.zeoserver read-only

Zope Replication Services (ZRS)

TimeZone

Zope Application Server

environment-vars =
    TZ Asia/HongKong

時區設定 pytz python-dateutil python-tz /etc/timezone ubuntu

WARNING plone.event The timezone HKT is not a valid timezone from the Olson database or pytz. Falling back to UTC.

先在 Linux 設定系統 Local Time 為 UTC

$ sudo dpkg-reconfigure tzdata
Current default time zone: 'Etc/UTC'
Local time is now:      Thu Aug 28 15:23:54 UTC 2014.
Universal Time is now:  Thu Aug 28 15:23:54 UTC 2014.

再到 Plone Site Setup 設定 Default TimeZone 為 Asia/Taipei

或是使用 http://bitbucket.org/pellepim/jstimezonedetect

plone.app.event 設計思惟 buildout.cfg 裡 [instance] 指定 TZ 在 date 的 Linux 指令顯示 CST 情況下,也沒有正確。

SSL HTTPS

Synchronizing

Static Site Generator: Django Medusa 複製網站內容

Static Deployment: stxnext.staticdeployment Dexterity support

Postfix Check Email Sending Status

Log Rotation for uwsgi and Python Applications: SIGHUP is NOT used for log rotation

wheel: for Python deployment. moving-a-static-website-to-aws-s3-cloudfront-with-https