GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing webwareforpython.github.io — Deployment — Webware for Python 3 3.1.0 documentation Deployment¶Webware for Python 3 uses the Web Server Gateway Interface (WSGI) which allows deploying Webware apps with any available WSGI server. If your performance requirements are not that high, you can use waitress as WSGI server, which is used as the development server for Webware, to serve your application on a production system as well. If your performance requirements are higher, we recommend serving Webware applications using Apache and mod_wsgi. But there are also many other options, and you can add caching, load balancing and other techniques or use a CDN to improve performance. Installation on the Production System¶In order to install your Webware for Python 3 application on the production system, first make sure the minimum required Python version is already installed. One popular and recommended option is running a Linux distribution on your production system - see Installing Python 3 on Linux. Note that Webware for Python 3.0 supports Python 3.6 to 3.12, and Webware for Python 3.1 supports Python 3.10 to 3.14. Next, we recommend creating a virtual environment for your Webware for Python 3 application. We also recommend creating a dedicated user as owner of your application, and placing the virtual environment into the home directory of that user. When you are logged in as that user under Linux, you can create the virtual environment with the following command. If you get an error, you may need to install python3 -m venv .venv This will create the virtual environment in the subdirectory . .venv/bin/activate pip install "Webware-for-Python>=3" You will also need to install other Python packages required by your application into the virtual environment with pip, unless these are provided as part of the application, e.g. in a pip install waitress As the next step, you need to copy the application working directory containing your Webware for Python 3 application to your production system. We recommend putting it into the directory where you created the virtual environment, so that both are siblings. It is important that the application working directory is readable for the user that will run the WSGI server, but not writable. For security reasons, we recommend running the WSGI server with as a dedicated user with low privileges who is not the owner of the application working directory. The directory should also not be readable to other users. The subdirectories of the application working directory should be readable only as well, except for the webware make -g www-data path-to-app-work-dir We recommend using an automatic deployment solution such as Fabric for copying your application working directory from your development or staging server to your production server. It is also possible to use Git hooks to deploy your application with Git. Also, make sure the virtual environment you created above is readable by the user running the WSGI server, e.g. by using the same group ownership as above: chgrp -R www-data .venv Starting the WSGI Server on Boot¶On a production system, you want to set up your system so that the WSGI server starts automatically when the system boots. If you are using Apache and mod_wsgi, as explained further below, then you only need to make sure Apache starts automatically, and you can skip this step. There are a lot of options to start applications at boot time. First, you can use the startup system of your operating system directly. We will show how this works using systemd as an example. Second, you can use one of the many available process managers to start and control the WSGI server. We will show how this works using Supervisor. Using systemd¶We assume that you have already copied your application working directory to the production system as explained above, and we assume you’re using waitress as your WSGI server. In order to make your application available as a systemd service, you only need to add the following service file into the directory [Unit] Description=My Webware application After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=1 User=www-data Group=www-data ExecStart=path-to-virtual-env/bin/webware serve --prod WorkingDirectory=path-to-app-work-dir [Install] WantedBy=multi-user.target Adapt the options as needed. Note that if you use the After adding or changing the service file, you need to run the following command so that systemd refreshes its configuration: sudo systemctl daemon-reload You tell systemd to automatically run your service file on system boot by enabling the service with the following command: sudo systemctl enable webware If you named your service file differently, you need to specify that name instead of sudo systemctl disable webware To start the service manually, run this command: sudo systemctl start webware You can list errors that appeared while running the service using this command: sudo journalctl -ru webware The output of your application will be logged to the file To restart the service, you need to do this: sudo systemctl restart webware If you want to automatically restart the service whenever there are changes in the application working directory, you can install a systemd path unit to watch the directory and run the above command whenever something changes. Alternatively, you can run Using Supervisor¶You can also use Supervisor to control your WSGI server. On many Linux distributions, Supervisor can be installed with the package manager, but you can also install it manually using: pip install supervisor The disadvantage of such a manual installation is that you will also need to integrate it into the service management infrastructure of your system manually, e.g. using a service file as explained above. Therefore we recommend that you install the Linux package if it is available. For instance, on Ubuntu you would do this with: sudo apt-get install supervisor In the following, we assume that you installed Supervisor like this. You will then usually have a directory [program:webware] user=www-data command=path-to-virtual-env/bin/webware serve --prod directory=path-to-app-work-dir You can add many more options to the configuration. Adapt the options above and add other options as needed. You may want to change the section header Reload the Supervisor configuration file and restart affected programs like this: supervisorctl reread supervisorctl update This should automatically start the Webware application. By default, the output of your application will be redirected to the file To show the process status of your application, run this command: supervisorctl status webware If you named the configuration section differently, you need to specify that name instead of supervisorctl restart webware If you want to automatically restart whenever there are changes in the application working directory, you can for example use Supervisor to run a separate program that watches the directory using inotify, and runs the above command whenever something changes, or you can run Logfile Rotation¶The application log file (which you will find in path-to-app-work-dir/Logs/Application.log { weekly rotate 9 copytruncate compress dateext missingok notifempty su www-data www-data } Modify the configuration as you see fit. The Assuming you created the configuration file as logrotate -f /etc/logrotate.d/webware Running behind a Reverse Proxy¶There are several reasons why you may want to run the WSGI server that is serving your Webware application behind a reverse proxy. First, it can serve as a kind of load balancer, redirecting traffic to other applications or static files away from your Webware application and request the WSGI server only for the dynamic content where it is really needed. Second, it can provide TLS encryption in order to support HTTPS connections, compress data going in and out the server, and cache frequently used content, and is optimized to do all of this very quickly. If you’re using the waitress WSGI server, this is an important issue, since waitress itself does not provide TLS support. Third, a reverse proxy also adds another security layer to your production system. In the following we show how you can use Apache and NGINX as reverse proxy for your Webware application. Again, if you are using Apache and mod_wsgi, as explained further below, then you normally don’t need a separate proxy server, and you can skip this step. Using Apache as Reverse Proxy¶The first thing you need to do after installing Apache is to enable the Apache mod_proxy and mod_proxy_http modules. You can usually do this as follows: sudo a2enmod proxy proxy_http At this point, you may want to enable other Apache modules as well. For instance, if you want to use encryption with TLS (HTTPS connections), you need to also enable the mod_ssl module: sudo a2enmod ssl Maybe you want to enable some more modules providing load balancing capabilities, such as mod_proxy_balancer and mod_lbmethod_byrequests. We won’t cover these modules in this deployment guide, but keep in mind that they are available if you need to scale up. Assuming you configured the WSGI server to run on port 8080 using the localhost interface 127.0.0.1, you now need to add the following directives to your Apache configuration: ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ Note: Do not set If you want to support encryption, you also need to create a server certificate and specify it in your Apache configuration. For testing only, a self-signed certificate will do, which may be already installed and configured. In the Internet you will find many instructions for creating a real server certificate and configuring Apache to use it. Reload Apache after any changes you make to the configuration, e.g. with The two lines of configuration above make Apache work as a reverse proxy for any URL, i.e. all traffic is passed on to the WSGI server. This means that the WSGI server will also deliver any static assets that are part of your application, like images, CSS scripts, JavaScript files or static HTML pages. This is inefficient and creates an unnecessary load on the WSGI server. It is much more efficient if you let Apache serve the static assets. To achieve this, use the following Apache configuration: Alias /static path-to-app-work-dir/Static
<Directory path-to-app-work-dir/Static>
Require all granted
</Directory>
ProxyPass /static !
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
With this configuration, you can access the static assets in the You can also do it the other way around, e.g. let everything behind the prefix DocumentRoot path-to-app-work-dir/Static <Directory path-to-app-work-dir/Static> Require all granted </Directory> ProxyPass /app http://127.0.0.1:8080/ ProxyPassReverse /app http://127.0.0.1:8080/ In this case, you should also tell the Webware application that you are using the webware serve -l 127.0.0.1 -p 8080 --url-prefix /app --prod This prefix will then be passed to Webware in the Similarly, to tell Webware that you are using HTTPS connections, you can use the webware serve -l 127.0.0.1 -p 8080 --url-schema https --prod You should then also add the following line to the Apache configuration: RequestHeader set X-Forwarded-Proto https If you want to override WSGI environment variables using proxy headers, you need to add the options See also the remarks on running behind a reverse proxy in the waitress documentation. Using NGINX as a Reverse Proxy¶Frequently, NGINX is used instead of Apache as a reverse proxy, because it is more lightweight and performs a bit better when serving static content. Contrary to Apache, you don’t need to enable any additional modules to make NGINX work as a reverse proxy. After installing NGINX and configuring the WSGI server to run on port 8080 using the localhost interface 127.0.0.1, you now need to add the following lines to your NGINX configuration: location /static {
alias path-to-app-work-dir/Static;
}
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
}
If you want to support encryption, you also need to create a server certificate and specify it in your NGINX configuration. For testing only, a self-signed certificate will do, which may be already installed. In the Internet you will find many instructions for creating a real server certificate and configuring NGINX to use it. After reloading the NGINX configuration, e.g. with If you want to do it the other way around, i.e. serve any static assets at the root URL, and your Webware application with the URL prefix root path-to-app-work-dir/Static
location / {
}
location /app {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
}
In this case, you should also tell the Webware application that you are using the webware serve -l 127.0.0.1 -p 8080 --url-prefix /app --prod This prefix will then be passed to Webware in the If you want to override WSGI environment variables using proxy headers, you need to add the options See also the remarks on running behind a reverse proxy in the waitress documentation. Using Apache and mod_wsgi¶While you can deploy Webware applications using the waitress WSGI server, as explained above, or run the application with other possibly better performing WSGI servers, as explained further below, our recommended way of deploying Webware application is using Apache and mod_wsgi, since it combines excellent performance with low installation and maintenance effort. In particular, you will not need to care about running a separate WSGI server and starting it automatically, because this is handled by mod_wsgi already, and you will not need to install a reverse proxy, because you can use Apache to server the static content and dispatch to Webware via mod_wsgi for the dynamic content. The Apache web server can also care about everything that is needed to serve your content securely via HTTPS. The first thing you need is to make sure that Apache is installed on your production system with the “worker” MPM module. On some systems, the “prefork” MPM module is still the default, but “worker” is much better suited for our purposes. See also the section on processes and threading in the mod_wsgi documentation. Next you will need to install mod_wsgi. If possible, install a version that is available as a binary package for your system. There may be different versions of mod_wsgi available. Make sure you install the one for the Apache version running on your system and the Python version you are using in your Webware application. The package may be called something like “apache2-mod_wsgi-python3” or “libapache2-mod-wsgi-py3”. If no suitable, current version of mod_wsgi is available, you will need to install mood_wsgi from source. After installation, the module should be already enabled, but to be sure, enable the mod_wsgi Apache module with the following command: sudo a2enmod wsgi At this point, you may want to enable other Apache modules as well. For instance, if you want to use encryption with TLS (HTTPS connections), you need to also enable the mod_ssl module: sudo a2enmod ssl In that case, you also need to create a server certificate and specify it in your Apache configuration. For testing only, a self-signed certificate will do, which may be already installed and configured. In the Internet you will find many instructions for creating a real server certificate and configuring Apache to use it. Add the following lines to your Apache configuration in order to serve your Webware application under the root URL, and static assets under the URL prefix Alias /static path-to-app-work-dir/Static <Directory path-to-app-work-dir/Static> Require all granted </Directory> WSGIDaemonProcess webware threads=20 python-home=path-to-virtual-env WSGIProcessGroup webware WSGIScriptAlias / path-to-app-work-dir/Scripts/WSGIScript.py <Directory path-to-app-work-dir/Scripts> Require all granted </Directory> Note that Reload Apache after any changes you make to the configuration, e.g. with If you want to do it the other way around, i.e. serve any static assets at the root URL, and your Webware application with the URL prefix DocumentRoot path-to-app-work-dir/Static <Directory path-to-app-work-dir/Static> Require all granted </Directory> WSGIDaemonProcess webware threads=20 python-home=path-to-virtual-env WSGIProcessGroup webware WSGIScriptAlias /app path-to-app-work-dir/Scripts/WSGIScript.py <Directory path-to-app-work-dir/Scripts> Require all granted </Directory> In this case, the prefix You can test the Apache configuration for errors with the command LogLevel info WSGIVerboseDebugging On A frequent problem is that the virtual environment into which you installed Webware uses a different Python version than the one that the currently enabled mod_wsgi module was built for. In this case, re-create the virtual environment with the proper Python version, or install a mod_wsgi module that was built for the Python version you are using in your Webware application. The output of your application will be logged to the file Note that mod_wsgi can be operated in two modes, “embedded mode” and “daemon mode”. The above configuration uses “daemon mode” which is the recommended mode for running Webware applications, even if “embedded mode” is the default mode for historical reasons. The configuration creates one “process group” called “webware”. You can adapt and optimize the configuration by setting various options, like this: WSGIDaemonProcess webware \ user=www-data group=www-data \ threads=15 \ python-home=path-to-virtual-env \ display-name='%{GROUP}' \ lang='de_DE.UTF-8' locale='de_DE.UTF-8' \ queue-timeout=45 socket-timeout=60 connect-timeout=15 \ request-timeout=60 inactivity-timeout=0 startup-timeout=15 \ deadlock-timeout=60 graceful-timeout=15 eviction-timeout=0 \ restart-interval=0 shutdown-timeout=5 maximum-requests=0 You can also define more than one process group, and use different process groups for different applications. In this case, mod_macro can be useful to avoid specifying the same options multiple times. It can be used like this to define different groups with a different number of threads that are created in each daemon process: <Macro WSGIProcess $name $threads>
WSGIDaemonProcess $name \
user=www-data group=www-data \
threads=$threads \
display-name='%{GROUP}' \
python-home=path-to-common-virtual-env \
lang='de_DE.UTF-8' locale='de_DE.UTF-8' \
queue-timeout=45 socket-timeout=60 connect-timeout=15 \
request-timeout=60 inactivity-timeout=0 startup-timeout=15 \
deadlock-timeout=60 graceful-timeout=15 eviction-timeout=0 \
restart-interval=0 shutdown-timeout=5 maximum-requests=0
</Macro>
Use WSGIProcess app1 25
WSGIScriptAlias /app1 \
path-to-app1-work-dir/Scripts/WSGIScript.py process-group=app1
<Directory path-to-app1-work-dir/Scripts>
Require all granted
</Directory>
Use WSGIProcess app2 10
WSGIScriptAlias /app2 \
path-to-app2-work-dir/Scripts/WSGIScript.py process-group=app2
<Directory path-to-app2-work-dir/Scripts>
Require all granted
</Directory>
In the above configurations, we are running only one process per process group, but multiple threads. The first app will use 25 threads, while the second app will use only 10. The WSGI environment variable If you want to restart the daemon process after deploying a new version of the Webware application to the application working directory, you can do so by changing (touching) the WSGI file: touch Scripts/WSGIScript.py The mod_wsgi documentation also explains how to restart daemon processes by sending a SIGINT signal, which can be also done by the Webware application itself, and it also explains how you can monitor your application for code changes and automatically restart in that case. Other WSGI servers¶Depending on your production environment and the type of your application, it may make sense to deploy Webware applications with other WSGI servers. In the following we will give some advice for configuring some of the more popular WSGI servers to run Webware applications. Using Bjoern as WSGI server¶Bjoern is a fast, lightweight WSGI server for Python, written in C using Marc Lehmann’s high performance libev event loop and Ryan Dahl’s http-parser. You first need to install In order to make use of Bjoern, you need to add the following at the end of the from bjoern import run run(application, 'localhost', 8088) Since Bjoern does not support the WSGI settings = {'WSGIWrite': False} A systemd unit file at [Unit] Description=Bjoern WSGI server running Webware application After=network.target StartLimitIntervalSec=0 [Install] WantedBy=multi-user.target [Service] User=www-data Group=www-data PermissionsStartOnly=true WorkingDirectory=path-to-app-work-dir ExecStart=path-to-virtual-env/bin/python Scripts/WSGIScript.py TimeoutSec=600 Restart=on-failure RuntimeDirectoryMode=775 You can then enable and run the service as follows: systemctl enable bjoern systemctl start bjoern Using MeinHeld as WSGI server¶MeinHeld is another lightweight, high performance WSGI server. You first need to Add the following at the end of the from meinheld import server server.listen(("127.0.0.1", 8080)) server.run(application) Similarly to Bjoern, you need to also adapt the settings at the top of the settings = {'WSGIWrite': False} Using CherryPy as WSGI server¶Cherrypy is a minimalist Python web framework that also contains a reliable, HTTP/1.1-compliant, WSGI thread-pooled webserver. TO make use of CherryPy’s WSGI server, add the following at the end of the import cherrypy cherrypy.tree.graft(application, '/') cherrypy.server.unsubscribe() server = cherrypy._cpserver.Server() server.socket_host = '127.0.0.1' server.socket_port = 8080 server.thread_pool = 30 server.subscribe() cherrypy.engine.start() cherrypy.engine.block() Using uWSGI as WSGI server¶The uWSGI project aims at developing a full stack for building hosting services, and it also contains a WSGI server component. You first need to You can start the uWSGI server component as follows: cd path-to-app-work-dir . ../.venv/bin/activate uwsgi --http-socket 127.0.0.1:8080 --threads 30 \\ --virtualenv path-to-virtual-env --wsgi-file Scripts/WSGIScript.py You can also create a systemd file to run this automatically when the system boots, as explained above. Many more uWSGI configuration options are explained in the uWSGI documentation, we will not go into more details here. Using Gunicorn as WSGI server¶Gunicorn is a fast WSGI server for Unix using a pre-fork worker model. You first need to You can start the Gunicorn WSGI server as follows: cd path-to-app-work-dir . ../.venv/bin/activate PYTHONPATH=Scripts gunicorn -b 127.0.0.1:8080 WSGIScript:application You can also create a systemd file to run this automatically when the system boots, as explained above. Many more Gunicorn configuration options are explained in the Gunicorn documentation, we will not go into more details here. Sourceless Installs¶When deploying a Webware application, you do not really need to copy the source code to the production system, it suffices to deploy the compiled compiled Python files. Though this is actually not considered a good practice, and it also does not really help to keep the source code secret (as it can be decompiled pretty easily), there may be reasons why you still want to do this, for instance to impede casual users to tinker with your code on the server. To do this, you first need to compile all your Python files in the application working directory: cd path-to-app-work-dir . ../.venv/bin/activate python -OO -m compileall -b . By activating the virtual environment, you make sure that you compile the source files with the proper Python version. The If you want to serve contexts outside the application working directory, like the default Examples or Admin context, you need to compile these as well, in a similar way. You can now remove all the source files except the WSGI script and the cd path-to-app-work-dir find . -type f -name '*.py' -delete -o \ -type d -name 'Scripts' -prune -o \ -type d -name __pycache__ -exec rm -rf {} \+ In order to make this work, you will also need to modify some settings in ExtensionsToIgnore = { '.py', '.pyo', '.tmpl', '.bak', '.py_bak', '.py~', '.psp~', '.html~', '.tmpl~' } ExtensionCascadeOrder = ['.pyc', '.psp', '.html'] FilesToHide = { '.*', '*~', '*.bak', '*.py_bak', '*.tmpl', '*.py', '*.pyo', '__init__.*', '*.config' } Caveats of Multiprocessing Mode¶As explained above, it is possible to operate mod_wsgi and some other WSGI servers in multiprocessing mode, where several processes serve the same Webware application in parallel, or you can run several multithreaded WSGI servers in parallel, maybe even on different machines, and use a load balancer as a reverse proxy to distribute the load between the different servers. This is totally doable, and may make sense in order to better utilize existing hardware. Because of the the GIL, a multithreaded Python application will not be able to get the full performance from a multi-core machine when running a CPU-bound application. However, there are some caveats that you need to be aware of:
|
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |