This page shows how OpenStreetMap Carto can be used to implement a tile server using the same software adopted by OpenStreetMap. It includes step-by-step instructions to install an Ubuntu based Tile Server and is limited to describe some best practices, in the consideration that the main scope of this site is to provide tutorials to set-up a development environment of OpenStreetMap Carto and offer recommendations to edit the style.
The OSM Tile Server is a web server specialized in delivering raster maps, serving them as static tiles and able to perform rendering in real time or providing cached images. The adopted web software by OpenStreetMap is the Apache HTTP Server, together with a specific plugin named mod_tile and a related backend stack able to generate tiles at run time; programs and libraries are chained together to create the tile server.
As so often with OpenStreetMap, there are many ways to achieve a goal and nearly all of the components have alternatives that have various specific advantages and disadvantages. This tutorial describes the standard installation process of the OSM Tile Server used on OpenStreetMap.org.
It consists of the following main components:
All mentioned software is open-source.
For the tile server, a PostGIS database is required, storing geospatial features populated by osm2pgsql tool from OSM data. Also, a file system directory including the OSM.xml file, map symbols (check openstreetmap-carto/symbols subdirectory) and shapefiles (check openstreetmap-carto/data subdirectory) is needed. OSM.xml is preliminarily produced by a tool named carto from the openstreetmap-carto style (project.mml and all related CartoCSS files included in openstreetmap-carto).
When the Apache web server receives a request from the browser, it invokes the mod_tile plugin, which in turn checks if the tile has already been created (from a previous rendering) and cached, so that it is ready for use; in case, mod_tile immediately sends the tile back to the web server. Conversely, if the request needs to be rendered, then it is queued to the renderd backend, which is responsible to invoke Mapnik to perform the actual rendering; renderd is a daemon process included in the mod_tile sources and interconnected to mod_tile via UNIX queues. renderd is the standard backend currently used by www.openstreetmap.org, even if some OSM implementations use Tirex; Mapnik extracts data from the PostGIS database according to the openstreetmap-carto style information and dynamically renders the tile. renderd passes back the produced tile to the web server and in turn to the browser.
The renderd daemon implements a queuing mechanism with multiple priority levels to provide an as up-to-date viewing experience given the available rendering resources. The highest priority is for on -the fly rendering of tiles not yet in the tile cache, two priority levels for re-rendering out of date tiles on the fly and two background batch rendering queues. To avoid problems with directories becoming too large and to avoid too many tiny files, Mod_tile/renderd store the rendered tiles in “meta tiles”, in a special hashed directory structure.1
Even if the tileserver dynamically generates tiles at run time, they can also be pre-rendered for offline viewing with a specific tool named render_list, which is typically used to pre-render low zoom level tiles and takes significant time to accomplish the process (tens of hours in case the full planet is pre-rendered); this utility is included in mod_tile, as well as another tool named render_expired, which provides methods to allow expiring map tiles. More detailed description of render_list and render_expired can be found in their man pages.
A background on the tiles expiry method can be found at tiles expiry mechanism.
The overall process is here represented2.
client browser | ||||
Disk Cache (tiles) | Apache Web Server | Web page | ||
renderd | mod_tile | tiles | ||
Mapnik XML | Mapnik | |||
PostgreSQL PostGIS | shapefiles data directory |
An additional description of the rendering process of OpenStreetMap can be found at OSM architecture.
The following step-by-step procedure can be used to install and configure all the necessary software to operate your own OpenStreetMap tile server on Ubuntu.3
The goal for this procedure is to use Ubuntu packages and official PPAs whenever possible.
We consider using Ubuntu 20.04.2 LTS Focal Fossa, or 18.04 LTS Bionic Beaver, suggested operating system version.
Other tested O.S. include Ubuntu 16.04 LTS Xenial Xerus, Ubuntu 15.4 Vivid Vervet or Ubuntu 14.04.3 LTS Trusty Tahr (other versions should work). All should be 64-bit computing architecture. Other distributions like Debian might be checked, but could require changes to the installation procedure.
This procedure is updated to the version of OpenStreetMap Carto available at the time of writing. To get the correct installation procedure, the INSTALL history should be checked, considering that the OpenStreetMap Carto maintainers use to keep the INSTALL page updated. Check also the README changelog.
This procedure also supports WSL - Windows Subsystem for Linux. This means that a Windows 10 64-bit PC can be used to perform the installation, after setting-up WSL.
Make sure your Ubuntu system is fully up-to-date:
lsb_release -a
Previous command returns the Ubuntu version.
To update the system:
sudo apt-get update
sudo apt-get -y upgrade
If on a brand new system you also want to do sudo apt-get dist-upgrade && sudo shutdown -r now
.
sudo apt-get -y install ca-certificates gnupg curl unzip gdal-bin \
tar wget bzip2 build-essential clang python3-psycopg2 python3-yaml \
python3-requests postgresql-client
Optional elements:
sudo apt-get -y install munin-node munin protobuf-c-compiler libtiff5-dev
libcairomm-1.0-dev libagg-dev lua5.1 liblua5.1-0-dev
Check prerequisites suggested by openstreetmap-carto.
For the subsequent installation steps, we suppose that cd
defaults to your home directory.
Importing and managing map data takes a lot of RAM and a swap is generally needed.
To check whether a swap partition is already configured on your system, use one of the following two commands:
Reports the swap usage summary (no output means missing swap):
swapon -s
Display amount of free and used memory in the system (check the line specifying Swap):
free -h
If you do not have an active swap partition, especially if your physical memory is small, you should add a swap file. First we use fallocate
command to create a file. For example, create a file named swapfile with 2G capacity in root file system:
sudo fallocate -l 2G /swapfile
Then make sure only root can read and write to it.
sudo chmod 600 /swapfile
Format it to swap:
sudo mkswap /swapfile
Enable the swap file
sudo swapon /swapfile
The Operating System tuning adopted by the OpenStreetMap tile servers can be found in the related Chef configuration.
Run locale to list what locales are currently defined for the current user account:
locale
To set the en_GB locale:
export LANGUAGE=en_GB.UTF-8
export LANG=en_GB.UTF-8
export LC_ALL=en_GB.UTF-8
The exported variables can be put to the file /etc/environment
.
New locales can also be generated by issuing:
sudo locale-gen en_GB en_GB.UTF-8
sudo dpkg-reconfigure locales
We suppose that you have already created a login user during the installation of Ubuntu, to be used to run the tile server. Let’s suppose that your selected user name is tileserver. Within this document, all times tileserver is mentioned, change it with your actual user name.
If you need to create a new user:
sudo useradd -m tileserver
sudo passwd tileserver
Set a password when prompted.
Git might come already preinstalled sometimes.
git --version # to verify whether git is already installed
sudo apt-get install -y git
We need to install the Mapnik library. Mapnik is used to render the OpenStreetMap data into the tiles managed by the Apache web server through renderd and mod_tile.
With Ubuntu 20.04 LTS, go to mapnik installation.
With Ubuntu 18.04 LTS, which installs FreeType 2.8.1, skip this paragraph and continue with installing Mapnik.
Mapnik depends on FreeType for TrueType, Type 1, and OpenType font support. With Ubuntu 16.04 LTS, the installed version of FreeType is 2.6.1 which has the stem darkening turned on and this makes Noto CJK fonts bolder and over-emphasized. Installing a newer version of FreeType from a separate PPA, overriding the default one included in Ubuntu 16.04 LTS, solves this issue4:
echo "Old freetype version:"
dpkg -l|grep freetype6
sudo add-apt-repository -y ppa:no1wantdthisname/ppa
sudo apt-get update
sudo apt-get install -y libfreetype6 libfreetype6-dev
Check the updated freetype version:
echo "Updated freetype version:"
dpkg -l|grep freetype6
In case you need to downgrade the FreeType to the stock version in Ubuntu 16.04 repository, simply purge the PPA via ppa-purge:
sudo apt-get install ppa-purge && sudo ppa-purge ppa:no1wantdthisname/ppa
We report some alternative procedures to install Mapnik (in the consideration to run an updated version of Ubuntu).
With Ubuntu versions older than 18.04 LTS, the default Mapnik version is older than the minumum one required, which is 3.0.19. Anyway, a specific PPA made by talaj offers the packaged version 3.0.19 of Mapnik for Ubuntu 16.04 LTS Xenial.
sudo add-apt-repository -y ppa:talaj/osm-mapnik
sudo apt-get update
Ubuntu 18.04 LTS provides Mapnik 3.0.19 and does not need a specific PPA.
The following command installs Mapnik from the standard Ubuntu repository:
sudo apt-get install -y git autoconf libtool libxml2-dev libbz2-dev \
libgeos-dev libgeos++-dev libproj-dev gdal-bin libgdal-dev g++ \
libmapnik-dev mapnik-utils python3-mapnik
With Ubuntu 18.04 LTS, you might use python-mapnik instead of python3-mapnik.
Launchpad reports the Mapnik version installed from package depending on the operating system; the newer the OS, the higher the Mapnik release.
GitHub reports the ordered list of available versions for:
Version 3.0.19 is the minimum one suggested at the moment.5 If using the above mentioned PPA, that version comes installed instead of the default one available with Ubuntu.
After installing Mapnik from package, go to check Mapnik installation.
To install Mapnik from sources, follow the Mapnik installation page for Ubuntu.
First create a directory to load the sources:
mkdir -p ~/src ; cd ~/src
Note: if you get the following error: ++ compiler does not support C++14 standard (-std=c++14), which is required. Please upgrade your compiler
, use this explort instead of the one included in the linked documentation:
export CXX="clang++-10" && export CC="clang-10"
Refer to Mapnik Releases for the latest version and changelog.
Remove any other old Mapnik packages:
sudo apt-get purge -y libmapnik* mapnik-*
sudo apt-get purge -y python-mapnik
sudo apt-get purge -y python3-mapnik
sudo add-apt-repository --remove -y ppa:mapnik/nightly-trunk
sudo add-apt-repository --remove -y ppa:talaj/osm-mapnik
Install prerequisites:
sudo apt-get install -y libxml2-dev libfreetype6-dev \
libjpeg-dev libpng-dev libproj-dev libtiff-dev \
libcairo2 libcairo2-dev python-cairo python-cairo-dev \
libgdal-dev git
sudo apt-get install -y build-essential python-dev libbz2-dev libicu-dev
sudo apt-get install -y python zlib1g-dev clang make pkg-config curl
# you might have to update your outdated clang
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update -y
sudo apt-get install -y gcc-6 g++-6 clang-3.8
export CXX="clang++-10" && export CC="clang-10"
Check clang --version
and g++-6 --version
before upgrading the compiler. As mentioned, installing gcc-6 and clang-3.8 should only be done with Ubuntu 16.04, which by default comes with older versions (not with Ubuntu 18.04).
We need to install Boost either from package or from source.
Do not install boost from package if you plan to compile mapnik with an updated compiler. Compile instead boost with the same updated compiler.
sudo apt-get install -y libboost-all-dev
Remove a previous installation of boost from package:
sudo apt-get purge -y libboost-all-dev # remove installation from package
Download boost from source:
cd ~/src
wget https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2
tar xjf boost_1_66_0.tar.bz2
rm boost_1_66_0.tar.bz2
cd boost_1_66_0
Notice that boost and mapnik shall be compiled with the same compiler. With Ubuntu 16.04 and gcc-6, g++-6, clang-3.8 you should use these commands:
./bootstrap.sh --with-toolset=clang
./b2 stage toolset=clang-3.8 define=_GLIBCXX_USE_CXX11_ABI=0 --with-thread --with-filesystem --with-python --with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ --with-program_options --with-system link=shared
sudo ./b2 install toolset=clang-3.8 define=_GLIBCXX_USE_CXX11_ABI=0 --with-thread --with-filesystem --with-python --with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ --with-program_options --with-system link=shared -d0
sudo ldconfig && cd ~/
With Ubuntu 18.04 or Ubuntu 16.04 using the default compiler, the compilation procedure is the following:
./bootstrap.sh
./b2 stage toolset=gcc --with-thread --with-filesystem --with-python --with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ --with-program_options --with-system link=shared
sudo ./b2 install toolset=gcc --with-thread --with-filesystem --with-python --with-regex -sHAVE_ICU=1 -sICU_PATH=/usr/ --with-program_options --with-system link=shared -d0
sudo ldconfig && cd ~/
Do not try compiling mapnik with an updated compiler if boost is installed from package.
HarfBuzz is an OpenType text shaping engine.
It might be installed from package, but better is downloading a more updated source version, compiling it. To install from package:
sudo apt-get install -y libharfbuzz-dev
Check the lastest version here. This example grubs harfbuzz-1.7.6:
cd ~/src
wget https://www.freedesktop.org/software/harfbuzz/release/harfbuzz-1.7.6.tar.bz2
tar xjf harfbuzz-1.7.6.tar.bz2
rm harfbuzz-1.7.6.tar.bz2
cd harfbuzz-1.7.6
./configure && make && sudo make install
sudo ldconfig && cd ~/
At the time of writing, Mapnik 3.0 is the current stable release and shall be used. The branch for the latest Mapnik from 3.0.x series is v3.0.x.6
Download the latest sources of Mapnik:
cd ~/src
git clone -b v3.0.x https://github.com/mapnik/mapnik
cd mapnik
git submodule update --init
source bootstrap.sh
./configure CUSTOM_CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" CXX=${CXX} CC=${CC}
make
After Mapnik is successfully compiled, use the following command to install it to your system:
make test
sudo make install
cd ~/
Python bindings are not included by default. You’ll need to add those separately.
Install prerequisites:
sudo apt-get install -y python-setuptools python3-setuptools
Only in case you installed boost from package, you also need:
sudo apt-get install -y libboost-python-dev
Do not peform the above libboost-python-dev installation with boost compiled from source.
Set BOOST variables if you installed boost from sources:
export BOOST_PYTHON_LIB=boost_python
export BOOST_THREAD_LIB=boost_thread
export BOOST_SYSTEM_LIB=boost_system
Download and compile python-mapnik. We still use v3.0.x branch:
cd ~/src
git clone -b v3.0.x https://github.com/mapnik/python-mapnik.git
cd python-mapnik
sudo -E python3 setup.py develop
sudo -E python3 setup.py install
Note: Mapnik and mapnik-config
(part of Mapnik) need to be installed prior to this setup.
You can then verify that Mapnik has been correctly installed.
Report Mapnik version number and provide the path of the input plugins directory7:
mapnik-config -v
mapnik-config --input-plugins
Verify that Python is installed. Also verify that pip is installed.
Check then with Python 3:
python3 -c "import mapnik;print(mapnik.__file__)"
If python 2.7 is used (not Ubuntu 20.04 LTS), use this command to check:
python -c "import mapnik;print mapnik.__file__"
It should return the path to the python bindings (e.g., /usr/lib/python2.7/dist-packages/mapnik/__init__.pyc
). If python replies without errors, then Mapnik library was found by Python.
If you are preparing a remote virtual machine, configure the firewall to allow remote access to the local port 80 and local port 443.
If you run a cloud based VM, also the VM itself shall be set to open this port.
The Apache free open source HTTP Server is among the most popular web servers in the world. It’s well-documented, and has been in wide use for much of the history of the web, which makes it a great default choice for hosting a website.
To install apache:
sudo apt-get install -y apache2 apache2-dev
The Apache service can be started with
sudo service apache2 start
Error “Failed to enable APR_TCP_DEFER_ACCEPT” with Ubuntu on Windows is due to this socket option which is not natively supported by Windows. To overcome it, edit /etc/apache2/apache2.conf with
sudo vi /etc/apache2/apache2.conf
and add the following line to the end of the file:
AcceptFilter http none
To check if Apache is installed, direct your browser to the IP address of your server (eg. http://localhost). The page should display the default Apache home page. Also this command allows checking correct working:
curl localhost| grep 'It works!'
The Apache tuning adopted by the OpenStreetMap tile servers can be found in the related Chef configuration.
You can run the following command to reveal the public IP address of your server:
wget https://ipinfo.io/ip -qO -
You can test Apache by accessing it through a browser at http://your-server-ip.
Mod_tile is an Apache module to efficiently render and serve map tiles for www.openstreetmap.org map using Mapnik.
With Ubuntu 18.04 (bionic) and Ubuntu 20.04 (focal), mod_tile/renderd can be installed by adding the OpenStreetMap PPA maintained by the “OpenStreetMap Administrators” team:
sudo add-apt-repository -y ppa:osmadmins/ppa
sudo apt-get update
Also the above mentioned talaj PPA is suitable.
After adding the PPA, mod_tile/renderd can be installed from package through the following command:
sudo apt-get install -y libapache2-mod-tile # this includes both mod-tile and renderd
On Ubuntu 21.04 (hirsute) the package is available and can be installed with
sudo apt-get install -y libapache2-mod-tile renderd
Alternatively to installing Mod_tile via PPA, we can compile it from its GitHub repository.
To remove the previously installed PPA and related packages:
sudo apt-get purge -y libapache2-mod-tile
sudo apt -y autoremove
sudo add-apt-repository -y --remove ppa:osmadmins/ppa
sudo add-apt-repository -y --remove ppa:talaj/osm-mapnik
To compile Mod_tile:
sudo apt-get install -y autoconf autogen
mkdir -p ~/src ; cd ~/src
git clone https://github.com/openstreetmap/mod_tile.git
# Alternative repository:
# git clone -b switch2osm git://github.com/SomeoneElseOSM/mod_tile.git
cd mod_tile
./autogen.sh && ./configure && make && sudo make install && sudo make install-mod_tile && sudo ldconfig
cd ~/
Check also https://github.com/openstreetmap/mod_tile/blob/master/docs/build/building_on_ubuntu_20_04.md
The rendering process implemented by mod_tile and renderd is well explained in the related GitHub readme.
Check that Python is installed:
sudo apt-get install -y python3 python3-distutils
# Verify Python installation:
python -V
python3 -V
This is necessary in order to run OpenStreetMap-Carto scripts/indexes.
sudo apt-get install -y python-yaml
pip -V # to verify whether pip is already installed
sudo apt-get install -y python3-pip
python3 -m pip install --upgrade pip
The Mapnik Utilities package includes shapeindex.
sudo apt-get install -y mapnik-utils
mkdir -p ~/src
cd ~/src
git clone https://github.com/gravitystorm/openstreetmap-carto.git
cd openstreetmap-carto
Read installation notes for further information.
Currently Noto fonts are used.
To install them (except Noto Emoji Regular and Noto Sans Arabic UI Regular/Bold):
sudo apt-get install -y fonts-noto-cjk fonts-noto-hinted fonts-noto-unhinted fonts-hanazono ttf-unifont
Installation of Noto fonts (hinted ones should be used if available8):
cd ~/src
git clone https://github.com/googlefonts/noto-emoji.git
git clone https://github.com/googlefonts/noto-fonts.git
sudo cp noto-emoji/fonts/NotoColorEmoji.ttf /usr/share/fonts/truetype/noto
sudo cp noto-emoji/fonts/NotoEmoji-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansArabicUI/NotoSansArabicUI-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoNaskhArabicUI/NotoNaskhArabicUI-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansArabicUI/NotoSansArabicUI-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoNaskhArabicUI/NotoNaskhArabicUI-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansAdlam/NotoSansAdlam-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansAdlamUnjoined/NotoSansAdlamUnjoined-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansChakma/NotoSansChakma-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansOsage/NotoSansOsage-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansSinhalaUI/NotoSansSinhalaUI-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansArabicUI/NotoSansArabicUI-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansCherokee/NotoSansCherokee-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansSinhalaUI/NotoSansSinhalaUI-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansSymbols/NotoSansSymbols-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansArabicUI/NotoSansArabicUI-Bold.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/unhinted/ttf/NotoSansSymbols2/NotoSansSymbols2-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/hinted/ttf/NotoSansBalinese/NotoSansBalinese-Regular.ttf /usr/share/fonts/truetype/noto
sudo cp noto-fonts/archive/hinted/NotoSansSyriac/NotoSansSyriac-Regular.ttf /usr/share/fonts/truetype/noto
mkdir NotoSansSyriacEastern-unhinted
cd NotoSansSyriacEastern-unhinted
wget https://noto-website-2.storage.googleapis.com/pkgs/NotoSansSyriacEastern-unhinted.zip
unzip NotoSansSyriacEastern-unhinted.zip
sudo cp NotoSansSyriacEastern-Regular.ttf /usr/share/fonts/truetype/noto
cd ..
sudo apt install fontconfig
At the end:
sudo fc-cache -fv
fc-list
fc-list | grep Emoji
DejaVu Sans is used as an optional fallback font for systems without Noto Sans. If all the Noto fonts are installed, it should never be used.
sudo apt-get install -y fonts-dejavu-core
Read font notes for further information.
The unifont Medium font (lowercase label), which was included in past OS versions, now is no more available and substituted by Unifont Medium (uppercase). Warnings related to the unavailability of unifont Medium are not relevant9 and are due to the old decision of OpenStreetMap maintainers to support both the past Ubuntu 12.04 font and the newer version (uppercase).
One way to avoid the warning is removing the reference to “unifont Medium” in openstreetmap-carto/style.xml.
Another alternative way to remove the lowercase unifont Medium warning is installing the old “unifont Medium” font (used by Ubuntu 12.10):
mkdir -p ~/src ; cd ~/src
mkdir OldUnifont
cd OldUnifont
wget http://http.debian.net/debian/pool/main/u/unifont/unifont_5.1.20080914.orig.tar.gz
tar xvfz unifont_5.1.20080914.orig.tar.gz unifont-5.1.20080914/font/precompiled/unifont.ttf
sudo cp unifont-5.1.20080914/font/precompiled/unifont.ttf /usr/share/fonts/truetype/unifont/OldUnifont.ttf
sudo fc-cache -fv
fc-list | grep -i unifont # both uppercase and lowercase fonts will be listed
Notice that above installation operation is useless, just removes the warning.
Install Node.js with Ubuntu 20.04 LTS:
# Check installations:
node -v
nodejs -v
npm -v
# If components needs to be installed, run the following:
sudo apt install -y nodejs npm
Go to Check Node.js versions.
Additional notes on Node.js: other modes to install it:
A list of useful commands to manage Node.js is available at a specific page.
The above reported Node.js version also supports installing TileMill and Carto.
The recent versions of Ubuntu come with Node.js (nodejs package) and npm (npm package) in the default repositories. Depending on which Ubuntu version you’re running, those packages may contain outdated releases; the one coming with Ubuntu 16.04 will not be the latest, but it should be stable and sufficient to run Kosmtik and Carto. TileMill instead needs nodejs-legacy (or an old version of node installed via a Node.js version management tool).
For carto we will install nodejs:
sudo apt-get install -y nodejs npm
node -v 2>/dev/null || sudo ln -fs /usr/bin/nodejs /usr/local/bin/node
nodejs -v
node -v
npm -v
Alternatively, a suggested approach is using a Node.js version management tool, which simplifies the interactive management of different Node.js versions and allows performing the upgrade to the latest one. We will use n.
Install n:
mkdir -p ~/src ; cd ~/src
git clone https://github.com/tj/n.git
cd n
sudo make install # To uninstall: sudo make uninstall
cd ..
Some programs (like Kosmtik and carto) accept the latest LTS node version (sudo n lts
), other ones (like Tilemill) run with v6.14.1 (sudo n 6.14.1
).
For carto we will install the latest LTS one:
sudo n lts
To get the installed version numbers:
node -v
npm -v
Carto is the stylesheet compiler translating CartoCSS projects into Mapnik XML stylesheet.
According to the current openstreetmap-carto documentation, the minimum carto (CartoCSS) version that can be installed is 0.18. As carto compiles the openstreetmap-carto stilesheets, keeping the same version as in openstreetmap-carto documentation is recommended (instead of simply installing the latest carto release).
The latest carto version 1.2.0 can be installed with
sudo npm install -g carto
This works with Ubuntu 20.04 LTS.
Up to Ubuntu 18.04 LTS, this version produces warnings like “Styles do not match layer selector .text-low-zoom”.
To avoid these warning, install the version 0 of carto:
sudo npm install -g carto@0
It should be carto 0.18.2 at the time of writing.
In case the installation fails, this is possibly due to some incompatibility with npm/Node.js; to fix this, try downgrading the Node.js version.
To check the installed verison:
carto -v
When running carto, you need to specify the Mapnik API version through the -a
option. For the version to adopt, the openstreetmap-carto documentation offers some recommendations.
To list all the known API versions in your installed node software, run the following command:
npm install mapnik-reference
node -e "console.log(require('mapnik-reference'))"
Specifications for each API version are also documented within the carto repository.
You should use the closest API version to your installed Mapnik version (check with mapnik-config -v
).
Test carto and produce style.xml from the openstreetmap-carto style:
cd ~/src
cd openstreetmap-carto
carto -a "3.0.22" project.mml > style.xml
ls -l style.xml
When selecting the appropriate API version, you should not get any relevant warning message.
The command sudo apt-get install -y node-carto
might install an old carto version, not compatible with Openstreetmap Carto, and should be avoided.
PostgreSQL is a relational database, and PostGIS is its spatial extender, which allows you to store geographic objects like map data in it; it serves a similar function to ESRI’s SDE or Oracle’s Spatial extension. PostgreSQL + PostGIS are used for a wide variety of features such as rendering maps, geocoding, and analysis.
Currently the tested versions for OpenstreetMap Carto are PostgreSQL 10 and PostGIS 2.4:
Also older or newer PostgreSQL version should be suitable.
On Ubuntu there are pre-packaged versions of both postgis and postgresql, so these can simply be installed via the Ubuntu package manager.
sudo apt-get update
sudo apt-get install -y postgresql postgis
Optional components:
sudo apt-get install -y postgresql-contrib postgresql-12-postgis-3 postgresql-12-postgis-3-scripts
You need to start the db:
sudo service postgresql start
Note: used PostgreSQL port is 5432 (default).
Now you need to create a PostGIS database. The defaults of various programs including openstreetmap-carto (ref. project.mml) assume the database is called gis. You need to create a PostgreSQL database and set up a PostGIS extension on it.
The character encoding scheme to be used in the database is UTF8 and the adopted collation is en_GB.utf8. (The U&"..."
escaped Unicode syntax used in project.mml should work only when the server encoding is UTF8. This is also in line with what reported in the PostgreSQL Chef configuration code.)
sudo -u postgres createuser -s $USER
createdb gis --encoding="UTF8" --lc-collate="en_GB.UTF-8" --lc-ctype="en_GB.UTF-8" --template=template0
psql -d gis -c 'CREATE EXTENSION postgis; CREATE EXTENSION hstore;'
Note: ERROR: invalid locale name: "en_GB.UTF-8"
means that en_GB.UTF-8 locale has not been installed. After installing locale, the database shall be restarted in order to be able to load the locale.
Go to the next step.
If in different host:
export PGHOST=localhost
export PGPORT=5432
export PGUSER=postgres
export PGPASSWORD=postgres_007%
HOSTNAME=localhost # set it to the actual ip address or host name
createdb gis --host="$HOSTNAME" --encoding="UTF8" --lc-collate="en_GB.UTF-8" --lc-ctype="en_GB.UTF-8" --template=template0
If you get the following error:
ERROR: invalid locale name: "en_GB.utf8"
then you need to add ‘en_GB.utf8’ locale using the following command:
sudo dpkg-reconfigure locales
And select “en_GB.UTF-8 UTF-8” in the first screen (“Locales to be generated”). Subsequently, restarting the db would be suggested:
sudo service postgresql restart
If you get the following error:
ERROR: new collation (en_GB.utf8) is incompatible with the collation of the template database (en_US.UTF-8)
HINT: Use the same collation as in the template database, or use template0 as template.
you need to use template0 for gis:
psql -U postgres -h $HOSTNAME -c "CREATE DATABASE gis ENCODING 'UTF-8' LC_COLLATE 'en_GB.utf8' LC_CTYPE 'en_GB.utf8' TEMPLATE template0"
# alternative command: createdb -E UTF8 -l en_GB.UTF8 -O postgres -T template0 gis
If you get the following error:
ERROR: new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII)
HINT: Use the same encoding as in the template database, or use template0 as template.
(error generally happening with Ubuntu on Windows with WSL), then add also TEMPLATE template0
; e.g., use the following command:
psql -U postgres -h $HOSTNAME -c "CREATE DATABASE gis ENCODING 'UTF-8' LC_COLLATE 'en_GB.utf8' LC_CTYPE 'en_GB.utf8' TEMPLATE template0"
# alternative command: createdb -E UTF8 -l en_GB.utf8 -O postgres -T template0 gis
Check to create the DB within a disk partition where enough disk space is available10. If you need to use a different tablespace than the default one, execute the following commands instead of the previous ones (example: the tablespace has location /tmp/db
):
sudo mkdir /mnt/db # Suppose this is the tablespace location
sudo chown postgres:postgres /mnt/db
psql -U postgres -h $HOSTNAME -c "CREATE TABLESPACE gists LOCATION '/mnt/db'"
psql -U postgres -h $HOSTNAME -c "ALTER DATABASE gis SET TABLESPACE gists"
Create the postgis and hstore extensions:
psql -U postgres -h $HOSTNAME -c "\connect gis"
psql -U postgres -h $HOSTNAME -d gis -c "CREATE EXTENSION postgis"
psql -U postgres -h $HOSTNAME -d gis -c "CREATE EXTENSION hstore"
If you get the following error
ERROR: could not open extension control file "/usr/share/postgresql/9.3/extension/postgis.control": No such file or directory
then you might be installing PostgreSQL 9.3 (instead of 9.5), for which you should also need:
sudo apt-get install postgis postgresql-9.3-postgis-scripts
Install it and repeat the create extension commands. Notice that PostgreSQL 9.3 is not currently supported by openstreetmap-carto.
In order for the application to access the gis database, a DB user with the same name of your UNIX user is needed. Let’s suppose your UNIX ue is tileserver.
psql -d gis -c "create user tileserver;grant all privileges on database gis to postgres;"
psql -d gis -c 'create user "www-data";grant all privileges on database gis to "www-data";'
psql -d gis -c 'ALTER TABLE geometry_columns OWNER TO postgres;'
psql -d gis -c 'ALTER TABLE spatial_ref_sys OWNER TO postgres;'
If in different host, to remotely access PostgreSQL, you need to edit pg_hba.conf:
sudo vi /etc/postgresql/*/main/pg_hba.conf
and add the following line:
host all all <your IP set>/<your netmask> md5
host all all 0.0.0.0/0 md5
is an access control rule that let anybody login in from any address if providing a valid password (md5 keyword).
Then edit postgresql.conf:
sudo vi /etc/postgresql/*/main/postgresql.conf
and set listen_addresses = '*'
Finally, the DB shall be restarted:
sudo /etc/init.d/postgresql restart
Check that the gis database is available. To list all databases defined in PostgreSQL, issue the following command:
psql -U postgres -h $HOSTNAME -c "\l+"
The obtained report should include the gis database, as in the following table:
Name | Owner | Encoding | Collate | Ctype | Access privileges |
---|---|---|---|---|---|
gis | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =Tc/postgres |
postgres=CTc/postgres | |||||
tileserver=CTc/postgres |
The default PostgreSQL settings aren’t great for very large databases like OSM databases. Proper tuning can just about double the performance.
Set the postgres user to trust:
sudo vi /etc/postgresql/*/main/pg_hba.conf
# change: local all postgres peer
# to: local all postgres trust
After performing the above change, restart the DB:
sudo service postgresql restart
Run tune-postgis.sh:
export POSTGRES_USER=postgres
export PG_MAINTENANCE_WORK_MEM=256MB
export PG_WORK_MEM=16MB
export psql=psql
cd ~/src
cd openstreetmap-carto
bash scripts/tune-postgis.sh
Whitout setting postgres to trust, the following error occurs: psql: error: FATAL: Peer authentication failed for user "postgres"
when running tune-postgis.sh.
To cleanup the data directory and redo again tune-postgis.sh: rm -rf data
.
The PostgreSQL wiki has a page on database tuning.
Paul Norman’s Blog has an interesting note on optimizing the database, which is used here below.
Default maintenance_work_mem
and work_mem
settings are far too low for rendering.11: both parameters should be increased for faster data loading and faster queries (index scanning).
Conservative settings for a 4GB VM are work_mem=32MB
and maintenance_work_mem=256MB
. On a machine with enough memory you could set them as high as work_mem=256MB
and maintenance_work_mem=1GB
.
Besides, important settings are shared_buffers
and the write-ahead-log (wal). There are also some other settings you might want to change specifically for the import.
To edit the PostgreSQL configuration file with vi editor:
sudo vi /etc/postgresql/*/main/postgresql.conf
and if you are running PostgreSQL 9.3 (not supported):
sudo vi /etc/postgresql/9.3/main/postgresql.conf
Suggested minimum settings:
shared_buffers = 128MB
min_wal_size = 1GB
max_wal_size = 2GB
work_mem = 32MB # check comments for better tuning
maintenance_work_mem = 256MB
autovacuum = off
fsync = off
The latter two ones allow a faster import: the first turns off auto-vacuum during the import and allows you to run a vacuum at the end; the second introduces data corruption in case of a power outage and is dangerous. If you have a power outage while importing the data, you will have to drop the data from the database and re-import, but it’s faster. Just remember to change these settings back after importing. fsync has no effect on query times once the data is loaded.
The PostgreSQL tuning adopted by OpenStreetMap can be found in the PostgreSQL Chef Cookbook: the specific PostgreSQL tuning for the OpenStreetMap tile servers is reported in the related Tileserver Chef configuration.
For a dev&test installation on a system with 16GB of RAM, the suggested settings are the following12:
shared_buffers = 2GB
work_mem = 256MB
maintenance_work_mem = 1GB
wal_level = minimal
synchronous_commit = off
min_wal_size = 1GB
max_wal_size = 2GB
checkpoint_segments = 60
checkpoint_timeout = 15min
checkpoint_completion_target = 0.9
default_statistics_target = 1000
autovacuum = off
fsync = off
default_statistics_target can be even increased to 10000.
If performing database updates, run ANALYZE periodically.
To stop and start the database:
sudo /etc/init.d/postgresql stop
sudo /etc/init.d/postgresql start
You may get an error and need to increase the shared memory size. Edit /etc/sysctl.d/30-postgresql-shm.conf and run sudo sysctl -p /etc/sysctl.d/30-postgresql-shm.conf
. A parameter like kernel.shmmax=17179869184
and kernel.shmall=4194304
could be appropriate for a 16GB segment size.13
To manage and maintain the configuration of the servers run by OpenStreetMap, the Chef configuration management tool is used.
The configuration adopted for PostgreSQL is postgresql/attributes/default.rb.
Osm2pgsql is an OpenStreetMap specific software used to load the OSM data into the PostGIS database.
The default packaged versions of Osm2pgsql are 0.88.1-1 on Ubuntu 16.04 LTS and 0.96.0 on Ubuntu 18.04 LTS. Nevertheless, more recent versions are suggested, available at the OpenStreetMap Osmadmins PPA or compiling the software from sources.
To install osm2pgsql:
sudo apt install -y osm2pgsql
To install Osm2pgsql from Osmadmins PPA:
sudo add-apt-repository -y ppa:osmadmins/ppa
apt-key adv --keyserver keyserver.ubuntu.com --recv A438A16C88C6BE41CB1616B8D57F48750AC4F2CB
sudo apt-get update
sudo apt-get install -y osm2pgsql
Go to Get an OpenStreetMap data extract.
This alternative installation procedure generates the most updated executable by compiling the sources.
Install Needed dependencies:
sudo apt-get install -y make cmake g++ libboost-dev libboost-system-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev \
libbz2-dev libpq-dev libgeos-dev libgeos++-dev libproj-dev lua5.2 \
liblua5.2-dev
Download osm2pgsql:
mkdir -p ~/src ; cd ~/src
git clone git://github.com/openstreetmap/osm2pgsql.git
Prepare for compiling, compile and install:
cd osm2pgsql
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
sudo make install
cd
You need to download an appropriate .osm or .pbf file to be subsequently loaded into the previously created PostGIS instance via osm2pgsql
.
There are many ways to download the OSM data.
The reference is Planet OSM.
It’s probably easiest to grab an PBF of OSM data from geofabrik.
Also, BBBike.org provides extracts of more than 200 cities and regions world-wide in different formats.
Examples:
Map data of the whole planet (32G):
wget -c https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf
Map data of Great Britain (847M):
wget -c https://download.geofabrik.de/europe/great-britain-latest.osm.pbf
For just Liechtenstein:
wget https://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf
wget https://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf.md5
# Optionally, the following will xheck that the download wasn't corrupted:
md5sum -c liechtenstein-latest.osm.pbf.md5
Another method to download data is directly with your browser. Check this page.
Alternatively, JOSM can be used (Select the area to download the OSM data: JOSM menu, File, Download From OSM; tab Slippy map; drag the map with the right mouse button, zoom with the mouse wheel or Ctrl + arrow keys; drag a box with the left mouse button to select an area to download. The Continuous Download plugin is also suggested. When the desired region is locally available, select File, Save As, <filename>.osm
. Give it a valid file name and check also the appropriate directory where this file is saved.
In all cases, avoid using too small areas.
OpenStreetMap is open data. OSM’s license is Open Database License.
The osm2pgsql documentation reports all needed information to use this ETL tool, including related command line options.
osm2pgsql uses overcommit like many scientific and large data applications, which requires adjusting a kernel setting:
sudo sysctl -w vm.overcommit_memory=1
To load data from an .osm or .pbf file to PostGIS, issue the following:
cd ~/src
cd openstreetmap-carto
export OSM2PGSQL_CACHE=${OSM2PGSQL_CACHE:-512}
export OSM2PGSQL_NUMPROC=${OSM2PGSQL_NUMPROC:-1}
export OSM2PGSQL_DATAFILE=${OSM2PGSQL_DATAFILE:-data.osm.pbf}
osm2pgsql \
--cache $OSM2PGSQL_CACHE \
--number-processes $OSM2PGSQL_NUMPROC \
--hstore \
--multi-geometry \
--database gis \
--slim \
--drop \
--style openstreetmap-carto.style \
--tag-transform-script openstreetmap-carto.lua \
[.osm or .pbf file]
[.osm or .pbf file]
: substitute this with your already downloaded .osm or .pbf file, like, e.g., liechtenstein-latest.osm.pbf.
With available memory, set export OSM2PGSQL_CACHE=2500
; it allocates 2.5 GB of memory to the import process.
Option --create
loads data into an empty database rather than trying to append to an existing one.
Relaying to OSM2PGSQL_NUMPROC, if you have more cores available, you can set it accordingly.
The osm2pgsql manual describes usage and all options in detail.
Go to the next step.
If using a different server:
cd ~/src
cd openstreetmap-carto
HOSTNAME=localhost # set it to the actual ip address or host name
osm2pgsql -s -C 300 -c -G --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua -d gis -H $HOSTNAME -U postgres [.osm or .pbf file]
Notice that the suggested process adopts the -s
(--slim
option), which uses temporary tables, so running it takes more diskspace (and is very slow), while less RAM memory is used. You might add --drop
option with -s
(--slim
), to also drop temporary tables after import, otherwise you will also find the temporary tables nodes, ways, and rels (these tables started out as pure
“helper” tables for memory-poor systems, but today they are widely used because they are also a prerequisite for updates).
If everything is ok, you can go to the next step.
Notice that the following elements are used:
Depending on the input file size, the osm2pgsql command might take very long. An interesting page related to Osm2pgsql benchmarks associates sizing of hw/sw systems with related figures to import OpenStreetMap data.
Note: if you get the following error:
node_changed_mark failed: ERROR: prepared statement "node_changed_mark" does not exist
do the following command on your original.osm:
sed "s/action='modify' //" < original.osm | > fixedfile.osm
Then process fixedfile.osm.
If you get errors like this one:
Error reading style file line 79 (fields=4)
flag 'phstore' is invalid in non-hstore mode
Error occurred, cleaning up
or this one:
Postgis Plugin: ERROR: column "tags" does not exist
LINE 8: ...ASE WHEN "natural" IN ('mud') THEN "natural" ELSE tags->'wet...
then you need to enable hstore extension to the db with CREATE EXTENSION hstore;
and also add the –hstore flag to osm2pgsql.
Enabling hstore extension and using it with osm2pgsql will fix those errors.
At least 18 GB HD and appropriate RAM/swap is needed for this step (24 GB HD is better). 8 GB HD will not be enough. With 1 GB RAM, configuring a swap is mandatory.
python3 -m pip install psycopg2-binary
cd ~/src
cd openstreetmap-carto
scripts/get-external-data.py
To cleanup the get-external-data.py procedure and restart from scratch, remove the data directory (rm -r data
).
Configure a swap to prevent the following message:
INFO:root:Checking table water_polygons
Killed
The way shapefiles are loaded by the OpenStreetMap tile servers is reported in the related Chef configuration.
Read scripted download for further information.
Create partial indexes to speed up the queries included in project.mml and grant access to all gis tables to avoid renderd errors when accessing tables with user tileserver.
Add the partial geometry indexes indicated by openstreetmap-carto14 to provide effective improvement to the queries:
cd ~/src
cd openstreetmap-carto
HOSTNAME=localhost # set it to the actual ip address or host name
psql -d gis -f indexes.sql
Alternative mode:
cd ~/src
cd openstreetmap-carto
scripts/indexes.py | psql -d gis
If using a different host:
HOSTNAME=localhost # set it to the actual ip address or host name
cd ~/src
cd openstreetmap-carto
scripts/indexes.py | psql -U postgres -h $HOSTNAME -d gis
Alternative mode with a different host:
HOSTNAME=localhost # set it to the actual ip address or host name
psql -U postgres -h $HOSTNAME -d gis -f indexes.sql
Create PostgreSQL user “tileserver” (if not yet existing) and grant rights to all gis db tables for “tileserver” user and for all logged users:
psql -d gis <<\eof
REVOKE CONNECT ON DATABASE gis FROM PUBLIC;
GRANT CONNECT ON DATABASE gis TO "www-data";
GRANT CONNECT ON DATABASE gis TO "tileserver";
eof
To list all tables available in the gis database, issue the following command:
psql -d gis -c "\dt+"
or:
psql -U postgres -h $HOSTNAME -d gis -c "\dt+"
The database shall include the rels, ways and nodes tables (created with the --slim
mode of osm2pgsql) in order to allow updates.
In the following example of output, the --slim
mode of osm2pgsql was used:
Schema | Name | Type | Owner |
---|---|---|---|
public | planet_osm_line | table | postgres |
public | planet_osm_nodes | table | postgres |
public | planet_osm_point | table | postgres |
public | planet_osm_polygon | table | postgres |
public | planet_osm_rels | table | postgres |
public | planet_osm_roads | table | postgres |
public | planet_osm_ways | table | postgres |
public | spatial_ref_sys | table | postgres |
In fact, the tables planet_osm_rels, planet_osm_ways, planet_osm_nodes are available, as described in the Database Layout of Pgsql.
Check The OpenStreetMap data model at Mapbox for further details.
Read custom indexes for further information.
Next we need to plug renderd and mod_tile into the Apache webserver, ready to receive tile requests.
Get the Mapnik plugin directory:
mapnik-config --input-plugins
It should be /usr/local/lib/mapnik/input, or /usr/lib/mapnik/3.0/input or another one.
Edit renderd configuration file with your preferite editor:
sudo vi /usr/local/etc/renderd.conf
Note: when installing mod_tile from package, the pathname is /etc/renderd.conf.
sudo vi /etc/renderd.conf
In [mapnik]
section, change the value of the plugins_dir parameter to reflect the one returned by mapnik-config --input-plugins
:
Example (if installing Mapnik 3.0 from package):
plugins_dir=/usr/lib/mapnik/3.0/input/
With Mapnik 2.2 from package:
plugins_dir=/usr/lib/mapnik/2.2/input/
With Mapnik 3.0 from sources:
plugins_dir=/usr/local/lib/mapnik/input/
In [mapnik]
section, also change the value of the following settings:
font_dir=/usr/share/fonts
font_dir_recurse=true
In the [default]
section, change the value of XML and HOST to the following.
XML=/home/tileserver/src/openstreetmap-carto/style.xml
HOST=localhost
Notice that URI shall be set to /osm_tiles/
.
Also, substitute all ;**
with ;xxx=**
(e.g., with vi :1,$s/^;\*\* /;xxx=** /g
).
We suppose in the above example that your home directory is /home/tileserver. Change it to your actual home directory.
Example of file:
[renderd]
stats_file=/var/run/renderd/renderd.stats
;socketname=/var/run/renderd/renderd.sock
num_threads=4
tile_dir=/var/lib/mod_tile
[mapnik]
plugins_dir=/usr/lib/mapnik/3.0/input/
font_dir=/usr/share/fonts
font_dir_recurse=true
[default]
URI=/osm_tiles/
TILEDIR=/var/lib/mod_tile
XML=/home/tileserver/src/openstreetmap-carto/style.xml
HOST=localhost
TILESIZE=256
Save the file.
Check the existence of the /var/run/renderd directory, otherwise create it with sudo mkdir /var/run/renderd/renderd.sock
.
Check this to be sure:
ls -l /home/tileserver/src/openstreetmap-carto/style.xml
grep '^;xxx=\*\*' /usr/local/etc/renderd.conf
In case of error, verify user name and check again /usr/local/etc/renderd.conf
.
Install renderd init script by copying the sample init script included in its package.
sudo cp ~/src/mod_tile/debian/renderd.init /etc/init.d/renderd
Note: when installing mod_tile from package, the above command is not needed.
Grant execute permission.
sudo chmod a+x /etc/init.d/renderd
Note: when installing mod_tile from package, the above command is not needed.
Edit the init script file
sudo vi /etc/init.d/renderd
Change the following variables:
DAEMON=/usr/local/bin/$NAME
DAEMON_ARGS="-c /usr/local/etc/renderd.conf"
RUNASUSER=tileserver
Important note: when installing mod_tile from package, keep DAEMON=/usr/bin/$NAME
and DAEMON_ARGS="-c /etc/renderd.conf"
.
In RUNASUSER=tileserver
we suppose that your user is tileserver. Change it to your actual user name.
Save the file.
Create the following file and set tileserver (your actual user) the owner.
sudo mkdir -p /var/lib/mod_tile
sudo chown tileserver:tileserver /var/lib/mod_tile
Note: when installing mod_tile from package, the above commands are not needed.
Again change it to your actual user name.
Then start renderd service
sudo systemctl daemon-reload
sudo systemctl start renderd
sudo systemctl enable renderd
With WSL, renderd needs to be started with the following command:
sudo service renderd start
The following output is regular:
renderd.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install enable renderd
If systemctl is not installed (e.g., Ubuntu 14.4) use these commands respectively:
sudo update-rc.d renderd defaults
sudo service renderd start
Create a module load file.
sudo vi /etc/apache2/mods-available/mod_tile.load
Paste the following line into the file.
LoadModule tile_module /usr/lib/apache2/modules/mod_tile.so
Save it. Create a symlink.
sudo ln -s /etc/apache2/mods-available/mod_tile.load /etc/apache2/mods-enabled/
Then edit the default virtual host file.
test -f /etc/apache2/sites-enabled/000-default.conf || sudo ln -s /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-enabled
sudo vi /etc/apache2/sites-enabled/000-default.conf
Past the following lines after the line <VirtualHost *:80>
# Load all the tilesets defined in the configuration file into this virtual host
LoadTileConfigFile /usr/local/etc/renderd.conf
# Socket where we connect to the rendering daemon
ModTileRenderdSocketName /var/run/renderd/renderd.sock
# Timeout before giving up for a tile to be rendered
ModTileRequestTimeout 3
# Timeout before giving up for a tile to be rendered that is otherwise missing
ModTileMissingRequestTimeout 60
Note: when installing mod_tile from package, set LoadTileConfigFile /etc/renderd.conf
.
LoadTileConfigFile /etc/renderd.conf
Save and close the file.
Example:
<VirtualHost *:80>
LoadTileConfigFile /etc/renderd.conf
ModTileRenderdSocketName /var/run/renderd/renderd.sock
ModTileRequestTimeout 3
ModTileMissingRequestTimeout 60
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Restart Apache.
sudo systemctl restart apache2
If systemctl is not installed (e.g., Ubuntu 14.4):
sudo service apache2 restart
With WSL, restart the Apache service with the following commands:
sudo service apache2 stop; sudo service apache2 start
Test access to tiles locally:
wget --spider http://localhost/osm_tiles/0/0/0.png
You should get Remote file exists.
if everything is correctly configured.
Then in your web browser address bar, type
your-server-ip/osm_tiles/0/0/0.png
where you need to change your-server-ip with the actual IP address of the installed map server.
To expand it with the public IP address of your server, check this command for instance (paste its output to the browser):
echo "http://`wget http://ipinfo.io/ip -qO -`/osm_tiles/0/0/0.png"
You should see the tile of world map.
Congratulations! You just successfully built your own OSM tile server.
You can go to OpenLayers to display the slippy map.
Pre-rendering tiles is generally not needed (or not wanted); its main usage is to allow offline viewing instead of rendering tiles on the fly. Depending on the DB size, the procedure can take very long time and relevant disk data.
To pre-render tiles, use render_list command. Pre-rendered tiles will be cached in /var/lib/mod_tile
directory.
To show all command line option of render_list:
render_list --help
Example usage:
render_list -a
Depending on the DB size, this command might take very long.
The following command pre-renders all tiles from zoom level 0 to zoom level 10 using 1 thread:
render_list -n 1 -z 0 -Z 10 -a
A command line Perl script named render_list_geo.pl and developed by alx77 allows automatic pre-rendering of tiles in a particular area using geographic coordinates. The related Github README describes usage and samples.
To install it:
cd ~/src
git clone https://github.com/alx77/render_list_geo.pl
cd render_list_geo.pl
Example of command to generate the z11 tiles for the UK:
./render_list_geo.pl -n 1 -z 11 -Z 11 -x -9.5 -X 2.72 -y 49.39 -Y 61.26
For both render_list and render_list_geo.pl, option -m
allows selecting specific profiles relates to named sections in renderd.conf. Not using this option, the [default]
section of renderd.conf is selected.
To monitor the tile server, showing a line every time a tile is requested, and one every time related rendering is completed:
tail -f /var/log/syslog | grep " TILE "
To clear all osm tiles cache, remove /var/lib/mod_tile/default (using rm -rf if you dare) and restart renderd daemon:
sudo rm -rf /var/lib/mod_tile/default
sudo systemctl restart renderd
Remember to also clear the browser cache.
If systemctl is not installed (e.g., Ubuntu 14.4):
sudo service renderd restart
Show Apache loaded modules:
apache2ctl -M
You should find tile_module (shared)
Show Apache configuration:
apache2ctl -S
You should get the following messages within the log:
Loading tile config default at /osm_tiles/ for zooms 0 - 20 from tile directory /var/lib/mod_tile with extension .png and mime type image/png
Tail log:
tail -f /var/log/apache2/error.log
Most of the configuration issues can discovered by analyzing the debug log of renderd; we need to stop the daemon and start renderd in foreground:
sudo systemctl stop renderd
If systemctl is not installed (e.g., Ubuntu 14.4):
sudo service renderd stop
Then control the renderd output:
sudo -u tileserver /usr/local/bin/renderd -fc /usr/local/etc/renderd.conf
Ignore the five errors related to iniparser: syntax error in /usr/local/etc/renderd.conf
when referring to commented out variables (e.g., beginning with ;
).
Press Control-C to kill the program. After fixing the error, the daemon can be restarted with:
sudo systemctl start renderd
If systemctl is not installed (e.g., Ubuntu 14.4):
sudo service renderd start
Check existence of /var/run/renderd
:
ls -ld /var/run/renderd
Verify that the access permission are -rw-r--r-- 1 tileserver tileserver
. You can temporarily do
sudo chmod 777 /var/run/renderd
Check existence of the style.xml file:
ls -l /home/tileserver/src/openstreetmap-carto/style.xml
If missing, see above to create it.
Check existence of /var/run/renderd/renderd.sock
:
ls -ld /var/run/renderd/renderd.sock
Verify that the access permission are srwxrwxrwx 1 tileserver tileserver
.
In case of wrong owner:
sudo chown 'tileserver' /var/run/renderd
sudo chown 'tileserver' /var/run/renderd/renderd.sock
sudo service renderd restart
If the directory is missing:
sudo mkdir /var/run/renderd
sudo chown 'tileserver' /var/run/renderd
sudo service renderd restart
In case renderd dies with a segmentation fault error (e.g., Loading parameterization function for
and then Segmentation fault
), this might be probably due to a configuration mismatch between the Mapnik plugins and the renderd configuration; check plugins_dir parameter in /usr/local/etc/renderd.conf.
A PostGIS permission error means that the DB tables have not been granted for tileserver user:
...An error occurred while loading the map layer 'default': Postgis Plugin: ERROR: permission denied for relation...
To fix the permission error, run:
sudo ./install-postgis-osm-user.sh gis tileserver
An error related to missing tags
column in the renderd logs means that osm2pgsql was not run with the --hstore
option.
If everything in the configuration looks fine, but the map is still not rendered without any particular message produced by renderd, try performing a system restart:
sudo shutdown -r now
If the problem persists, you might have a problem with your UNIX user. Try debugging again, after setting these variables:
export PGHOST=localhost
export PGPORT=5432
export PGUSER=postgres
export PGPASSWORD=postgres_007%
As exceptional case, the following commands allow to fully remove Apache, mod_tile and renderd and reinstall the service:
sudo rm -r ~/src/mod_tile/
sudo apt-get purge apache2 apache2-dev
sudo rm -r /etc/apache2/mods-available
sudo rm /usr/local/etc/renderd.conf
sudo rm /etc/init.d/renderd
sudo rm -rf /var/lib/mod_tile
sudo rm -rf /usr/lib/apache2
sudo rm -rf /etc/apache2/
sudo rm -rf /var/run/renderd
sudo apt-get --reinstall install apache2-bin
sudo apt-get install apache2 apache2-dev
The file naming and image format used by mod_tile is described at Slippy map tilenames. Similar format is also used by Google Maps and many other map providers.
TMS and WMS are other protocols for serving maps as tiles, managed by different rendering backends.
Tiled web map is also known as slippy map in OpenStreetMap terminology.
OpenStreetMap does not provide an “official” JavaScript library which you are required to use. Rather, you can use any library that meets your needs. The two most popular are OpenLayers and Leaflet. Both are open source.
Page Deploying your own Slippy Map illustrates how to embed the previously installed map server into a website. A number of possible map libraries are mentioned, including some relevant ones (Leaflet, OpenLayers, Google Maps API) as well as many alternatives.
To display your slippy map with OpenLayers, create a file named ol.html under /var/www/html.
sudo vi /var/www/html/ol.html
Paste the following HTML code into the file.
You might wish to adjust the longitude, latitude and zoom level according to your needs. Check var zoom = 2, center = [0, 0];
.
Notice we are using https for openstreetmap.org.
<!DOCTYPE html>
<html>
<head>
<title>OpenStreetMap with OpenLayers</title>
<link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<style>
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
.ol-custom-overviewmap,
.ol-custom-overviewmap.ol-uncollapsible {
bottom: auto;
left: auto;
right: 0;
top: 85px;
}
.ol-zoom {
top: 3em;
}
.ol-zoom-extent {
top: 20.6em!important;
}
.ol-zoomslider {
top: 7.7em!important;
}
.ol-custom-fullscreen {
bottom: auto;
left: auto;
right: 0;
top: 50px;
}
.ol-custom-mouse-positionXY {
top: auto;
bottom: 4em;
font-family: "Arial";
font-size: 12px;
text-shadow: 0 0 0.5em #FFE, 0 0 0.5em #FFE, 0 0 0.5em #FFE;
}
.ol-custom-mouse-positionHDMS {
top: auto;
bottom: 5em;
font-family: "Arial";
font-size: 12px;
text-shadow: 0 0 0.5em #FFE, 0 0 0.5em #FFE, 0 0 0.5em #FFE;
}
.ol-custom-mouse-position3857 {
top: auto;
bottom: 6em;
font-family: "Arial";
font-size: 12px;
text-shadow: 0 0 0.5em #FFE, 0 0 0.5em #FFE, 0 0 0.5em #FFE;
}
#ZoomElement {
position: absolute;
top: auto;
left: 10px;
bottom: 2.5em;
text-decoration: none;
font-family: "Arial";
font-size: 10pt;
text-shadow: 0 0 0.5em #FFE, 0 0 0.5em #FFE, 0 0 0.5em #FFE;
z-index: 30;
}
#TSLabel {
position: absolute;
top: 21px;
right: 0;
font-family: "Arial";
font-size: 12px;
z-index: 30;
}
#osmLabel {
position: absolute;
top: 21px;
left: 0;
font-family: "Arial";
font-size: 12px;
z-index: 30;
}
#swipe {
position: absolute;
top: 0;
left: -4px;
z-index: 20;
}
</style>
</head>
<body>
<div class="ol-viewport">
<input class="ol-unselectable ol-control" id="swipe" type="range" style="width: 100%">
<div class="ol-unselectable ol-control" id="TSLabel"> Tile Server ►</div>
<div class="ol-unselectable ol-control" id="osmLabel">◄ OpenStreetMap </div>
<a class="ol-unselectable ol-control" id="ZoomElement"></a>
</div>
<div tabindex="0" id="map" class="map"></div>
<script>
var zoom = 2, center = [0, 0];
// Set up the Tile Server layer
var myTileServer = new ol.layer.Tile({
preload: Infinity,
source: new ol.source.OSM({
crossOrigin: null,
url: 'osm_tiles/{z}/{x}/{y}.png'
})
});
// Set up the OSM layer
var openStreetMap = new ol.layer.Tile({
preload: Infinity,
source: new ol.source.OSM({
crossOrigin: null,
url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'
})
});
if (window.location.hash !== '') {
var hash = window.location.hash.replace('#', '');
var parts = hash.split(';');
if (parts.length === 3) {
zoom = parseInt(parts[0], 10);
center = [
parseFloat(parts[2]),
parseFloat(parts[1])
];
}
}
// Set up the default view
var myTileView = new ol.View({
center: ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'),
zoom: zoom
});
// Create the map
var map = new ol.Map({
layers: [myTileServer, openStreetMap],
loadTilesWhileInteracting: true,
target: 'map',
controls: ol.control.defaults().extend([
new ol.control.ScaleLine(),
new ol.control.Zoom(),
new ol.control.ZoomSlider(),
new ol.control.ZoomToExtent(),
new ol.control.FullScreen({
className: 'ol-fullscreen ol-custom-fullscreen'
}),
new ol.control.OverviewMap({
className: 'ol-overviewmap ol-custom-overviewmap'
}),
new ol.control.MousePosition({
className: 'ol-mouse-position ol-custom-mouse-position3857',
coordinateFormat: ol.coordinate.createStringXY(4),
projection: 'EPSG:3857',
undefinedHTML: ' '
}),
new ol.control.MousePosition({
coordinateFormat: function(coord) {
return ol.coordinate.toStringHDMS(coord);
},
projection: 'EPSG:4326',
className: 'ol-mouse-position ol-custom-mouse-positionHDMS',
target: document.getElementById('mouse-position'),
undefinedHTML: ' '
}),
new ol.control.MousePosition({
className: 'ol-mouse-position ol-custom-mouse-positionXY',
coordinateFormat: ol.coordinate.createStringXY(4),
projection: 'EPSG:4326',
undefinedHTML: ' '
}),
]),
view: myTileView
});
map.on("moveend", function() {
var view = map.getView();
var center = ol.proj.transform(view.getCenter(), 'EPSG:3857', 'EPSG:4326');
var zoom = view.getZoom();
var zoomInfo = 'Zoom level = ' + zoom;
document.getElementById('ZoomElement').innerHTML = zoomInfo;
window.location.hash =
view.getZoom() + ';' +
Math.round(center[1]*1000000)/1000000 + ';' +
Math.round(center[0]*1000000)/1000000;
});
var swipe = document.getElementById('swipe');
openStreetMap.on('precompose', function(event) {
var ctx = event.context;
var width = ctx.canvas.width * (swipe.value / 100);
ctx.save();
ctx.beginPath();
ctx.rect(width, 0, ctx.canvas.width - width, ctx.canvas.height);
ctx.clip();
});
openStreetMap.on('postcompose', function(event) {
var ctx = event.context;
ctx.restore();
});
swipe.addEventListener('input', function() {
map.render();
}, false);
</script>
</body>
</html>
Save and close the file. Now you can view your slippy map by typing the following URL in browser.
http://your-server-ip/ol.html
To expand it with the public IP address of your server, check this command for instance (paste its output to the browser):
echo "http://`wget http://ipinfo.io/ip -qO -`/ol.html"
Leaflet is a JavaScript library for embedding maps. It is simpler and smaller than OpenLayers.
The easiest example to display your slippy map with Leaflet consists in creating a file named lf.html under /var/www/html.
sudo vi /var/www/html/lf.html
Paste the following HTML code in the file. Replace your-server-ip with your IP Address and adjust the longitude, latitude and zoom level according to your needs.
<!DOCTYPE html>
<html>
<head>
<title>OpenStreetMap with Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" type="text/css">
<script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<style>
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script>
// Create the map
var map = L.map('map').setView([45, 10], 3);
// Set up the OSM layer
L.tileLayer(
'http://your-server-ip/osm_tiles/{z}/{x}/{y}.png'
).addTo(map);
</script>
</body>
</html>
Save and close the file. Now you can view your slippy map by typing the following URL in the browser.
http://your-server-ip/lf.html
A rapid way to test the slippy map is through an online source code playground like this JSFiddle template.
The following example exploits Leaflet to show OpenStreetMap data.
Default tiles can be replaced with your tile server ones by changing
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
to http://your-server-ip/osm_tiles/{z}/{x}/{y}.png
.
To edit the sample, click on Edit in JSFiddle. Then in the Javascript panel modify the string inside quotes as descripted above. Press Run.
Check process description at mod_tile for further details. ↩
Information on previous periods partially taken from switch2osm.org - Serving Tiles, ref “The toolchain” chapter. ↩
sources used for this document are the following:
vholten comment on 11 Oct 2016, ref. FreeType <= 2.6.1 on OSM rendering server causes Noto CJK too much bold ↩
Information taken from switch2osm. ↩
.travis.yml applies the custom indexes via psql -1Xq -v ON_ERROR_STOP=1 -d gis -f indexes.sql
. Notice that indexes.sql shall be kept up to date with indexes.py and this is also checked by .travis.yml. ↩