BoundlessLogoWhite

Stay Connected with the Boundless Blog

OpenStreetMap Tile Cache Server Setup and Load

There are many reasons that you might want to stand up an OpenStreetMap (“OSM”)-based tile cache service – your organization may not have access to external services, your usage may be high enough that you need a more performant system, or you just want to apply custom symbology to create a basemap that better serves your needs.

Creating your own OSM Tile Cache server using the OpenGeo Suite from Boundless is a relatively easy task.   Before you do so, there are a few things you need to take into account when implementing the tile cache service based on OSM data. In the following blog we will discuss system sizing, creating and configuring the database, importing the OSM data, and symbolizing the data.

 

The machine that will process the OSM data will need enough disk space for the OSM data load as well as your resulting tile cache. The OSM worldwide dataset consumes about 120GB of disk space — depending on your tile cache settings, the end result can be 2TB+ of data. For this exercise we used an Ubuntu 14.0.4 VM with 12GB of RAM, 2 cores, and 2TB of disk space.

As our first step, we created /media/boundless/osmdata/ with 246GB of space and have 70GB+ on root for the postgres and geoserver binaries.


boundless@ubuntu:/$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        73G   41G   29G  59% /
none            4.0K     0  4.0K   0% /sys/fs/cgroup
udev            5.7G   12K  5.7G   1% /dev
tmpfs           1.2G  3.6M  1.2G   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            5.7G  284K  5.7G   1% /run/shm
none            100M   64K  100M   1% /run/user
/dev/sdb        246G   60M  234G   1% /media/boundless/
boundless@ubuntu:/$

Next, install the OpenGeo Suite following the documentation, I recommend Linux (Ubuntu or CentOS) for performance reasons.

The OpenGeo Suite will install GeoServer, GeoWebCache and PostgreSQL, as well as most of the dependencies that we need for OSM2PGSQL (the toolset we will use to load the OSM data into the DB).  One item that is not installed is the HSTORE extension for PostgreSQL. Run the following command to install the postgresql-contrib:

sudo apt-get install postgresql-contrib

Next we need create a place for the raw OSM files as well as for the postgres tablespaces (owned by postgres). In the our case we created osmdata and postgres under /media/boundless.

drwxr-xr-x 5 boundless boundless 4096 Oct 15 11:12 osmdata

drwxr-xr-x 3 postgres  postgres  4096 Oct 13 19:39 postgres

Next step is to start getting some of the data needed for our tile cache server. In this example we will use a subset of the data focused on Colorado. We downloaded the following file into our osmdata directory:

http://download.geofabrik.de/north-america/us/colorado-latest.osm.pbf

[Side comment: If you want to use the entire planet it’s located here – but please note this file will take a while to download. If you’re going to do this you will need to plan for more disk space and longer processing times than this example shows. The Colorado OSM file is a very small subset of the OSM data – if you wish to use the United States data, plan for 120GB+ while the world can be 650GB+. These size of the files is also increasing with every release as more data is contributed to OSM]

Now that we have our OSM data downloading and the libraries needed for the PostGIS and HSTORE extensions, we can setup a DB that will house the OSM data.

Create a user for the DB – in our case we are using the username “boundless” – and then a PostGIS-enabled Database:

su postgres 
createuser boundless 
cd /media/boundless/postgres mkdir tablespace_1 
chown postgres tablespace_1 
psql -p 5432 
create tablespace tablespace_1 location 
'/media/boundless/postgres/tablespace_1'; 
CREATE DATABASE osm WITH OWNER boundless tablespace tablespace_1; 
connect osm; 
CREATE EXTENSION postgis; 
CREATE EXTENSION postgis_topology; 
CREATE EXTENSION hstore;
SELECT postgis_full_version();

The output from the posgis_full_version should look similar to this:

POSTGIS="2.1.7 r13414" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.2, released 2015/02/10" LIBXML="2.9.1" LIBJSON="UNKNOWN" RASTER

(1 row)

Before we start to load the OSM data we need to tell the DB to use the tablespace we created earlier and and set some tuning parameters in PostgreSQL. Edit the postgresql.conf file with the following recommended settings.* Some items above may need to be uncommented in addition to setting the values.

nano /etc/postgresql/9.3/main/postgresql.conf

option default recommended
shared_buffers 24 MB 4 GB
work_mem 1 MB 100MB
maintenance_work_mem 16 MB 4096 MB
fsync on off
autovacuum on off (*)
checkpoint_segments 60
random_page_cost 4.0 1.1
effective_io_concurrency 1 2
temp_tablespace ’’ ’tablepsace_1’
listen_address ‘localhost’ ‘*’

*These may be different depending on your hardware and system configuration.

Edit the pg_hba.conf file to allow login with OS credentials (this can be disabled after the OSM load):

nano  /etc/postgresql/9.3/main/pg_hba.conf

change local   all             all                                     peer

to

local   all             all                                     trust

change host   all             all                                     peer

to

host   all             all                                     trust

Restart postgresql

service postgresql restart

Next we will install OSM2PGSQL:

apt-get install osm2pgsql

Once OSM2PGSQL is instllaed, download the Mapzen style file.

If the steps above have all been successful and the OSM world file and stylesheet are downloaded, un the osm2pgsql command (assuming workding dir is /media/boundless/osmdata):

osm2pgsql -c -k --slim -C 8000 --flat-nodes ./fn -d osm -U boundless -H 127.0.0.1  -S ./mapzen_osm2pgsql.style ./colorado-latest.osm.pbf

Notes:

-C 8000 is set to ~65% of RAM

–slim slows things down but uses less ram by storing intermediate files in the database.  This is required if you want to use append to add data later on.

 Below is a listing of the objects in the DB after the load.

osm=> d

                List of relations

 Schema |        Name        | Type  |   Owner

——–+——————–+——-+———–

 public | geography_columns  | view  | postgres

 public | geometry_columns   | view  | postgres

 public | planet_osm_line    | table | boundless

 public | planet_osm_nodes   | table | boundless

 public | planet_osm_point   | table | boundless

 public | planet_osm_polygon | table | boundless

 public | planet_osm_rels    | table | boundless

 public | planet_osm_roads   | table | boundless

 public | planet_osm_ways    | table | boundless

 public | raster_columns     | view  | postgres

 public | raster_overviews   | view  | postgres

 public | spatial_ref_sys    | table | postgres

(12 rows)

osm=> select * from geometry_columns;

 f_table_catalog | f_table_schema |    f_table_name    | f_geometry_column | coord_dimension |  srid  |    type

—————–+—————-+——————–+——————-+—————–+——–+————

 osm             | public         | planet_osm_point   | way               |               2 | 900913 | POINT

 osm             | public         | planet_osm_polygon | way               |               2 | 900913 | GEOMETRY

 osm             | public         | planet_osm_line    | way               |               2 | 900913 | LINESTRING

 osm             | public         | planet_osm_roads   | way               |               2 | 900913 | LINESTRING

(4 rows)

osm=>

The next step in creating our tile cache server is to load an ocean dataset and administrative boundaries to use in conjunction with the OSM data.

Load the Oceans Polygon (mercator):

wget -bqc http://data.openstreetmapdata.com/water-polygons-split-3857.zip

unzip water-polygons-split-3957.zip

shp2pgsql -g geom -s 900913 -I -D ./water-polygons-split-3857/water_polygons.shp ocean | psql -U boundless osm

Download worldwide boundary files:

wget -bqc http://www.naturalearthdata.com/http//www.naturalearthdata.com/download
/10m/cultural/ne_10m_admin_1_states_provinces_lines.zip

wget -bqc http://www.naturalearthdata.com/http//www.naturalearthdata.com/download
/10m/cultural/ne_10m_admin_0_boundary_lines_land.zip

unzip ne_10m_admin_0_boundary_lines_land.zip

unzip ne_10m_admin_1_states_provinces_lines.zip

Load the files into the database:

shp2pgsql -g geom -s 4326 -I -D ne_10m_admin_1_states_provinces_lines.shp admin1 | psql -U boundless osm

shp2pgsql -g geom -s 4326 -I -D  ne_10m_admin_0_boundary_lines_land.shp admin0 | psql -U boundless osm

The three new layers have an SRID of 4326, we will need to transform them in the DB to 900913. Login to the DB as the table owner and run the following:

alter table admin1 alter column geom type geometry(MULTILINESTRING,900913) using st_transform(geom,900913);

alter table admin0 alter column geom type geometry(MULTILINESTRING,900913) using st_transform(geom,900913);

Download the createDBObjects.sql and run it from the command line

boundless@ubuntu:/media/boundless/osmdata$ psql -d osm -f createDBobjects.sql

psql:createDBobjects.sql:2: NOTICE:  table “aero-poly” does not exist, skipping

DROP TABLE

SELECT 278

CREATE INDEX

psql:createDBobjects.sql:17: NOTICE:  table “agriculture” does not exist, skipping

DROP TABLE

SELECT 1805

CREATE INDEX

psql:createDBobjects.sql:30: NOTICE:  table “amenity-areas” does not exist, skipping

DROP TABLE

SELECT 1300

CREATE INDEX

psql:createDBobjects.sql:44: NOTICE:  table “beach” does not exist, skipping

DROP TABLE

SELECT 601

CREATE INDEX

psql:createDBobjects.sql:59: NOTICE:  table “building” does not exist, skipping

DROP TABLE

SELECT 200888

CREATE INDEX

psql:createDBobjects.sql:80: NOTICE:  table “forest” does not exist, skipping

DROP TABLE

SELECT 8386

CREATE INDEX

psql:createDBobjects.sql:99: NOTICE:  table “grass” does not exist, skipping

DROP TABLE

SELECT 17398

CREATE INDEX

psql:createDBobjects.sql:122: NOTICE:  table “highway-label” does not exist, skipping

DROP TABLE

SELECT 214823

CREATE INDEX

psql:createDBobjects.sql:143: NOTICE:  table “park” does not exist, skipping

DROP TABLE

SELECT 11587

CREATE INDEX

psql:createDBobjects.sql:166: NOTICE:  table “parking-area” does not exist, skipping

DROP TABLE

SELECT 16952

CREATE INDEX

psql:createDBobjects.sql:181: NOTICE:  table “placenames-medium” does not exist, skipping

DROP TABLE

SELECT 105

CREATE INDEX

psql:createDBobjects.sql:196: NOTICE:  table “route-bridge-0” does not exist, skipping

DROP TABLE

SELECT 4930

CREATE INDEX

psql:createDBobjects.sql:221: NOTICE:  table “route-bridge-1” does not exist, skipping

DROP TABLE

SELECT 6742

CREATE INDEX

psql:createDBobjects.sql:246: NOTICE:  table “route-bridge-2” does not exist, skipping

DROP TABLE

SELECT 130

CREATE INDEX

psql:createDBobjects.sql:271: NOTICE:  table “route-bridge-3” does not exist, skipping

DROP TABLE

SELECT 40

CREATE INDEX

psql:createDBobjects.sql:296: NOTICE:  table “route-bridge-4” does not exist, skipping

DROP TABLE

SELECT 4

CREATE INDEX

psql:createDBobjects.sql:321: NOTICE:  table “route-bridge-5” does not exist, skipping

DROP TABLE

SELECT 3

CREATE INDEX

psql:createDBobjects.sql:346: NOTICE:  table “route-fill” does not exist, skipping

DROP TABLE

SELECT 424383

CREATE INDEX

psql:createDBobjects.sql:397: NOTICE:  table “route-line” does not exist, skipping

DROP TABLE

SELECT 325307

CREATE INDEX

psql:createDBobjects.sql:432: NOTICE:  table “route-tunnels” does not exist, skipping

DROP TABLE

SELECT 106

CREATE INDEX

psql:createDBobjects.sql:453: NOTICE:  table “route-turning-circles” does not exist, skipping

DROP TABLE

SELECT 28105

CREATE INDEX

psql:createDBobjects.sql:462: NOTICE:  table “water-outline” does not exist, skipping

DROP TABLE

SELECT 44146

CREATE INDEX

psql:createDBobjects.sql:483: NOTICE:  table “water” does not exist, skipping

DROP TABLE

SELECT 44146

CREATE INDEX

psql:createDBobjects.sql:504: NOTICE:  table “wetland” does not exist, skipping

DROP TABLE

SELECT 1283

CREATE INDEX

boundless@ubuntu:/media/boundless/os

Using the GeoServer admin UI, create a workspace in GeoServer (localhost:8080/geoserver admin/geoserver) called osm with a http://osm.org namespace.

GeoServer for Open Geo Workspace

Create a PostGIS datastore called openstreetmap that connects to the osm database:

GeoServer for Open Geo Edit Vector Data Source

Next we will use the REST API to connect to GeoServer and create layers, symbology, and associate between the symbology and layers.

  1. Download the SLD scripts to your OSM data directory and unzip it.
  2. Run the SLD_create script in the SLD folder. This will create the styles and layers in GeoServer, associate the style to the corresponding layer, and then create a group layer that is the base map.

./SLD_create.sh

Once the SLD create script has run successfully you will see the layers and styles in your GeoServer instance. To see the basemap, go to layer preview and find the OSM group layer. It should look similar this:

GeoServer Basemap
If you zoom into Denver, Colorado you can see the results.
GeoServer Basemap
GeoServer Basemap
At a tight zoom level we can see more detail and get a feel for how the data looks.

So what have we accomplished? We have created and are now serving an OSM Tile Cache – We configured our Postgres/GIS instance to facilitate the import of OSM data, loaded both OSM and world wide boundary data, created feature extracts, published the data to geoserver and applied a basic styling for our basemap.

This example can be expanded upon for your organization’s uses. Maybe you want to incorporate your own data into the basemap, alter the symbology to meet your needs, load the entire world’s data, or all of the above to provide the perfect base map for your use.