A traditional Terracotta deployment with Nginx and Gunicorn¶
This tutorial describes how to deploy Terracotta on a server running Ubunutu 18.04. For this we will use Gunicorn to spin up the WSGI instance and Nginx to proxy incoming requests. Systemd will take care of keeping the Gunicron running. To serve Terracotta from a Ubuntu VM we will need the following:
A server with Ubuntu 18.04 installed and a non-root user with sudo privileges
Install Anaconda, Terracotta, Nginx and Gunicorn
Some data to display
The username of the VM is assumed to be ubuntu
. The IP of the VM
will be used as the domain name (VM_IP
).
Installation¶
First we need a Ubuntu 18.04 VM (e.g. on Microsoft Azure) and install Anaconda on it. After installing Anaconda we can create a new conda environment and install Terracotta and Gunicorn:
$ conda create --name gunicorn
$ source activate ENVNAME
$ sudo apt install build-essential gdal-bin libgdal-dev
$ pip install cython
$ cd /path/to/terracotta
$ pip install -e .
$ pip install gunicorn
Additionally we will need to install Nginx:
$ sudo apt install nginx
Check if everything is running fine with:
$ sudo systemctl status nginx
If the status check went fine and the firewall is configured correctly, you should now be able to access the default nginx page via:
http://your_server_ip
For further instructions on how to initially set up Nginx check here.
Get data and optimize for Terracotta¶
Copy the rasters you want to serve to /mnt/data
, optimize them with
terracotta optimize-rasters
and create a database with
terracotta ingest
:
$ terracotta optimize-rasters /mnt/data/rasters/*.tif -o /mnt/data/optimized-rasters
$ terracotta ingest /mnt/data/optimized-rasters/{name}.tif -o /mnt/data/terracotta.sqlite
This will create the database at /mnt/data/terracotta.sqlite
which we
will need later. While this is running we can set up systemd and nginx
Systemd¶
Systemd will take care of starting and restarting the Gunicorn process.
For that we create a file /etc/systemd/system/terracotta.service
:
[Unit]
Description=Gunicorn instance to serve Terracotta
After=network.target
[Service]
User=sammy
Group=www-data
WorkingDirectory=/mnt/data
Environment="PATH=/home/ubuntu/anaconda3/envs/gunicorn/bin"
Environment="TC_DRIVER_PATH=/mnt/data/terracotta.sqlite"
ExecStart=/home/ubuntu/anaconda3/envs/gunicorn/bin/gunicorn \
--workers 3 --bind unix:terracotta.sock -m 007 terracotta.server.app:app
[Install]
WantedBy=multi-user.target
All necessary environment variables like TC_DRIVER_PATH
can be set
by adding multiple Environment
lines. ExecStart
contains the
Gunicorn command that starts the Terracotta instance. It consists of:
Absolute path to Gunicorn executable
Number of workers to spawn (2 * cores + 1 is recommended)
Binding to a unix socket file
terracotta.sock
in the working directoryDotted path to the WSGI entry point, which consists of the path to the python module containing the main Flask app and the app object:
terracotta.server.app:app
The service and be started/enabled/restarted with:
$ sudo systemctl start terracotta
$ sudo systemctl enable terracotta
$ sudo systemctl restart terracotta
Nginx¶
The Gunicorn server is now running and the we can configure Nginx to
forward requests to it. Create a file
/etc/ngix/sites-available/terrcotta
with the contents:
server {
listen 80;
server_name VM_IP;
location / {
include proxy_params;
proxy_pass http://unix:/mnt/data/terracotta.sock;
}
}
And link it to the sites-enabled folder and restart nginx and terracotta services.
$ sudo ln -s /etc/nginx/sites-available/terracotta /etc/nginx/sites-enabled/terracotta
$ sudo systemctl restart nginx
$ sudo systemctl restart terracotta
To check errors in the service and nginx files:
$ sudo nginx -t
This guide is adjusted from here.
Optional: SSL Encryption¶
One way to encrypt the traffic from and to Terracotta is to generate a self-signed certificate. This process is described in depth here. In this recipe only the main commands are quoted.
To create a self signed key/certificate pair run
$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt
and enter the requested information. We also create a Diffie-Hellman group with:
$ sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096
This takes several minutes.
Now we need two additional Nginx config files. The first one tells Nginx
where the key/certificate pair can be found and is placed at
/etc/nginx/snippets/self-signed.conf
:
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
The second one (/etc/nginx/snippets/ssl-params.conf
) contains some
SSL encryption settings:
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable strict transport security for now. You can uncomment the following
# line if you understand the implications.
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
With these in place we can update the Nginx config file. It essentially
just performs a redirect from port 80 to 443. The new config file
/etc/nginx/sites-available/terracotta
should look similar to this:
server {
listen 443 ssl;
listen [::]:443 ssl;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
server_name VM_IP;
location / {
include proxy_params;
proxy_pass http://unix:/mnt/data/terracotta.sock
}
}
server {
listen 80;
listen [::]:80;
server_name VM_IP;
return 301 https://$server_name$request_uri;
}
Finally check the syntax and restart Nginx.
$ sudo nginx -t
$ sudo systemctl restart nginx
The warning of the syntax check as well as when you access the server
for the first time via https://VM_IP
are expected because we are
using a self signed SSL certificate. The traffic is encrypted, the
certificate is just not signed by any of the trusted certificate
authorities.