Deployment
上路之前,值得先閱讀 Web Architecture Developer Manual 的預備知識,再依照實際部屬的工具,動手進行設定。
每個 Framework 都自帶 Web Server 了,在 Reverse Proxy 或 Load Balance 場合,再把 Nginx 放在前面。
Solid Python Deployments for Everybody DevOps vs SRE
比較: 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
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
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
搭配 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
[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>
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 Redirect
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
RewriteRule vs ProxyPassReverse ProxyPass Keepalive: proxy: Error reading from remote server returned by
Nginx
web guide Load Balance regis_huang 有 PHP 參數調整經驗
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.
# 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; 語法
location /old-link.html { rewrite ^/.* http://www.google.com/ permanent; }
location ~ ^/crgis_tw/(.*) { root /var/www/html; }
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.siteisolation 或 AccessRule 來處理。
# 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
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
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
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
Internet Information Services (IIS)
External Links in a Plone Site Redirect to the Site Itself
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
Define Database Location with Unified Installation
plone.recipe.zeoserver read-only
Zope Replication Services (ZRS)
TimeZone
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 情況下,也沒有正確。
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