HOWTO: Install OpenTopoMap on Ubuntu 24.04 LTS (Part 2)

This comprehensive guide walks you through the steps to serve your OpenTopoMap tiles via Apache and the renderd daemon. It assumes that your server is already set up for OpenTopoMap tile rendering.

The commands below were tested on Ubuntu 24.04 LTS with Apache 2.4, Mapnik 3.1 and the official mod_tile 0.8.1 release. The renderer account in this guide is gis. Substitute another account consistently if required.

Install the build dependencies

sudo apt update
sudo apt install +  git +  cmake +  build-essential +  apache2 +  apache2-dev +  libmapnik-dev +  libcairo2-dev +  libiniparser-dev +  libcurl4-openssl-dev +  libglib2.0-dev +  curl

The standalone curl package is required when running the mod_tile test suite. Installing the libcurl development package alone is not sufficient.

Compile and install mod_tile

Use the official openstreetmap/mod_tile repository. The old SomeoneElseOSM/mod_tile switch2osm branch, Autotools build and manual source patches are no longer needed.

mkdir -p ~/src

git clone +  --branch v0.8.1 +  --depth 1 +  https://github.com/openstreetmap/mod_tile.git +  ~/src/mod_tile

Git reports detached-HEAD state because v0.8.1 is a release tag. That is expected.

Use a logged screen session for the build:

screen -L +  -Logfile /home/gis/mod-tile-build.log +  -S mod-tile-build

Run inside the screen session:

set -euo pipefail

cmake +  -S /home/gis/src/mod_tile +  -B /home/gis/src/mod_tile-build +  -DCMAKE_BUILD_TYPE=Release +  -DCMAKE_INSTALL_PREFIX=/usr +  -DCMAKE_INSTALL_LOCALSTATEDIR=/var +  -DCMAKE_INSTALL_RUNSTATEDIR=/run +  -DCMAKE_INSTALL_SYSCONFDIR=/etc +  -DUSE_MEMCACHED=OFF +  -DUSE_RADOS=OFF +  -DENABLE_TESTS=ON

cmake +  --build /home/gis/src/mod_tile-build +  --parallel "$(nproc)"

ctest +  --test-dir /home/gis/src/mod_tile-build +  --output-on-failure

sudo cmake +  --install /home/gis/src/mod_tile-build +  --strip

Detach from screen with Ctrl-A, then D. On the tested server all 145 tests passed. The installation places the programs in /usr/bin, the Apache module in /usr/lib/apache2/modules, and the configuration in /etc.

renderd --version
command -v renderd
command -v render_list

ls -l +  /usr/bin/renderd +  /usr/bin/render_list +  /usr/lib/apache2/modules/mod_tile.so +  /etc/renderd.conf +  /etc/apache2/mods-available/tile.load

Create the renderd configuration

Back up the generated default and replace it:

sudo cp -a /etc/renderd.conf /etc/renderd.conf.install-default

sudo tee /etc/renderd.conf >/dev/null <<'EOF'
[renderd]
num_threads=4
pid_file=/run/renderd/renderd.pid
socketname=/run/renderd/renderd.sock
stats_file=/run/renderd/renderd.stats
tile_dir=/var/cache/renderd/tiles

[mapnik]
font_dir=/usr/share/fonts
font_dir_recurse=1
plugins_dir=/usr/lib/mapnik/3.1/input

[opentopomap]
URI=/tile/
TILEDIR=/var/cache/renderd/tiles
XML=/home/gis/OpenTopoMap/mapnik/opentopomap.xml
HOST=localhost
TILESIZE=256
MINZOOM=0
MAXZOOM=17
TYPE=png image/png png256
EOF

Important: the TYPE setting contains three fields: the filename extension, MIME type and Mapnik output format. With mod_tile 0.8.1, the incomplete line TYPE=png image/png caused Apache child processes to segfault. Use the complete line shown above, or omit TYPE and use the default.

Prepare the persistent cache and runtime directory:

sudo install +  -d +  -o gis +  -g www-data +  -m 2775 +  /var/cache/renderd +  /var/cache/renderd/tiles

sudo install +  -d +  -o gis +  -g www-data +  -m 0775 +  /run/renderd

Create the renderd systemd service

The CMake installation does not install a systemd unit. Create one explicitly:

sudo tee /etc/systemd/system/renderd.service >/dev/null <<'EOF'
[Unit]
Description=OpenTopoMap tile rendering daemon
After=network.target postgresql.service
Wants=postgresql.service

[Service]
Type=simple
User=gis
Group=www-data
WorkingDirectory=/home/gis/OpenTopoMap/mapnik
Environment=HOME=/home/gis
ExecStart=/usr/bin/renderd --foreground --config=/etc/renderd.conf
Restart=on-failure
RestartSec=5
RuntimeDirectory=renderd
RuntimeDirectoryMode=0775
UMask=0002
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

sudo systemd-analyze verify /etc/systemd/system/renderd.service
sudo systemctl daemon-reload
sudo systemctl enable --now renderd

Verify the service, socket and cache permissions:

sudo systemctl status renderd --no-pager -l

sudo journalctl +  -u renderd +  --since '5 minutes ago' +  --no-pager

ls -la /run/renderd
ls -ld /var/cache/renderd/tiles

A healthy installation reports renderd 0.8.1, Mapnik 3.1, four rendering threads and the opentopomap map. The socket /run/renderd/renderd.sock must be accessible to Apache.

Configure Apache to load mod_tile

The installation already provides /etc/apache2/mods-available/tile.load. Do not create a second LoadModule directive.

Create the site-wide mod_tile configuration:

sudo tee /etc/apache2/conf-available/opentopomap-tiles.conf >/dev/null <<'EOF'
<IfModule tile_module>
    ModTileTileDir /var/cache/renderd/tiles
    LoadTileConfigFile /etc/renderd.conf
    ModTileRenderdSocketName /run/renderd/renderd.sock

    ModTileEnableStats On
    ModTileBulkMode Off

    ModTileRequestTimeout 10
    ModTileMissingRequestTimeout 120

    ModTileMaxLoadOld 16
    ModTileMaxLoadMissing 50

    ModTileCacheDurationMax 604800
    ModTileCacheDurationDirty 900
    ModTileCacheDurationMinimum 10800
    ModTileCacheDurationMediumZoom 13 86400
    ModTileCacheDurationLowZoom 9 518400
    ModTileCacheLastModifiedFactor 0.20

    ModTileEnableTileThrottling On
    ModTileEnableTileThrottlingXForward 0
    ModTileThrottlingTiles 10000 1
    ModTileThrottlingRenders 128 0.2

    ModTileEnableStatusURL On
    ModTileEnableDirtyURL Off
</IfModule>
EOF

sudo a2enmod tile
sudo a2enconf opentopomap-tiles
sudo apache2ctl configtest
sudo systemctl restart apache2

A single full restart is sufficient. The old workaround that reloaded Apache twice is no longer required.

sudo systemctl status apache2 renderd --no-pager -l
apache2ctl -M 2>/dev/null | grep tile

Recover from an Apache crash loop

If Apache child processes start segfaulting after enabling mod_tile, stop testing requests and restore Apache first:

sudo a2disconf opentopomap-tiles
sudo a2dismod tile
sudo apache2ctl configtest
sudo systemctl restart apache2

Then check /etc/renderd.conf. In particular, verify that TYPE contains all three fields before re-enabling the module.

Test renderd directly

Render the known Zugspitze tile through renderd. This produces one 8×8 metatile containing 64 individual tiles.

screen -L +  -Logfile /home/gis/render-test-zugspitze.log +  -S render-test-zugspitze

Run inside screen:

set -euo pipefail
SECONDS=0

printf '8691 5734 14\n' |
  render_list +    --config=/etc/renderd.conf +    --map=opentopomap +    --force +    --num-threads=1

printf 'Elapsed: %d seconds\n' "$SECONDS"

Do not place Bash’s time keyword directly after the pipe. In that position Bash tries to run an external time command. On the tested server the metatile rendered in 6.38 seconds.

You can monitor renderd in another terminal:

sudo journalctl -u renderd -f

Mapnik messages about unsupported SVG attributes such as overflow and enable-background are nonfatal.

Test tile delivery through Apache

curl +  --max-time 30 +  --fail +  --show-error +  --silent +  --dump-header /tmp/opentopomap-tile.headers +  --output /tmp/opentopomap-zugspitze-z14.png +  http://127.0.0.1/tile/14/8691/5734.png

cat /tmp/opentopomap-tile.headers
file /tmp/opentopomap-zugspitze-z14.png
ls -l /tmp/opentopomap-zugspitze-z14.png

The tested request returned a valid 51,732-byte PNG. Tiles are exposed using this URL scheme:

http://<server>/tile/{z}/{x}/{y}.png

For example:

http://<server>/tile/14/8691/5734.png

Inspect the cached metatile and optional status endpoint:

find /var/cache/renderd/tiles/opentopomap +  -type f +  -printf '%s bytes  %p\n' |
  sort -nr |
  head -20

curl --max-time 10 --fail --show-error +  http://127.0.0.1/tile/14/8691/5734.png/status

Done

Apache now serves OpenTopoMap tiles generated on demand by renderd and cached as metatiles below /var/cache/renderd/tiles/opentopomap. The render daemon starts automatically with systemd. A browsable Leaflet front end and HTTPS can be added separately.