Set Up OpenStreetMap (OSM) Tile Server on Debian 12 Bookworm

OpenStreetMap (OSM) is a user-contributed, freely-editable world map. You can think of it as an open-source and self-hosted alternative to Google Maps. This tutorial will show you how to build your own OpenStreetMap tile server on Debian 12 so you don’t have to use a proprietary map service.

OpenStreetMap Features

  • OpenStreetMap data covers the whole world, making it easy to support users in any country or every country.
  • OpenStreetMap is updated every minute of every hour of every day, and these updates are available to you in real-time.
  • OpenStreetMap data is free and open – there is no subscription fee and no page-view fee.
  • OpenStreetMap data is rich and detailed, containing huge amounts of data that is relevant to people on the ground – the people who collected it.

Prerequisites/Hardware Requirements

The required RAM and disk space depend on which country’s map you are going to use. For example,

  • The UK map requires at least 12G RAM and 100GB disk space.
  • The whole planet map requires at least 32G RAM and 1TB SSD (Solid State Drive). It’s not viable to use a spinning hard disk for the whole planet map.

You will need more disk space if you are going to pre-render tiles to speed up map loading in the web browser, which is highly recommended. Check this tile disk usage page to see how much disk space are required for pre-rendering tiles. For example, if you are going to pre-render tiles from zoom level 0 to zoom level 15 for the planet map, an extra 460 GB disk space is required.

Another thing to note is that importing large map data, like the whole planet, to PostgreSQL database takes a long time. Consider adding more RAM and especially using SSD instead of spinning hard disk to speed up the import process.

If you are going to host the entire world map, I recommend you buy the extra-large VPS from Contabo, which boasts

  • A 10 core CPU
  • 60 GB RAM
  • 1.6 TB Intel Optane SSD

It costs just 26.99 €/month.

Step 1: Upgrade Software

It’s always a good practice to update server software before doing any major work on your server. Log into your server via SSH and run the following command.

sudo apt update; sudo apt upgrade

If you encounter the following errors,

perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LANGUAGE = (unset),
	LC_ALL = (unset),
	LC_MONETARY = "zh_CN.UTF-8",
	LC_ADDRESS = "zh_CN.UTF-8",
	LC_TELEPHONE = "zh_CN.UTF-8",
	LC_NAME = "zh_CN.UTF-8",
	LC_MEASUREMENT = "zh_CN.UTF-8",
	LC_IDENTIFICATION = "zh_CN.UTF-8",
	LC_NUMERIC = "zh_CN.UTF-8",
	LC_PAPER = "zh_CN.UTF-8",
	LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").

That means your local computer is trying to send the locale environment variable to the debian VPS, but Debian doesn’t have the locale installed. To fix this, edit the SSH daemon configuration file.

sudo nano /etc/ssh/sshd_config

Scroll down to the end, you will find the following line, which tells SSH daemon to accept environment variables from the SSH client.

AcceptEnv LANG LC_*

Change it to the following, so SSH daemon won’t accept environment variables.

AcceptEnv no

Save and close the file. Then restart SSH daemon.

sudo systemctl restart ssh

Log out and log back in. You won’t see the locale error anymore.

Step 2: Install PostgreSQL Database Server and the PostGIS Extension

We will use PostgreSQL to store map data. The PostgreSQL team always strives to make performance improvements with every new version. Run the following 4 commands to install the latest version of PostgreSQL.

echo "deb [signed-by=/etc/apt/keyrings/postgresql.asc] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list

sudo mkdir -p /etc/apt/keyrings/

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/keyrings/postgresql.asc

sudo apt update

sudo apt install -y postgresql postgresql-contrib postgresql-15 postgresql-client-15

Then install PostGIS, which is a geospatial extension to PostgreSQL.

sudo apt install postgis postgresql-15-postgis-3

PostgreSQL database server will automatically start and listens on 127.0.0.1:5432. The postgres user will be created on the OS during the installation process. It’s the super user for PostgreSQL database server. By default, this user has no password and there’s no need to set one because you can use sudo to switch to the postgres user and log into PostgreSQL server.

sudo -u postgres -i

Now you can create a PostgreSQL database user osm.

createuser osm

Then create a database named gis and at the same time make osm as the owner of the database. Please don’t change the database name. Other tools like Renderd and Mapnik assume there’s a database named gis.

createdb -E UTF8 -O osm gis

Next, create the postgis and hstore extension for the gis database.

psql -c "CREATE EXTENSION postgis;" -d gis

psql -c "CREATE EXTENSION hstore;" -d gis

Set osm as the table owner.

psql -c "ALTER TABLE spatial_ref_sys OWNER TO osm;" -d gis

Exit from the postgres user.

exit

Create osm user on your operating system so the tile server can run as osm user. The following command will create a system user without password.

sudo adduser --system --group --home /home/osm/ osm

Step 3: Download Map Stylesheet and Map Data

Change to osm’s home directory.

cd /home/osm/

Grant permissions to your user account with the following command. Replace username with your real username.

sudo apt install acl
sudo setfacl -R -m u:username:rwx /home/osm/

Download the latest CartoCSS map stylesheets to the osm user’s home directory with git.

sudo apt install git

git clone https://github.com/gravitystorm/openstreetmap-carto.git

Then run one of the following commands to download the map data in PBF (ProtoBufBinary) format.

Britain and Ireland (1.7G)

wget -c http://download.geofabrik.de/europe/britain-and-ireland-latest.osm.pbf

Europe (25.8G)

wget -c http://download.geofabrik.de/europe-latest.osm.pbf

North America (11.8G)

wget -c http://download.geofabrik.de/north-america-latest.osm.pbf

South America (2.9G)

wget -c http://download.geofabrik.de/south-america-latest.osm.pbf

Central America (570MB)

wget -c http://download.geofabrik.de/central-america-latest.osm.pbf

Asia (11.2G)

wget -c http://download.geofabrik.de/asia-latest.osm.pbf

Africa (5.5G)

wget -c http://download.geofabrik.de/africa-latest.osm.pbf

Whole planet (66G). Note: I recommend only downloading the whole plant map when you really need to display the map of the whole world, or you will waste time waiting for the tile server to process unnecessary data.

wget -c http://planet.openstreetmap.org/pbf/planet-latest.osm.pbf

or

wget -c https://download.bbbike.org/osm/planet/planet-latest.osm.pbf

If you want other map of individual country/state/province/city, go to http://download.geofabrik.de. Also, BBBike.org provides extracts of more than 200 cities and regions worldwide in different formats.

Step 4: Optimize PostgreSQL Server Performance

The import process can take some time. To speed up this process, we can tune some PostgreSQL server settings to improve performance. Edit PostgreSQL main configuration file.

sudo nano /etc/postgresql/15/main/postgresql.conf

First, we should change the value of shared_buffer. The default setting is:

shared_buffers = 128MB

This is too small. The rule of thumb is to set it to 25% of your total RAM (excluding swap space). For example, my VPS has 60G RAM, so I set it to:

shared_buffers = 15GB

Find the following line.

#work_mem = 4MB
#maintenance_work_mem = 64MB

Again, the value is too small. I use the following settings.

work_mem = 1GB
maintenance_work_mem = 8GB

Then find the following line.

#effective_cache_size = 4GB

If you have lots of RAM like I do, you can set a higher value for the effective_cache_size like 20G.

effective_cache_size = 20GB

Save and close the file. Restart PostgreSQL for the changes to take effect.

sudo systemctl restart postgresql

By default, PostgreSQL would try to use huge pages in RAM. However, Linux by default does not allocate huge pages. Check the process ID of PostgreSQL.

sudo head -1 /var/lib/postgresql/15/main/postmaster.pid

Sample output:

7031

Then check the VmPeak value of this process ID.

grep ^VmPeak /proc/7031/status

Sample output:

VmPeak: 16282784 kB

This is the peak memory size that will be used by PostgreSQL. Now check the size of huge page in Linux.

cat /proc/meminfo | grep -i huge

Sample output:

AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB

We can calculate how many huge pages we need. Divide the VmPeak value by the size of huge page: 16282784 kB / 2048 kB = 7950. Then we need to edit the sysctl files to change Linux kernel parameters. Instead of editing the /etc/sysctl.conf file, we create a custom config file, so your custom configurations won’t be overwritten when upgrading software packages.

sudo touch /etc/sysctl.d/60-custom.conf

Then run the following command to allocate 7950 huge pages.

echo "vm.nr_hugepages = 7950" | sudo tee -a /etc/sysctl.d/60-custom.conf

Save and close the file. Apply the changes.

sudo sysctl -p /etc/sysctl.d/60-custom.conf

If you check the meminfo again,

cat /proc/meminfo | grep -i huge

We can see there are 7950 huge pages available.

AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:    7950
HugePages_Free:     7950
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:        16281600 kB

Restart PostgreSQL to use huge pages.

sudo systemctl restart postgresql

Use Screen on Remote Servers

Since the import process can take a long time and your computer might be disconnected from Internet, it’s recommended to use the screen utility to keep your session alive. Install screen on the Debian 12 server:

sudo apt install screen

Then start screen:

screen

Upon first launch, you will see an introduction text, simply press Enter to end. Then you will be able to run commands as usual.

Step 5: Import the Map Data to PostgreSQL

To import map data, we need to install osm2pgsql which converts OpenStreetMap data to postGIS-enabled PostgreSQL databases.

sudo apt install osm2pgsql

Grant permissions to the postgres user.

sudo setfacl -R -m u:postgres:rwx /home/osm/

Switch to the postgres user.

sudo -u postgres -i

Run the following command to load map stylesheet and map data into the gis database. Replace great-britain-latest.osm.pbf with your own map data file.

osm2pgsql --slim -d gis --hstore --multi-geometry --number-processes 10 --tag-transform-script /home/osm/openstreetmap-carto/openstreetmap-carto.lua --style /home/osm/openstreetmap-carto/openstreetmap-carto.style -C 32000 /home/osm/great-britain-latest.osm.pbf

where

  • --slim: run in slim mode rather than normal mode. This option is needed if you want to update the map data using OSM change files (OSC) in the future.
  • -d gis: select database.
  • --hstore: add tags without column to an additional hstore (key/value) column to PostgreSQL tables
  • --multi-geometry: generate multi-geometry features in postgresql tables.
  • --style: specify the location of style file
  • --number-processes: number of CPU cores on your server. I have 10.
  • -C flag specifies the cache size in MegaBytes. It should be around 70% of the free RAM on your machine. Bigger cache size results in faster import speed. For example, my server has 60GB free RAM, so I can specify -C 32000. Be aware that PostgreSQL will need RAM for shared_buffers. Use this formula to calculate how big the cache size should be: (Total RAM - PostgreSQL shared_buffers) * 70%
  • Finally, you need to specify the location of map data file.

Command Output:

openstreetmap-osm2pgsql-import-map-data

If you are going to import the full planet map data, then use the --drop option and the --flat-nodes option to increase the import speed. Note that the --flat-nodes option isn’t suitable for small maps.

osm2pgsql --slim -d gis --drop --flat-nodes /home/osm/nodes.cache --hstore --multi-geometry --number-processes 10 --tag-transform-script /home/osm/openstreetmap-carto/openstreetmap-carto.lua --style /home/osm/openstreetmap-carto/openstreetmap-carto.style -C 32000 /home/osm/planet-latest.osm.pbf

RAM usage will gradually increase during the importing process.

Now you probably don’t need to do other things on your server. Since you are using Screen, you can press Ctrl+A, release those keys, and then press D key to detach from the current Screen session. You will see a message like below.

[detached from 32113.pts-1.buster]

This tells me that the previous Screen session ID is 32113. You can log out from the SSH session and even shut down your computer. Don’t worry, the OSM import process is still running. When you need to come back and check the import progress, SSH into your server and run the following command to get the previous Screen Session ID.

screen -ls

Sample output:

There is a screen on:
	32113.pts-1.buster	(05/19/2020 03:45:29 PM)	(Detached)
1 Socket in /run/screen/S-linuxbabe.

Then you can re-attach to the previous Screen session.

screen -r 32113

And you will be able to continue your work. Once the import is complete, grant all privileges of the gis database to the osm user.

psql -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO osm;" -d gis

Exit from the postgres user.

exit

Note: If the osm2pgsql import isn’t finished yet, please don’t continue with step 6.

Step 6: Install Renderd and mod_tile

  • renderd is a daemon for rendering OpenStreetMap tiles from the PostgreSQL database.
  • mod_tile is an Apache module that is used to serve tiles to clients (e.g. web browsers)

We can install them from the default Debian 12 software repository.

sudo apt install apache2 libapache2-mod-tile renderd

A config file for renderd will be created at /etc/apache2/conf-available/renderd.conf. Enable the tile module.

sudo a2enmod tile

Next, create a virtual host for the tile server.

sudo nano /etc/apache2/sites-available/tileserver_site.conf

Add the following lines in this file. Replace tile.your-domain.com with your real domain name. Don’t forget to DNS A record.

<VirtualHost *:80>
    ServerName tile.your-domain.com   
    DocumentRoot /var/www/
    LogLevel info
 
    <Directory /var/cache/renderd/tiles>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Require all granted

        ModTileTileDir /var/cache/renderd/tiles
        LoadTileConfigFile /etc/renderd.conf
        ModTileEnableStats On
        ModTileBulkMode Off
        ModTileRequestTimeout 3
        ModTileMissingRequestTimeout 10
        ModTileMaxLoadOld 2
        ModTileMaxLoadMissing 5
        ModTileRenderdSocketName /run/renderd/renderd.sock
        ModTileCacheDurationMax 604800
        ModTileCacheDurationDirty 900
        ModTileCacheDurationMinimum 10800
        ModTileCacheDurationMediumZoom 13 86400
        ModTileCacheDurationLowZoom 9 518400
        ModTileCacheLastModifiedFactor 0.20
        ModTileEnableTileThrottling Off
        ModTileEnableTileThrottlingXForward 0
        ModTileThrottlingTiles 10000 1
        ModTileThrottlingRenders 128 0.2
    </Directory>

</VirtualHost>

Save and close the file. Enable this virtual host.

sudo a2ensite tileserver_site.conf

Restart Apache for the changes to take effect.

sudo systemctl restart apache2

The render daemon will automatically start, as can be seen with:

systemctl status renderd

Step 7: Generate Mapnik Stylesheet

Install the required packages.

sudo apt install curl unzip gdal-bin mapnik-utils libmapnik-dev python3-pip nodejs npm

Then install the carto package with npm.

sudo npm install -g carto

Install the yaml andpsycopg2 Python module.

sudo apt install python3-pretty-yaml python3-yaml python3-psycopg2

Switch to the postgres user.

sudo -u postgres -i

Cd into the carto style directory.

cd /home/osm/openstreetmap-carto/

Get shapefiles.

scripts/get-external-data.py

debian-osm-Generate-Mapnik-Stylesheet

If you encounter the following error message while running the above command, then you have DNS issues. Simply wait for several minutes and run the Python script again.

Failed to establish a new connection: [Errno -3] Temporary failure in name resolution

Now build the Mapnik XML stylesheet with the carto map stylesheet compiler.

carto project.mml > style.xml

Grant all privileges of the gis database to the osm user.

psql -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO osm;" -d gis

Exit from the postgres user.

exit

Step 8: Install Fonts

You need to install the fonts-dejavu package.

sudo apt install fonts-dejavu fonts-dejavu-web

To display non-Latin characters, install the following packages.

sudo apt install fonts-noto-cjk fonts-noto-cjk-extra fonts-noto-hinted fonts-noto-unhinted fonts-unifont

Step 9: Configure renderd

Edit renderd config file.

sudo nano /etc/renderd.conf

In the [renderd] section, change the number of threads according to the number of CPU cores on your server.

num_threads=10

Add a default layer. Lines beginning with semicolons (;) are comments.

; ADD YOUR LAYERS:
[default]
URI=/osm/
XML=/home/osm/openstreetmap-carto/style.xml
HOST=tile.your-domain.com

Configure renderd OSM

By default, renderd allows a max zoom level of 18. If you need zoom level 19, add the following line in the [default] section.

MAXZOOM=19

Save and close the file. Then create a new directory for the renderd service.

sudo mkdir /etc/systemd/system/renderd.service.d/

Create a custom config file under this directory.

sudo nano /etc/systemd/system/renderd.service.d/custom.conf

Add the following lines in this file.

[Service]
User=osm

Save and close the file. Change the ownership of /run/renderd/ and /var/cache/renderd/tiles/ directory.

sudo chown osm /run/renderd/ -R
sudo chown osm /var/cache/renderd/tiles/ -R

Then restart renderd service.

sudo systemctl daemon-reload

sudo systemctl restart renderd

You need to check the log of renderd.

sudo journalctl -eu renderd

Make sure renderd does not produce any error in the log after the restart, or the map won’t be displayed.

Step 10: Configure Apache

In your web browser address bar, type

tile.your-domain.com/osm/0/0/0.png

You should see the tile of the world map. Congrats! You just successfully built your own OSM tile server.

osm-tile-for-world-map

If you have enabled the UFW firewall, be sure to open port 80 and 443 with the following command.

sudo ufw allow 80,443/tcp

If you see the 404 not found error, simply wait a few minutes, refresh the page in your browser and it should be able to load the tile of world map. If it still won’t load, then restart renderd service (sudo systemctl restart renderd).

Step 11: Display Your Tiled Web Map

Tiled web map is also known as slippy map in OpenStreetMap terminology. There are two free and open-source JavaScript map libraries you can use for your tile server: OpenLayer and Leaflet. The advantage of Leaflet is that it is simple to use and your map will be mobile-friendly.

OpenLayer

To display your slippy map with OpenLayer, download JavaScript and CSS from openlayer.org and extract it to the webroot folder.

cd /var/www/

sudo wget https://github.com/openlayers/openlayers/releases/download/v5.3.0/v5.3.0.zip

sudo unzip v5.3.0.zip

Next, create the index.html file.

sudo nano /var/www/index.html

Paste the following HTML code in the file. Replace red-colored text and adjust the longitude, latitude and zoom level according to your needs.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Accessible Map</title>
<link rel="stylesheet" href="http://tile.your-domain.com/v5.3.0/css/ol.css" type="text/css">
<script src="http://tile.your-domain.com/v5.3.0/build/ol.js"></script>
<style>
  a.skiplink {
    position: absolute;
    clip: rect(1px, 1px, 1px, 1px);
    padding: 0;
    border: 0;
    height: 1px;
    width: 1px;
    overflow: hidden;
  }
  a.skiplink:focus {
    clip: auto;
    height: auto;
    width: auto;
    background-color: #fff;
    padding: 0.3em;
  }
  #map:focus {
    outline: #4A74A8 solid 0.15em;
  }
</style>
</head>
<body>
  <a class="skiplink" href="#map">Go to map</a>
  <div id="map" class="map" tabindex="0"></div>
  <button id="zoom-out">Zoom out</button>
  <button id="zoom-in">Zoom in</button>
  <script>
    var map = new ol.Map({
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM({
             url: 'http://tile.your-domain.com/osm/{z}/{x}/{y}.png'
          })
       })
     ],
     target: 'map',
     controls: ol.control.defaults({
        attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
          collapsible: false
        })
     }),
    view: new ol.View({
       center: [244780.24508882355, 7386452.183179816],
       zoom:5
    })
 });

  document.getElementById('zoom-out').onclick = function() {
    var view = map.getView();
    var zoom = view.getZoom();
    view.setZoom(zoom - 1);
  };

  document.getElementById('zoom-in').onclick = function() {
     var view = map.getView();
     var zoom = view.getZoom();
     view.setZoom(zoom + 1);
  };
</script>
</body>
</html>

Save and close the file. Now you can view your slippy map by typing your sub-domain in the browser address bar.

tile.your-domain.com

or

tile.your-domain.com/index.html

Leaflet

To display your slippy map with Leftlet, download JavaScript and CSS from leftletjs.com and extract it to the webroot folder.

cd /var/www/html/

sudo wget http://cdn.leafletjs.com/leaflet/v1.9.4/leaflet.zip

sudo unzip leaflet.zip

Next, create the index.html file.

sudo nano /var/www/index.html

Paste the following HTML code in the file. Replace red-colored text and adjust the longitude, latitude and zoom level according to your needs.

<html>
<head>
<meta charset="UTF-8">
<title>My first osm</title>
<link rel="stylesheet" type="text/css" href="leaflet.css"/>
<script type="text/javascript" src="leaflet.js"></script>
<style>
   #map{width:100%;height:100%}
</style>
</head>

<body>
  <div id="map"></div>
  <script>
    var map = L.map('map').setView([55,0.8],6);
    L.tileLayer('http://tile.your-domain.com/osm/{z}/{x}/{y}.png',{maxZoom:18}).addTo(map);
</script>
</body>
</html>

Save and close the file. Now you can view your slippy map by typing your server IP address in browser.

tile.your-domain.com

or

tile.your-domain.com/index.html

openstreetmap tile server setup

Step 12: Pre-render Tiles

Rendering tiles on-the-fly will increase the map loading time in web browser. To pre-render tiles instead of rendering on the fly, use the following render_list command. Use -z and -Z flag specify the zoom level and replace the number of threads according to the number of CPU cores on your server. Render_list renders a list of map tiles by sending requests to the rendering daemon. Pre-rendered tiles will be cached in /var/lib/mod_tile directory.

render_list -m default -a -z 0 -Z 19 --num-threads=10

If later you updated the map data, you can pre-render all tiles again by using the --force option.

render_list -m default -a -z 0 -Z 19 --num-threads=10 --force

To render map tiles in the background, add the & symbol at the end.

render_list -m default -a -z 0 -Z 19 --num-threads=10 &

Now you can close the terminal window. To check the rendering progress, open another SSH session, and run the following command.

sudo journalctl -eu renderd

The above command will show the latest log of the renderd service. The following lines show that my OSM server is now rendering map tiles at zoom level 12.

 renderd[20838]: DEBUG: START TILE default 12 1008-1015 4056-4063, new metatile
 renderd[20838]: Rendering projected coordinates 12 1008 4056 -> -10175297.205328|-19724422.274944 -10097025.688364|-19646150.757980 to a 8 x 8 tile
 renderd[20838]: DEBUG: DONE TILE default 12 1008-1015 3984-3991 in 0.799 seconds
 renderd[20838]: DEBUG: Sending render cmd(3 default 12/1008/3984) with protocol version 2 to fd 18
 renderd[20838]: DEBUG: Got incoming request with protocol version 2
 renderd[20838]: DEBUG: Got command RenderBulk fd(18) xml(default), z(12), x(1008), y(4064), mime(image/png), options()
 renderd[20838]: DEBUG: START TILE default 12 1008-1015 4064-4071, new metatile
 renderd[20838]: Rendering projected coordinates 12 1008 4064 -> -10175297.205328|-19802693.791908 -10097025.688364|-19724422.274944 to a 8 x 8 tile

Step 13: Enable HTTPS

To encrypt HTTP traffic, we can obtain and install a free TLS certificate from Let’s Encrypt. First, install the Let’s Encrypt client (certbot) on Debian 12.

sudo apt install certbot

Since we are using Apache web server, we also need to install the Apache plugin.

sudo apt install python3-certbot-apache

Then run the following command to obtain and install TLS certificate.

sudo certbot --apache --agree-tos --redirect --hsts --staple-ocsp --must-staple --email [email protected] -d tile.your-domain.com

Once the certificate is installed, refresh the web page and you will see a lock in the address bar.

sm-tile-server-ubuntu-20.04-install

If you see a yellow triangle in Firefox address bar, that means the tile URLs are still using HTTP. You need to edit the index.html file and replace all HTTP protocol with HTTPS with the following command.

sudo sed -i 's/http/https/g' /var/www/index.html

Step 14: Enable HTTP2

To further improve map loading performance, you can enable HTTP2 protocol. First, you need to enable the HTTP2 module.

sudo a2enmod http2

Then open the SSL virtual host file.

sudo nano /etc/apache2/sites-enabled/tileserver_site-le-ssl.conf

Put the following directive after the opening <VirtualHost *:443> tag.

Protocols h2 http/1.1

Save and close the file. Then restart Apache for the changes to take effect.

sudo systemctl restart apache2

Restrict Access to Your OSM Tile Server with HTTP Referrer Header

By default, anyone can use OpenLayer or Leaflet to create a slippy map with the URL of your tile server. To restrict access to your tile server, edit the Apache virtual host file.

sudo nano /etc/apache2/sites-enabled/tileserver_site-le-ssl.conf

Add the following lines in the <VirtualHost> tags.

    <Location /osm>
        SetEnvIf Referer example\.com trusted_referer
        Order deny,allow
        Deny from all
        Allow from env=trusted_referer
    </Location>

The above code checks if the HTTP referer header includes your own domain. If not, access to the /osm directory will be denied. The backslash is used to escape the dot character. To add multiple hostnames as trusted referrers, use the following syntax.

SetEnvIf Referer (example\.com|www\.example\.com|map\.example\.com) trusted_referer

Save and close the file. Then test the syntax.

sudo apache2ctl -t

If the syntax is Ok, reload Apache for the changes to take effect.

sudo systemctl reload apache2

Auto-Renew TLS Certificate

You can create Cron job to automatically renew TLS certificate. Simply open root user’s crontab file.

sudo crontab -e

Add the following line at the bottom of the file.

@daily certbot renew --quiet && systemctl reload apache2

PostgreSQL Database and Web Server on Different Hosts

If your PostgreSQL and Apache web server reside on different hosts, then you need to edit the project.mml file on the Apache host.

nano /home/osm/openstreetmap-carto-4.20.0/project.mml

Find the following lines:

osm2pgsql: &osm2pgsql
  type: "postgis"
  dbname: "gis"
  key_field: ""
  geometry_field: "way"
  extent: "-20037508,-20037508,20037508,20037508"

Specify the IP address of PostgreSQL database server.

osm2pgsql: &osm2pgsql
  type: "postgis"
  host: "10.0.0.2"
  dbname: "gis"
  key_field: ""
  geometry_field: "way"
  extent: "-20037508,-20037508,20037508,20037508"

Save and close the file. Then build the Mapnik XML stylesheet with the carto map stylesheet compiler.

carto project.mml > style.xml

On the PostgreSQL database server, edit the main configuration file.

sudo nano /etc/postgresql/11/main/postgresql.conf

Add the following line to set PostgreSQL to listen on all interfaces.

listen_addresses = '*'

Save and close the file. Then edit the PostgreSQL client authentication configuration file.

sudo nano /etc/postgresql/11/main/pg_hba.conf

Add the following line at the end of the file to allow the osm user to login from the Apache host. Replace 10.0.0.1 with the IP address of Apache host.

host   gis   osm   10.0.0.1/32   trust

Save and close the file. Then restart PostgreSQL.

sudo systemctl restart postgresql

Restart the render daemon on the Apache host.

sudo systemctl restart renderd

You need to check the log of renderd. Make sure renderd does not produce any error in the log, or the map won’t be displayed.

sudo journalctl -eu renderd

You should also restrict access to port 5432 of the PostgreSQL database server. For example, you can use the following UFW command to allow the IP address of Apache host only.

sudo ufw allow in from 10.0.0.1 to any port 5432

Next Step

I hope this tutorial helped you set up OpenStreetMap tile server on Debian 12.You may also want to set up Nominatim geocoding server to provide search functionality.

As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 5 Average: 5]

24 Responses to “Set Up OpenStreetMap (OSM) Tile Server on Debian 12 Bookworm

  • david knibb
    4 years ago

    Hi
    I said I’d report back. I followed your instructions and all went well until I got to

    osm2pgsql --slim -d gis --hstore --multi-geometry --number-processes 10 --tag-transform-script /home/osm/openstreetmap-carto/openstreetmap-carto.lua --style /home/osm/openstreetmap-carto/openstreetmap-carto.style -C 32000 /home/osm/great-britain-latest.osm.pbf
    

    postgres refused to connect. I tried different alternatives but always the same outcome – that is

    Osm2pgsql failed due to ERROR: Connection to database failed: could not connect to server: No such file or directory
    	Is the server running locally and accepting
    	connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
    

    Any ideas ? Thanks

    David

    • Xiao Guoan (Admin)
      4 years ago

      Check if PostgreSQL is listening on port 5432.

      sudo ss -lnpt | grep 5432

      The output should be like

      LISTEN    0     128       127.0.0.1:5432       0.0.0.0:*      users:(("postgres",pid=624,fd=5))                                              
      LISTEN    0     128           [::1]:5432          [::]:*      users:(("postgres",pid=624,fd=3))  
      

      If you don’t see anything in the output, then PostgreSQL is not running. Restart it.

      sudo systemctl restart postgresql
      • david knibb
        4 years ago

        Thank you – yes I had already done this. But postgressql is running anyway – – but the grep comand returns nothing.

        the code /etc/init.d/postgresql status

        confirms the fact that it is running. So somehow it must be on a different port.

        David

    • Xiao Guoan (Admin)
      4 years ago

      PostgreSQL listen on port 5432 by default. Run the following command to check what port is used by your PostgreSQL server.

      sudo ss -lnpt | grep postgres
  • david knibb
    4 years ago

    further progress – now completed stop 10.

    The only minor issue is that when I typed tile.localhost/osm/0/0/0.png

    I got server not found.

    so I left off the ’tile’ – and tried

    localhost/osm/0/0/0.png

    and it worked ! Great.

    Cup of coffee and I’ll try the rest.

  • david knibb
    4 years ago

    Brilliant – everything works – apart from the issues of ’tile’ in the web address.
    So thanks a million.
    If one wishes to add extra countries – I started as a test with a small one – Belgium – but now wish to add say the UK – then clealy it has to be downloaded and the Osm2pgsql needs to be run.
    Which other steps are essential ??
    Ta

    David

  • davidknibb
    4 years ago

    Now I’ve got the server working – thanks again – does any one know where to point me to take the next steps ?
    for example – I use qmapshack – so does anyone know how to set up the ‘tms’ file to incorporate the URL from the map server.
    I simply use ‘localhost’ to server the map tiles – but I’ve tried loads of variations in QMS and all I get is ‘x maps pending’ – just as in the openstreetmap situations.
    Where would you look in general to take the next steps ?

  • DavidKnibb
    4 years ago

    in the end I’ve answered my own question.
    firstly i removed slippymap.html in /var/www/osm (which links to local maps and mapnik world maps)
    then I used the leaflet.html example at switch2osm – and changed the url at L.tilelayer to my own local address
    Then the address to use in the tms file for qmapshack is
    http://localhost/osm/%1/%2/%3.png
    (just replace say OpenStreetMap.tms with your own version
    Hope this help.
    I’ll try it on MOBAC now

  • Hi,
    I’m a newbi in OSM stuffs. I followed this tutorial but got a 404 not found at the step 10.
    And this in error.log of apache2 :

    [Thu Jul 09 11:06:47.795124 2020] [tile:info] [pid 62456:tid 140448827950848] [client ::1:60660] tile_storage_hook: handler(tile_serve), uri(/osm/0/0/0.png)
    [Thu Jul 09 11:06:47.795280 2020] [tile:info] [pid 62456:tid 140448827950848] [client ::1:60660] Requesting style(default) z(0) x(0) y(0) from renderer with priority 5
    
    • I just removed ServerAlias, restarted Apache and now it works

  • david knibb
    4 years ago

    I’ve had the server running with the Uk for some time now. Yesterday I decided to expand it – and ran osm2pqsql with the brtain and ireland osmpbf. I expected that the map would serve both britain and ireland. but it still only server britain. I ran osm2pgsql with the –create option – and assumed all previous data would be cleared – but it obviously wasn’t. So after running osm2pgsql (step5) which of the steps 6 onwards need to be repeated ??
    Anyone got any ideas please ?
    Thanks

  • centos7
    3 years ago

    great, thanks, but how do I install this on Centos 7? seems to have problems with a lot of packages (renderd, mod_tile etc.)

  • Sebastian
    3 years ago

    Hello everyone,

    I have the same bug:
    dpkg-source:error :can’t build with source format ‘3.0(native)’:

    🙁

    Can anybody help?
    Thank you very much 🙂

    • Xiao Guoan (Admin)
      3 years ago

      I tested the instructions several times on new Debian 10 installs and it worked flawlessly every time. Follow step 6 to the letter and you should be fine. If you have doubts about the instructions, simply ask.

      • Sebastian
        3 years ago

        Hi Xiao,

        I found the bug…

        I replace thee line in the change log to
        libapache2-mod-tile (0.4-12~buster) precise; urgency=low

        I missed to replace the – to a .

        That was the problem 😉 Maybe this helps other people too. You could also mark it in color 😉

        Thank you for your tutorial (y)
        Sebastian

  • david knibb
    3 years ago

    I was about to reply Sebastian, but it looks as if you have already solved it.

    Once you’ve sorted these little issues – the system works well.

    David

  • Hello everyone !

    I want to thank you for your work !

    I’ve got an issue with the step 9, this is a picture :

    https://zupimages.net/viewer.php?id=20/44/83yw.jpg

    Tell me if you need more informations

    Léo

  • Kaushik Ray
    3 years ago

    Hello again Friend,

    Hope you are doing well, yet again another great source for information. I was trying to go through the tutorial and when I got to Step 6, I cloned mod_tile GIT repo but I don’t see a debian folder in it.

    I also checked in the GIT repo in github and same. Could you please see what i may be doing wrong or may be the repo got updated.

    Thank you
    Kaushik Ray

    • Roberto
      3 years ago

      Same problem here, did you find a solution?

      • Kaushik Ray
        3 years ago

        No I didn’t really try hard to find a solution to be honest. I moved to Ubuntu 18.04 and everything worked fine.

    • Roberto
      3 years ago

      Found a solution, change the repo to https://github.com/SomeoneElseOSM/mod_tile.git

      That’s all

  • Kaushik Ray
    3 years ago

    No I didn’t really try hard to find a solution to be honest. I moved to Ubuntu 18.04 and everything worked fine.

    • Roberto
      3 years ago

      I found a solution, change step 6 repo to https://github.com/SomeoneElseOSM/mod_tile.git

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here