Set Up OSM Nominatim Geocoding Server on Ubuntu 22.04

In a previous tutorial, I explained the process of building your own OSM tile server on Ubuntu 22.04. This tutorial is going to show you how to set up Nominatim Geocoding server on Ubuntu 22.04. Nominatim provides search functionality for OpenStreetMap, so if a visitor enters an address in a search box, the latitude/longitude location for that address will be returned.

Set Up OSM Nominatim Geocoding Server maplibre

Note: If you are going to set up Nominatim for the entire planet, then you should spin up another server for Nominatim, because it will also require 64GB RAM and 1TB SSD.

Step 1: Install and Configure PostgreSQL

Note: If OSM tile server and Nominatim are installed on the same server, then you can skip this step, because you have already done this when setting up the OSM tile server.

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

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

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

sudo apt install postgis postgresql-16-postgis-3

Then we need to tune PostgreSQL for maximal performance. Edit the main configuration file.

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

Find the following parameters in this file and use the following values.

shared_buffers = 15GB
work_mem = 1GB
maintenance_work_mem = 10GB
effective_cache_size = 24GB
synchronous_commit = off
max_wal_size = 1GB
checkpoint_timeout = 10min
checkpoint_completion_target = 0.9
fsync = off
full_page_writes = off

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

sudo systemctl restart postgresql

Note that you should turn on fsync and full_page_write after importing the OSM database, or you risk corrupting the database.

fsync = on
full_page_writes = on

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/16/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 Linux kernel parameters.

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

Add the following line to allocate 7950 huge pages.

vm.nr_hugepages = 7950

Save and close the file. Then 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

Restart PostgreSQL to use huge pages.

sudo systemctl restart postgresql

Step 2: Build Nominatim From Source

Install dependency packages to build Nominatim.

sudo apt update

sudo apt install build-essential cmake g++ libboost-dev libboost-system-dev libboost-filesystem-dev liblua5.4-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev php php-pgsql php-intl php-cgi phpunit php-codesniffer nlohmann-json3-dev python3-setuptools python3-dev python3-pip python3-psycopg2 python3-tidylib python3-behave python3-pytest php-cli python-babel-localedata python3-babel python3-datrie python3-jinja2 python3-markupsafe python3-psutil pylint git pandoc python3-argparse-manpage clang-tidy postgresql-server-dev-16

Create the nominatim user. (No need to create a password for this user.)

sudo useradd -d /srv/nominatim -s /bin/bash -m nominatim

Grant permissions to your own user account. Repalce username with your real username.

sudo apt install acl

sudo setfacl -R -m u:username:rwx /srv/nominatim/

Change to the /srv/nominatim/ directory.

cd /srv/nominatim/

Download Nominatim from the official website.

wget https://nominatim.org/release/Nominatim-4.3.1.tar.bz2

Extract the tarball.

tar xvf Nominatim-4.3.1.tar.bz2

Create the build directory.

mkdir build

Change to this directory and configure the build environment.

cd build

cmake /srv/nominatim/Nominatim-4.3.1

nominatim cmake

Compile the source code.

make

Build Nominatim From Source code

Install Nominatim.

sudo make install

install nominatim geocoder ubuntu 22.04

Step 3: Import OSM Database

Download Wikipedia importance dump file, which will improve the quality of the Nomiatim search results.

cd /srv/nominatim/build/

wget https://www.nominatim.org/data/wikimedia-importance.sql.gz

Download US and UK postcodes data.

wget https://www.nominatim.org/data/us_postcode_data.sql.gz

wget https://www.nominatim.org/data/gb_postcode_data.sql.gz

Download country code data file.

wget -O country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz

Then you need to download an OSM pbf file and import it to PostgreSQL. You can go to http://download.geofabrik.de to download the extract you need. You can also use the PBF file during the tile server setup process.

Install required Python modules.

sudo pip3 install python-dotenv sqlalchemy asyncpg

Create the www-data user in PostgreSQL, so the web server will have read-only access to the database.

sudo -u postgres -i createuser www-data

Grant permission to the postgres user.

sudo setfacl -R -m u:postgres:rwx /srv/nominatim/

Switch to the postgres user.

sudo -u postgres -i

And run the following command to import OSM extracts to PostgreSQL.

cd /srv/nominatim/build/

/usr/local/bin/nominatim import -j 6 --osm-file /path/to/the/map.osm.pbf 2>&1 | tee setup.log

It will automatically create the nominatim database in PostgreSQL and import OSM extracts with osm2pgsql.

Nominatim import speed for planet pbf on AMD EPYC 7282

After importing the database, the indexing process will begin. There are 30 ranks in total.

nominatim-indexing-process-20.04

Once it’s finished, run the following command to verify.

nominatim admin --check-database

nominatim admin --check-database

You might find the following nominatim commands useful. Details can be obtained from and manual (man nominatim).

  • nominatim freeze: make database read-only
  • nominatim replication: Update the database using an online replication service.
  • nominatim add-data: Add additional data from a file or an online source.
  • nominatim index: Reindex all new and modified data.
  • nominatim admin: Analyse and maintain the database.

Exit out of the postgres user.

exit

Step 4: Set Up Web Server

Apache

If Nominatim is installed on the OSM tile server, then edit the tile server configuration file.

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

Add the following lines between the VirtualHost tags.

<Directory "/srv/nominatim/build/website">
  Options FollowSymLinks MultiViews
  AddType application/json   .php
  DirectoryIndex search.php
  Require all granted
</Directory>

alias /nominatim /srv/nominatim/build/website

Save and close the file. Then reload Apache.

sudo systemctl reload apache2

If you are setting up Nominatim on a separate server, then you need to install Apache and PHP.

sudo apt install apache2 php8.1 libapache2-mod-php8.1 php-common php8.1-cli php8.1-common php8.1-opcache php8.1-readline

Create a virtual host for Nominatim.

sudo nano /etc/apache2/sites-enabled/nominatim.conf

Add the following lines in this file.

<VirtualHost *:80>
    ServerName nominatim.example.com

    DocumentRoot /srv/nominatim/build/website

    <Directory "/srv/nominatim/build/website">
          Options FollowSymLinks MultiViews
          AddType application/json   .php
          DirectoryIndex search.php
          Require all granted
   </Directory>

   alias /nominatim /srv/nominatim/build/website
   alias /.well-known /var/www/html/.well-known

    ErrorLog ${APACHE_LOG_DIR}/nominatim_error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/nominatim_access.log combined
</VirtualHost>

Save and close the file. Then restart Apache.

sudo systemctl restart apache2

Grant permission to the www-data user.

sudo setfacl -R -m u:www-data:rx /srv/nominatim/

sudo chown www-data:www-data /var/www/html/ -R

Step 5: Enabling HTTPS

To encrypt the HTTP traffic, we can enable HTTPS by installing a free TLS certificate issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client (certbot) on Ubuntu 22.04 server.

sudo apt install certbot python3-certbot-apache

And run this command to obtain and install TLS certificate.

sudo certbot --apache --agree-tos --redirect --hsts --uir --staple-ocsp --email [email protected] -d nominatim.example.com

Step 6: Update Nominatim Database

To keep the Nominatim database up to date, we need to install Pyosmium. It’s available from the default software repository, but it’s recommended to install the latest version using pip3.

sudo pip3 install osmium

This will install a binary /usr/local/bin/pyosmium-get-changes. Switch to the postgres user.

sudo -u postgres -i

Initialize the replication service.

cd /srv/nominatim/build/

nominatim replication --init

Sample output:

2022-08-14 10:27:32: Using project directory: /srv/nominatim/build
2022-08-14 10:27:32: Initialising replication updates
2022-08-14 10:27:46: Updates initialised at sequence 5178279 (2022-08-07 17:19:45+00:00)
2022-08-14 10:27:46: Create functions

Check for updates.

nominatim replication --check-for-updates

Sample output:

2022-08-14 10:31:07: Using project directory: /srv/nominatim/build
2022-08-14 10:31:09: New data available (5178279 => 5187674).

Update the database.

nominatim replication

Step 7: Set Up Cron Job For Automatic Update

Edit root user’s Crontab file.

sudo crontab -e

Add the following line in this file.

@daily sudo -u postgres -i /usr/local/bin/nominatim replication --project-dir /srv/nominatim/build/ > /dev/null

Save and close the file. If you don’t want to automatically update Nominatim database, simply remove the above line from your Crontab file.

How to Add Search Functionality to a Slippy Map

Maplibre

If you use Maplibre to display your map, then add the following lines in HTML header.

  <script src="https://unpkg.com/@maplibre/[email protected]/dist/maplibre-gl-geocoder.min.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/@maplibre/[email protected]/dist/maplibre-gl-geocoder.css" type="text/css" />

Then add the following code in the HTML body, above the </script> tag. Replace nominatim.example.com/nominatim with the URL of your own Nonimatim server.

var geocoder_api = {
    forwardGeocode: async (config) => {
        const features = [];
        try {
            let request =
                'https://nominatim.example.com/nominatim/search?q=' +
                config.query +
                '&format=geojson&polygon_geojson=1&addressdetails=1';
            const response = await fetch(request);
            const geojson = await response.json();
            for (let feature of geojson.features) {
                let center = [
                    feature.bbox[0] +
                    (feature.bbox[2] - feature.bbox[0]) / 2,
                    feature.bbox[1] +
                    (feature.bbox[3] - feature.bbox[1]) / 2
                ];
                let point = {
                    type: 'Feature',
                    geometry: {
                        type: 'Point',
                        coordinates: center
                    },
                    place_name: feature.properties.display_name,
                    properties: feature.properties,
                    text: feature.properties.display_name,
                    place_type: ['place'],
                    center: center
                };
                features.push(point);
            }
        } catch (e) {
            console.error(`Failed to forwardGeocode with error: ${e}`);
        }

        return {
            features: features
        };
    }
};
map.addControl(
    new MaplibreGeocoder(geocoder_api, {
        maplibregl: maplibregl
    })
);

Then reload your map in the web browser.

Set Up OSM Nominatim Geocoding Server maplibre

Troubleshooting

If the search functionality on your map doesn’t work, you can check the console of your web browser to find out what went wrong. Some folks may see the 406 not acceptable or a CORS not allowed error. Make sure you have set the correct MIME type for .php in the Apache configuration file. Some folks may have the following line, which can cause the above errors.

AddType text/html .php

It should be

AddType application/json .php

After changing the MIME type. Reload Apache for the changes to take effect.

sudo systemctl reload apache2

Check Apache status. Make sure it’s running.

sudo systemctl status apache2

How to Upgrade PostgreSQL Database Server

The following instructions show how to upgrade from PostgreSQL 14 to PostgreSQL 15 after it’s released.

When a new version of PostgreSQL comes out, you can upgrade to take advantage of performance improvements. Simply run the following command, and the apt package manager will install the latest version of PostgreSQL from the apt.postgresql.org repository.

sudo apt update; sudo apt upgrade -y

After that, you also need to upgrade existing PostgreSQL clusters. Pro Tip: You should open a GNU Screen session to prevent connection drop because the upgrade will take some time.

screen

Change to the /srv/nominatim/build directory.

cd /srv/nominatim/build/

Remove all files and folders under this directory.

sudo rm * -r

Remove the postgresql-server-dev-14 package.

sudo apt remove postgresql-server-dev-14

Install the postgresql-server-dev-15 package.

sudo apt remove postgresql-server-dev-15

Rebuild Nomiatim from source.

cmake /srv/nominatim/Nominatim-4.1.0

make

Then list PostgreSQL clusters.

sudo pg_lsclusters

Sample output:

Ver Cluster Port Status Owner    Data directory              Log file
14  main    5432 online postgres /var/lib/postgresql/12/main /var/log/postgresql/postgresql-12-main.log
15  main    5433 online postgres /var/lib/postgresql/14/main /var/log/postgresql/postgresql-14-main.log

As you can see, PostgreSQL 14 is using the default 5432 port. PostgreSQL 15 is using port 5433. Stop PostgreSQL server.

sudo systemctl stop postgresql

Let’s check the cluster status again with: sudo pg_lsclusters. They are all down.

Ver Cluster Port Status Owner    Data directory              Log file
14  main    5432 down   postgres /var/lib/postgresql/12/main /var/log/postgresql/postgresql-12-main.log
15  main    5433 down   postgres /var/lib/postgresql/14/main /var/log/postgresql/postgresql-14-main.log

Rename the cluster name of PostgreSQL 14 from main to latest_stable.

sudo pg_renamecluster 15 main latest_stable

Then we need to shrink the PostgreSQL shared_buffer.

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

Decrease the value to prevent out-of-memory problem during upgrade. For example, I reduce the value from 15GB to 5GB.

shared_buffers = 5GB

Save and close the file.

Next, upgrade the old PostgreSQL 14 cluster. This works by copying the databases from /var/lib/postgresql/14/main/ directory to the /var/lib/postgresql/15/main/ directory with pg_dump and pg_restore. Database configuration files will also be copied.

sudo pg_upgradecluster 14 main

nominatim upgrade postgresql

Start PostgreSQL server.

sudo systemctl start postgresql

Now check if your application is working. If it’s working well, then drop the old cluster.

sudo pg_dropcluster 14 main

Check cluster status again:

sudo pg_lsclusters

If the upgrade is successful, you can change the shared_buffer back to the original value in the /etc/postgresql/15/main/postgresql.conf file. Don’t forget to restart PostgreSQL.

Wrapping Up

I hope this tutorial helped you set up Nominatim geocoding server on Ubuntu 22.04. 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: 4 Average: 5]

12 Responses to “Set Up OSM Nominatim Geocoding Server on Ubuntu 22.04

  • Morning
    1 year ago

    I have built my own OpenStreetMap Tile following your tutorials. How to use my leaflet html to link nominatim? Could you give me some advice? Thanks a lot!

  • Gabriel
    1 year ago

    Hello ,

    The command : /usr/local/bin/nominatim import –osm-file /path/to/the/map.osm.pbf 2>&1 | tee setup.log give to me errors about env . Please help me to setup the enviroment .

  • Pranas
    1 year ago

    Thank you!

    • niclas
      1 year ago

      may be it is the same error as described below? See my Post to missing package python3-ico!

  • ondralohnisky
    1 year ago

    Hello, i followed all steps and everything works pretty well 😉
    But i can’t figure out how to integrate it with nginx configuration. This is where i am stucked like half day.
    Can anybody help me translate apache .conf to ngix .conf? Thanks a lot if anybody reply ^^
    I mean this:

    
      Options FollowSymLinks MultiViews
      AddType application/json   .php
      DirectoryIndex search.php
      Require all granted
    
    
    alias /nominatim /srv/nominatim/build/website
    
  • niclas
    1 year ago

    The import command

    /usr/local/bin/nominatim import --osm-file /home/weise/openmaptiles/data/austria.osm.pbf 2>&1 | tee setup.log

    throws following error:

    2023-01-1................2023-01-17 16:05:36: Setting up tokenizer' in 0s
    
    
    Traceback (most recent call last):
      File "/usr/local/bin/nominatim", line 14, in 
        exit(cli.nominatim(module_dir='/usr/local/lib/nominatim/module',
      File "/usr/local/lib/nominatim/lib-python/nominatim/cli.py", line 264, in nominatim
        return parser.run(**kwargs)
      File "/usr/local/lib/nominatim/lib-python/nominatim/cli.py", line 126, in run
        return args.command.run(args)
      File "/usr/local/lib/nominatim/lib-python/nominatim/clicmd/setup.py", line 116, in run
        tokenizer = self._get_tokenizer(args.continue_at, args.config)
      File "/usr/local/lib/nominatim/lib-python/nominatim/clicmd/setup.py", line 185, in _get_tokenizer
        return tokenizer_factory.create_tokenizer(config)
      File "/usr/local/lib/nominatim/lib-python/nominatim/tokenizer/factory.py", line 66, in create_tokenizer
        tokenizer_module = _import_tokenizer(module_name)
      File "/usr/local/lib/nominatim/lib-python/nominatim/tokenizer/factory.py", line 44, in _import_tokenizer
        return importlib.import_module('nominatim.tokenizer.' + name + '_tokenizer')
      File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "", line 1050, in _gcd_import
      File "", line 1027, in _find_and_load
      File "", line 1006, in _find_and_load_unlocked
      File "", line 688, in _load_unlocked
      File "", line 883, in exec_module
      File "", line 241, in _call_with_frames_removed
      File "/usr/local/lib/nominatim/lib-python/nominatim/tokenizer/icu_tokenizer.py", line 24, in 
        from nominatim.tokenizer.icu_rule_loader import ICURuleLoader
      File "/usr/local/lib/nominatim/lib-python/nominatim/tokenizer/icu_rule_loader.py", line 15, in 
        from icu import Transliterator
    

    It seems that a python-module python3-icu is missing. I have tried the command

    sudo apt-get install python3-icu

    and dropped the unfinished nominatim database with

    sudo -i -u postgres psql
    drop database nominatim;
    exit

    and started the import again (same command as above, altered for desired country).
    Conclusion:
    In Step 2 the package python3-ico is missing in the apt install command!

  • For the third time in a row I’m getting this error:

    
    root@vmi1046457:/srv/nominatim/build# /usr/local/bin/nominatim import --osm-file /root/openmaptiles/data/planet-latest.osm.pbf 2>&1 | tee setup.log
    2023-03-23 22:08:09: Using project directory: /srv/nominatim/build
    2023-03-23 22:08:12: Creating database
    2023-03-23 22:08:13: Setting up country tables
    2023-03-23 22:08:15: Importing OSM data file
    2023-03-23 22:08:15  osm2pgsql version 1.6.0
    2023-03-23 22:08:15  Database version: 15.1 (Ubuntu 15.1-1.pgdg22.04+1)
    2023-03-23 22:08:15  PostGIS version: 3.3
    2023-03-23 22:08:15  Parsing gazetteer style file '/usr/local/etc/nominatim/import-extratags.style'.
    NOTICE:  table "place" does not exist, skipping
    Processing: Node(209580k 545.8k/s) Way(0k 0.00k/s) Relation(0 0.0/s)
    Processing: Node(2126050k 518.3k/s) Way(0k 0.00k/s) Relation(0 0.0/s)Traceback (most recent call last):
      File "/usr/local/bin/nominatim", line 14, in 
        exit(cli.nominatim(module_dir='/usr/local/lib/nominatim/module',
      File "/usr/local/lib/nominatim/lib-python/nominatim/cli.py", line 264, in nominatim
        return parser.run(**kwargs)
      File "/usr/local/lib/nominatim/lib-python/nominatim/cli.py", line 126, in run
        return args.command.run(args)
      File "/usr/local/lib/nominatim/lib-python/nominatim/clicmd/setup.py", line 92, in run
        database_import.import_osm_data(files,
      File "/usr/local/lib/nominatim/lib-python/nominatim/tools/database_import.py", line 108, in import_osm_data
        run_osm2pgsql(options)
      File "/usr/local/lib/nominatim/lib-python/nominatim/tools/exec_utils.py", line 152, in run_osm2pgsql
        subprocess.run(cmd, cwd=options.get('cwd', '.'),
      File "/usr/lib/python3.10/subprocess.py", line 524, in run
        raise CalledProcessError(retcode, process.args,
    subprocess.CalledProcessError: Command '['/usr/local/lib/nominatim/osm2pgsql', '--hstore', '--latlon', '--slim', '--with-forward-dependencies', 'false', '--log-progress', 'true', '--number-processes', '1', '--cache', '32855', '--output', 'gazetteer', '--style', '/usr/local/etc/nominatim/import-extratags.style', '--create', '/root/openmaptiles/data/planet-latest.osm.pbf']' died with .
    root@vmi1046457:/srv/nominatim/build#
    
    

    What could be the causes? How to make it work?

  • Victor Barnieh
    11 months ago

    Hi I have followed your tutorial and the installation was perfect but at what point do you mkdir website? I did mine at end of the lesson that’s using the Apache2 configuration [(nominatim.conf) DocumentRoot /srv/nominatim/build/website] and my website folder is empty and can’t access the site. Please help. Thanks

  • you’re missing a

    python3-dotenv

    dependency

  • drebsdorf
    8 months ago

    Handsdown the best guide out there

    One small thing though, you want to run

    nominatim refresh –wiki-data –importance

    just before

    nominatim admin –check-database

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