Deploying StreetSign in Production

How to deploy a ‘production-ready’ StreetSign installation.

Dependencies

First, install the Python headers (for compiling some extra modules), ImageMagick (to generate thumbnails), make, and git (to download StreetSign).

On Debian/Ubuntu Server, this will be:

sudo apt-get install python3-dev make imagemagick git

On CentOS/RHEL 8+, this is:

sudo yum install python3-devel make ImageMagick git

Then install uv, which setup.sh uses to create the virtualenv and install Python dependencies:

curl -LsSf https://astral.sh/uv/install.sh | sh

User/Group

StreetSign, like every other service, should really run as its own user, for security’s sake:

sudo useradd streetsign

Which will also create a new group for it.

Installation path

Following the LSB, the best place for public-facing services to install their data is /srv/. Create that directory and install StreetSign there:

sudo mkdir /srv/streetsign
sudo chown -R streetsign:streetsign /srv/streetsign

Actually Installing it

Make sure uv and make are installed first (see Dependencies).

We’ll use git to clone the latest version and set it up:

cd /srv/streetsign
sudo su streetsign
git clone https://github.com/jamswat/streetsign.git .
./setup.sh

Set a secret key

Before running in production you must set a unique, random SECRET_KEY — the server refuses to start in production mode while it is left at the insecure default. Generate one:

python3 -c "import uuid; print(uuid.uuid4())"

and set it either in config.py:

SECRET_KEY = 'the-value-you-just-generated'

or via the environment (e.g. in the systemd unit or a .env file):

export SECRET_KEY='the-value-you-just-generated'

SECRET_KEY signs session cookies, so keep it secret and never commit it to a repository. It is not used for password hashing, so you can rotate it without affecting stored passwords.

Test that everything is ready

This step is optional, but probably a good idea. While still running as the streetsign user:

./run.py waitress

and then from a web browser, browse to the server’s IP on port 5000. If you don’t know the server’s IP:

ip -4 addr show

Note that servers often have a firewall (e.g. iptables, or similar) blocking port 5000.

Then exit from the streetsign user.

Configure StreetSign to start at boot

Unfortunately, this is different on practically every Linux distribution.

There are startup files in the StreetSign source, in the deployment folder.

systemd systems (Ubuntu 20.04+, CentOS/RHEL 8+, Debian 11+, etc)

On a systemd-based Linux distribution, copy the deployment/systemd/streetsign.service file to /etc/systemd/system, edit it to make sure it’s all correct for your system (which it should be, if you’ve followed the above instructions):

sudo cp /srv/streetsign/deployment/systemd/streetsign.service /etc/systemd/system/

Then enable the service:

sudo systemctl enable streetsign

Then start it up:

sudo systemctl start streetsign

If it starts without errors, you’re done. To verify that it starts on boot, feel free to reboot the server and see what happens.

Logs for StreetSign can be found with the usual systemd tools:

journalctl -u streetsign.service

Getting StreetSign onto Port 80

If StreetSign is going to be public-facing and you want it on the standard HTTP port 80 or over HTTPS, it’s best to run a reverse proxy in front of it.

In-process static file serving via WhiteNoise means nginx is not required for serving static assets — requests for static files should simply be proxied to the app alongside everything else. However, if you do serve static files directly through nginx, ensure the expires and alias directives match your deployment paths.

nginx

Install nginx:

sudo apt-get install nginx

Or on CentOS:

yum install nginx

Copy the basic StreetSign configuration file in:

sudo cp /srv/streetsign/deployment/nginx/streetsign /etc/nginx/sites-available/

on CentOS, copy it to /etc/nginx/conf.d/streetsign.conf:

sudo cp /srv/streetsign/deployment/nginx/streetsign /etc/nginx/conf.d/streetsign.conf

Edit it with whatever settings you wish.

The supplied configuration sets X-Forwarded-For and X-Forwarded-Proto. StreetSign ignores those headers unless TRUSTED_PROXY_HOPS is set to the number of proxies in front of it, so set TRUSTED_PROXY_HOPS = 1 in config.py (or the environment) when using this configuration.

Enable it (Debian only):

sudo ln -s /etc/nginx/sites-available/streetsign /etc/nginx/sites-enabled/

If StreetSign is the only thing you use nginx for and you don’t need the default welcome page, disable it:

sudo rm /etc/nginx/sites-enabled/default

Then restart nginx:

sudo systemctl restart nginx

Docker

Pre-built images are published to GitHub Container Registry on every tagged release — no local build required:

docker run -d --name streetsign -p 5000:5000 ghcr.io/jamswat/streetsign:1.5

Each release publishes several tags: the full version (1.5.0), the minor line (1.5), the major line (1), and latest (the newest release). Use 1.5 to get patch updates within the 1.5 series, or a full version such as 1.5.0 to pin exactly.

Or with docker-compose (pulls the image automatically):

docker compose up -d

See the README for Docker-specific configuration, volume mounts, and docker-compose usage.

CentOS notes (especially SELinux)

CentOS often has SELinux installed and locked down. You will probably need to allow httpd to make outgoing connections.

Run the following commands as root.

First, install semanage:

yum install policycoreutils-python

Then allow httpd outgoing network access (to the actual Python server):

/usr/sbin/setsebool httpd_can_network_connect 1

To make that permanent:

/usr/sbin/setsebool -P httpd_can_network_connect 1