Offline/off-grid mapserver tutorial
Map © Maanmittauslaitos, CC-BY-4.0

Offline/off-grid mapserver tutorial

Setting up your own WMS map server isn’t overly hard. There’s various open source server platforms for that. For simplicity and performance reasons, this tutorial is about setting up a WMS server with MapServer.

Please note that this tutorial is specifically for topographical maps of Finland.
This tutorial presumes that you have basic Linux command line knowledge and know how to install software on your system.

First, let’s start with some requirements. You will need at least 45GB of storage space, preferably of the solid-state type. Hardware-wise, almost everything goes. However, the more users you have, the more CPU and RAM you will need to prevent the map server from getting painfully slow. You can later also look into mapcache but that is not part of this tutorial. Software-wise, you will need to install

Once you have everything in place, create a directory of your choosing and create the subdirectories config and maps.

Go to the maps subdirectory and run the Download script. That is going to take a while, depending on your internet connection. It will download about 42GB of map data.

download.sh

download.sh
#!/bin/bash

WGET="wget -r -N -np -nH -nd -A png,pgw"
BASEURL="http://kartat.kapsi.fi/files"

PERUS="peruskarttarasteri_jhs180/painovari/1m/etrs89/png/"
TOPO50k="maastokarttarasteri_50k_jhs180/painovari/4m/etrs89/png/"
TOPO100k="maastokarttarasteri_100k_jhs180/kaikki/etrs89/png/"
TOPO250k="maastokarttarasteri_250k_jhs180/kaikki/etrs89/png/"
TOPO500k="maastokarttarasteri_500k_jhs180/kaikki/etrs89/png/"
YLEIS1000k="yleiskarttarasteri_1000k_jhs180/kaikki/etrs89/png/"
YLEIS2000k="yleiskarttarasteri_2000k_jhs180/kaikki/etrs89/png/"
YLEIS4500k="yleiskarttarasteri_4500k_jhs180/kaikki/etrs89/png/"
YLEIS8000k="yleiskarttarasteri_8000k_jhs180/kaikki/etrs89/png/"

${WGET} -P PERUS ${BASEURL}/${PERUS}
${WGET} -P TOPO50k ${BASEURL}/${TOPO50k}
${WGET} -P TOPO100k ${BASEURL}/${TOPO100k}
${WGET} -P TOPO250k ${BASEURL}/${TOPO250k}
${WGET} -P TOPO500k ${BASEURL}/${TOPO500k}
${WGET} -P YLEIS1000k ${BASEURL}/${YLEIS1000k}
${WGET} -P YLEIS2000k ${BASEURL}/${YLEIS2000k}
${WGET} -P YLEIS4500k ${BASEURL}/${YLEIS4500k}
${WGET} -P YLEIS8000k ${BASEURL}/${YLEIS8000k}

gdaltindex PERUS.shp PERUS/*.png
gdaltindex TOPO50k.shp TOPO50k/*.png
gdaltindex TOPO100k.shp TOPO100k/*.png
gdaltindex TOPO250k.shp TOPO250k/*.png
gdaltindex TOPO500k.shp TOPO500k/*.png
gdaltindex YLEIS1000k.shp YLEIS1000k/*.png
gdaltindex YLEIS2000k.shp YLEIS2000k/*.png
gdaltindex YLEIS4500k.shp YLEIS2000k/*.png
gdaltindex YLEIS8000k.shp YLEIS8000k/*.png
Relevant documentation


Next, go to the config subdirectory and create the wms.map file.

Notes:

wms.map

wms.map
MAP
  NAME "TOPO_FIN"
  IMAGETYPE      PNG8
  EXTENT         20000.000000 6570000.000000 788000.000000 7818000.000000

  SIZE           256 256
  MAXSIZE        4096
  SHAPEPATH      "/maps/maastokartta"
  IMAGECOLOR     255 255 255

  PROJECTION
     "init=epsg:3067"
  END

WEB
  METADATA
    "wms_title"           "Finland - topographical map"
    "wms_onlineresource"  "http://<server-ip>/?service=WMS"
    "wms_srs"             "EPSG:3067 EPSG:3857"
    "wms_getmap_formatlist" "PNG,PNG8,JPEG"
    "wms_enable_request"  "* !GetLegendGraphic"
  END
END

LAYER
  NAME "Basemap"
  METADATA
    "wms_title" "Basemap"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_peruskartta.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 56000.000000 6594000.000000 740000.000000 7782000.000000
  MINSCALEDENOM 0
  MAXSCALEDENOM 25000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Topo_50k"
  METADATA
    "wms_title" "Topo_50k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_50000.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6594000.000000 740000.000000 7794000.000000
  MINSCALEDENOM 25000
  MAXSCALEDENOM 50000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Topo_100k"
  METADATA
    "wms_title" "Topo_100k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_100000.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 740000.000000 7818000.000000
  MINSCALEDENOM 50000
  MAXSCALEDENOM 100000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Topo_250k"
  METADATA
    "wms_title" "Topo_250k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_250000.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 788000.000000 7818000.000000
  MINSCALEDENOM 100000
  MAXSCALEDENOM 250000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Topo_500k"
  METADATA
    "wms_title" "Topo_500k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_500000.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 76000.000000 6570000.000000 884000.000000 7818000.000000
  MINSCALEDENOM 250000
  MAXSCALEDENOM 500000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Overview_1000k"
  METADATA
    "wms_title" "Overview_1000k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_yk1000k.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 740896.000000 7819280.000000
  MINSCALEDENOM 500000
  MAXSCALEDENOM 1000000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Overview_2000k"
  METADATA
    "wms_title" "Overview_2000k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_yk2000k.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 740896.000000 7819280.000000
  MINSCALEDENOM 1000000
  MAXSCALEDENOM 2000000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Overview_4500k"
  METADATA
    "wms_title" "Overview_4500k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_yk4500k.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 740896.000000 7819280.000000
  MINSCALEDENOM 2000000
  MAXSCALEDENOM 4500000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

LAYER
  NAME "Overview_8000k"
  METADATA
    "wms_title" "Overview_8000k"
  END
  STATUS ON
  TILEINDEX "/maps/maastokartta/index_yk8000k.shp"
  TILEITEM "Location"
  TYPE RASTER
  EXTENT 20000.000000 6570000.000000 740896.000000 7819280.000000
  MINSCALEDENOM 4500000
  PROJECTION
     "init=epsg:3067"
  END
  PROCESSING "RESAMPLE=BILINEAR"
END

END
Relevant documentation


When wms.map is in place, go to your directory - not the config or maps subdir - and create the mapserver.conf file. The file doesn’t actually contain any active instructions but we don’t want the default configuration which comes with the container.

mapserver.conf

mapserver.conf
CONFIG
  ENV
    #
    # Default Map
    #
    # MS_MAPFILE "/etc/mapserver/mapserver.map"
  END

  #
  # Map Aliases
  #
  # MAPS
  #   wfs "/etc/mapserver/wfs.map"
  # END
END
Relevant documentation


Finally, when everything else in in place, create docker-compose.yaml in your directory.
Please change the paths in the volumes section to fit your directory’s path!
In the compose file, we pass 2 important environment variables to MapServer:

docker-compose.yaml

docker-compose.yaml
services:
  mapserver:
    image: camptocamp/mapserver
    container_name: mapserver
    volumes:
      - <your dir>/config:/etc/mapserver:rw
      - <your dir>/mapserver.conf:/etc/mapserver.conf:ro
      - <your dir>/maps:/maps:rw
    networks:
      - default
    ports:
      - 80:80
    environment:
      - MS_MAP_NO_PATH=1
      - MS_MAPFILE=/etc/mapserver/wms.map
    restart: unless-stopped

networks:
  default:
    external: true
    name: web_services
Relevant documentation


If everything is set up properly, you should be able to start your MapServer instance with