SERVICE modules
We are using Ubuntu Bionic 64bit
https://github.com/elpaso/qgis3-server-vagrant
in Vagrant it is provided by the box:
https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box
Quickstart:
vagrant up
vagrant ssh sudo su -
Checkpoint: you need to be able to log into the machine and become root
Only for unprovisioned machines!
wget https://github.com/elpaso/qgis3-server-vagrant/archive/master.zip unzip master.zip rmdir /vagrant/ mv qgis3-server-vagrant-master/ /vagrant
# Add QGIS repositories apt-key adv --keyserver keyserver.ubuntu.com --recv-key CAEB3DC3BDF7FB45 echo 'deb http://qgis.org/debian bionic main' > /etc/apt/sources.list.d/debian-gis.list apt-get update && apt-get -y upgrade
Checkpoint: the available version of qgis-server must be >= 3 from qgis.org
apt-cache policy qgis-server qgis-server: Installed: 1:3.0.0+28bionic Candidate: 1:3.0.0+28bionic Version table: *** 1:3.0.0+28bionic 500 500 http://qgis.org/debian bionic/main amd64 Packages
Install the software
export DEBIAN_FRONTEND=noninteractive apt-get -y install qgis-server python-qgis xvfb # Install utilities (optional) apt-get -y install vim unzip ipython3
Checkpoint: qgis installed with no errors, you can check it with
/usr/lib/cgi-bin/qgis_mapserv.fcgi 2> /dev/null Content-Length: 54 Content-Type: text/xml; charset=utf-8 Server: Qgis FCGI server - QGis version 3.0.0-Girona Status: 500 <ServerException>Project file error</ServerException>
# Install sample projects and plugins mkdir -p $QGIS_SERVER_DIR/logs cp -r /vagrant/resources/web/htdocs $QGIS_SERVER_DIR cp -r /vagrant/resources/web/plugins $QGIS_SERVER_DIR cp -r /vagrant/resources/web/projects $QGIS_SERVER_DIR chown -R www-data.www-data $QGIS_SERVER_DIR
# Setup xvfb cp /vagrant/resources/xvfb/xvfb.service \ /etc/systemd/system/xvfb.service systemctl enable /etc/systemd/system/xvfb.service service xvfb start # Symlink to cgi for apache CGI mode ln -s /usr/lib/cgi-bin/qgis_mapserv.fcgi \ /usr/lib/cgi-bin/qgis_mapserv.cgi
Installation (with FCGI module)
# Common configuration export QGIS_SERVER_DIR=/qgis-server # Install the required server software export DEBIAN_FRONTEND=noninteractive apt-get -y install apache2 libapache2-mod-fcgid
Configure the web server
cp /vagrant/resources/apache2/001-qgis-server.conf \ /etc/apache2/sites-available sed -i -e "s@QGIS_SERVER_DIR@${QGIS_SERVER_DIR}@g" \ /etc/apache2/sites-available/001-qgis-server.conf sed -i -e 's/VirtualHost \*:80/VirtualHost \*:81/' \ /etc/apache2/sites-available/001-qgis-server.conf sed -i -e "s@QGIS_SERVER_DIR@${QGIS_SERVER_DIR}@g" \ $QGIS_SERVER_DIR/htdocs/index.html
VirtualHost configuration for both FastCGI and CGI
<VirtualHost *:81> # [ ... ] Standard config goes here # Longer timeout for WPS... default = 40 FcgidIOTimeout 120 FcgidInitialEnv LC_ALL "en_US.UTF-8" FcgidInitialEnv LANG "en_US.UTF-8" FcgidInitialEnv PYTHONIOENCODING UTF-8 FcgidInitialEnv QGIS_DEBUG 1 FcgidInitialEnv QGIS_SERVER_LOG_FILE "QGIS_SERVER_DIR/logs/qgis-apache-001.log" FcgidInitialEnv QGIS_SERVER_LOG_LEVEL 0 FcgidInitialEnv QGIS_PLUGINPATH "QGIS_SERVER_DIR/plugins" FcgidInitialEnv QGIS_AUTH_DB_DIR_PATH "QGIS_SERVER_DIR" FcgidInitialEnv QGIS_OPTIONS_PATH "QGIS_SERVER_DIR" FcgidInitialEnv QGIS_CUSTOM_CONFIG_PATH "QGIS_SERVER_DIR" FcgidInitialEnv DISPLAY ":99"
CGI
# For simple CGI: ignored by fcgid SetEnv LC_ALL "en_US.UTF-8" SetEnv LANG "en_US.UTF-8" SetEnv PYTHONIOENCODING UTF-8 SetEnv QGIS_DEBUG 1 SetEnv QGIS_SERVER_LOG_FILE "QGIS_SERVER_DIR/logs/qgis-apache-001.log" SetEnv QGIS_SERVER_LOG_LEVEL 0 SetEnv QGIS_PLUGINPATH "QGIS_SERVER_DIR/plugins" SetEnv QGIS_AUTH_DB_DIR_PATH "QGIS_SERVER_DIR" SetEnv QGIS_OPTIONS_PATH "QGIS_SERVER_DIR" SetEnv QGIS_CUSTOM_CONFIG_PATH "QGIS_SERVER_DIR" SetEnv DISPLAY ":99"
# Needed for QGIS plugin HTTP BASIC auth <IfModule mod_fcgid.c> RewriteEngine on RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] </IfModule> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride All Options +ExecCGI -MultiViews +FollowSymLinks Allow from all AddHandler cgi-script .cgi AddHandler fcgid-script .fcgi Require all granted </Directory> </VirtualHost>
Enable sites and restart
a2enmod rewrite # Only required by some plugins a2enmod cgid # Required by plain old CGI a2dissite 000-default a2ensite 001-qgis-server # Listen on port 81 instead of 80 (nginx) sed -i -e 's/Listen 80/Listen 81/' /etc/apache2/ports.conf service apache2 restart # Restart the server
Checkpoint: check wether Apache is listening on localhost port 8081 http://localhost:8081
# Install the software export DEBIAN_FRONTEND=noninteractive apt-get -y install nginx
rm /etc/nginx/sites-enabled/default cp /vagrant/resources/nginx/qgis-server \ /etc/nginx/sites-enabled sed -i -e "s@QGIS_SERVER_DIR@${QGIS_SERVER_DIR}@" \ /etc/nginx/sites-enabled/qgis-server
# Extract server name and port from HTTP_HOST, this # is needed because we are behind a VMs mapped port map $http_host $parsed_server_name { default $host; "~(?P<h>[^:]+):(?P<p>.*+)" $h; } map $http_host $parsed_server_port { default $host; "~(?P<h>[^:]+):(?P<p>.*+)" $p; }
Load balancing (round robin default, or least_conn;)
upstream qgis_mapserv_backend {
server unix:/run/qgis_mapserv4.sock;
server unix:/run/qgis_mapserv3.sock;
server unix:/run/qgis_mapserv2.sock;
server unix:/run/qgis_mapserv1.sock;
}
Note: sessions and persistence (ip-hash)!
server { listen 80 default_server; listen [::]:80 default_server; # This is vital underscores_in_headers on; root /qgis-server/htdocs; location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; }
location /cgi-bin/ { # Disable gzip (it makes scripts feel slower since they # have to complete before getting gzipped) gzip off; # Fastcgi socket fastcgi_pass qgis_mapserv_backend; # $http_host contains the original server name and port, such as: "localhost:8080" # QGIS Server behind a VM needs this parsed values in order to automatically # get the correct values for the online resource URIs fastcgi_param SERVER_NAME $parsed_server_name; fastcgi_param SERVER_PORT $parsed_server_port; # Fastcgi parameters, include the standard ones # (note: this needs to be last or it will overwrite fastcgi_param set above) include /etc/nginx/fastcgi_params; } }
Socket
# Path: /etc/systemd/system/qgis-server-fcgi@.socket # systemctl enable qgis-server-fcgi@{1..4}.socket && systemctl start qgis-server-fcgi@{1..4}.socket [Unit] Description = QGIS Server FastCGI Socket (instance %i) [Socket] SocketUser = www-data SocketGroup = www-data SocketMode = 0660 ListenStream = /run/qgis_mapserv%i.sock [Install] WantedBy = sockets.target
Service
# Path: /etc/systemd/system/qgis-server-fcgi@.service # systemctl start qgis-server-fcgi@{1..4}.service [Unit] Description = QGIS Server Tracker FastCGI backend (instance %i) [Service] User = www-data Group = www-data ExecStart = /usr/lib/cgi-bin/qgis_mapserv.fcgi StandardInput = socket #StandardOutput = null #StandardError = null StandardOutput=syslog StandardError=syslog SyslogIdentifier=qgis-server-fcgi WorkingDirectory=/tmp Restart = always
Service
# Environment Environment="QGIS_AUTH_DB_DIR_PATH=QGIS_SERVER_DIR/projects" Environment="QGIS_SERVER_LOG_FILE=QGIS_SERVER_DIR/logs/qgis-server-fcgi.log" Environment="QGIS_SERVER_LOG_LEVEL=0" Environment="QGIS_DEBUG=1" # Temporary workaround for #18230 Environment="QGIS_PREFIX_PATH=/usr" Environment="DISPLAY=:99" Environment="QGIS_PLUGINPATH=QGIS_SERVER_DIR/plugins" Environment="QGIS_OPTIONS_PATH=QGIS_SERVER_DIR" Environment="QGIS_CUSTOM_CONFIG_PATH=QGIS_SERVER_DIR" [Install] WantedBy = multi-user.target
Check WMS and WFS using QGIS as a client.
Check that WFS requires a "username" and "password"
Check that WWS GetFeatureInfo returns a (blueish) formatted HTML
Note: a test project with pre-configured endpoints is available in the resources/qgis/ directory.
Searching features with WMS
http://localhost:8080/cgi-bin/qgis_mapserv.fcgi? MAP=/qgis-server/projects/helloworld.qgs&SERVICE=WMS &REQUEST=GetFeatureInfo&CRS=EPSG%3A4326&WIDTH=1794&HEIGHT=1194 &LAYERS=world&QUERY_LAYERS=world& FILTER=world%3A%22NAME%22%20%3D%20%27SPAIN%27
The filter is a QGIS Expression:
FILTER=world:"NAME" = 'SPAIN'
The SELECTION parameter can highlight features from one or more layers: Vector features can be selected by passing comma separated lists with feature ids in GetMap and GetPrint. Example: SELECTION=mylayer1:3,6,9;mylayer2:1,5,6
http://localhost:8080/cgi-bin/qgis_mapserv.fcgi? MAP=/qgis-server/projects/helloworld.qgs&SERVICE=WMS&VERSION=1.3.0& SELECTION=world%3A44&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true& LAYERS=world&CRS=EPSG%3A4326&STYLES=&DPI=180&WIDTH=1794&HEIGHT=1194& BBOX=31.7944%2C-18.2153%2C58.0297%2C21.20361
From composer templates (with substitutions!)
<Layouts> <Layout units="mm" printResolution="300" name="Printable World" worldFileMap="{db75b0bf-f2f1-42e6-9727-1b6b21d8862e}"> ...
FORMAT can be any of PDF, PNG See also: DXF Export
http://localhost:8080/cgi-bin/qgis_mapserv.fcgi? MAP=/qgis-server/projects/helloworld.qgs&SERVICE=WMS&VERSION=1.1.1& REQUEST=GetPrint&TEMPLATE=Printable%20World&CRS=EPSG%3A4326& map0:EXTENT=4,52,14,58&FORMAT=png&LAYERS=bluemarble,world
http://localhost:8080/cgi-bin/qgis_mapserv.fcgi? MAP=/qgis-server/projects/helloworld.qgs&SERVICE=WMS& VERSION=1.1.1&REQUEST=GetPrint&TEMPLATE=Printable%20World &CRS=EPSG%3A4326&map0:EXTENT=4,52,14,58&FORMAT=png &LAYERS=bluemarble,world&print_title=Custom%20print%20title!
Since QGIS 2.8
from qgis.server import QgsServer s = QgsServer() header, body = s.handleRequest( 'MAP=/qgis-server/projects/helloworld.qgs' + '&SERVICE=WMS&REQUEST=GetCapabilities') print(header, body)
Full script: https://github.com/qgis/QGIS/blob/release-2_18/tests/src/python/qgis_wrapped_server.py
Since QGIS 2.99
from qgis.core import QgsApplication from qgis.server import * qgs_app = QgsApplication([], False) qgs_server = QgsServer() request = QgsBufferServerRequest( 'http://localhost:8081/?MAP=/qgis-server/projects/helloworld.qgs' + '&SERVICE=WMS&REQUEST=GetCapabilities') response = QgsBufferServerResponse() qgs_server.handleRequest(request, response) print(response.headers(), response.body()) qgs_app.exitQgis()
Full script: https://github.com/qgis/QGIS/blob/master/tests/src/python/qgis_wrapped_server.py
See presentation: http://www.itopen.it/bulk/nodebo/Presentations/Server%20Plugins/index.html
There are no substantial differences between plugins API in 2.x and 3.x
Since QGIS 2.12
Fine-grained control over layers, features and attributes!
https://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/server.html#access-control-plugin
Since QGIS 2.99
New server plugin-based architecture!
You can now create custom services in pure Python.
Systemd
# Listen on ports 809%i # Path: /etc/systemd/system/qgis-server-python@.service # systemctl start qgis-server-python@{1..4}.service [Unit] Description = QGIS Server Tracker Python backend (instance %i) [Service] User = www-data Group = www-data ExecStart = /qgis-server/qgis_wrapped_server_wsgi.py StandardInput = null #StandardOutput = null #StandardError = null StandardOutput=syslog StandardError=syslog SyslogIdentifier=qgis-server-python WorkingDirectory=/tmp Restart = always
Systemd
# Environment Environment=QGIS_SERVER_PORT=809%i Environment="QGIS_AUTH_DB_DIR_PATH=/qgis-server/projects" Environment="QGIS_SERVER_LOG_FILE=/qgis-server/logs/qgis-server-python.log" Environment="QGIS_SERVER_LOG_LEVEL=0" Environment="QGIS_DEBUG=1" # Temporary workaround for #18230 Environment="QGIS_PREFIX_PATH=/usr" Environment="DISPLAY=:99" Environment="QGIS_PLUGINPATH=/qgis-server/plugins" Environment="QGIS_OPTIONS_PATH=/qgis-server" Environment="QGIS_CUSTOM_CONFIG_PATH=/qgis-server" [Install] WantedBy = multi-user.target
A QGIS Server instance caches:
Caches are not shared among instances.
Layers are not cached.
Caching is generally delegated to different tier, caching solutions are expecially recommended for serving tiles:
Look for metatiles support if your layers contain labels.
The Python QGIS tests contain a comprehensive set of scripts to test all possible services of QGIS Server:
QGIS authentication DB qgis-auth.db path can be specified with the environment variable QGIS_AUTH_DB_DIR_PATH
QGIS_AUTH_PASSWORD_FILE environment variable can contain the master password required to decrypt the authentication DB.
Note: ensure to limit the file as only readable by the Server’s process user and to not store the file within web-accessible directories.
QGIS_SERVER_PARALLEL_RENDERING
Activates parallel rendering for WMS GetMap requests. It’s disabled (false) by default. Available values are:
0 or false (case insensitive) 1 or true (case insensitive)
QGIS_SERVER_MAX_THREADS
Number of threads to use when parallel rendering is activated. Default value is -1 to use the number of processor cores.
QGIS_SERVER_LOG_FILE
Specify path and filename. Make sure that server has proper permissions for writing to file. File should be created automatically, just send some requests to server. If it’s not there, check permissions.
QGIS_SERVER_LOG_LEVEL
Specify desired log level. Available values are:
0 or INFO (log all requests) 1 or WARNING 2 or CRITICAL (log just critical errors, suitable for production purposes)
LTR: 12 months support
https://www.qgis.org/it/site/getinvolved/development/roadmap.html#release-schedule
Space | Forward |
---|---|
Right, Down, Page Down | Next slide |
Left, Up, Page Up | Previous slide |
G | Go to slide number |
P | Open presenter console |
H | Toggle this help |