Howto use OpenBSD as a GIS server

Here's a quick howto to play a bit with some GIS data on OpenBSD (Well, most of this stuff is not OpenBSD-specific). The magic keywords and building bricks are :

In the following, i'll use my local server rhaalovely.net as example URL, you just have to replace it by your DNS. It this sounds boring to you, don't close the tab, there's a funky map at the bottom !

Install mapserver in OpenBSD's apache chroot

Quite simple, nothing more than the usual stuff in chroot. I assume that you already have the basis.. we need to copy PROJ4 files to the chroot, so mapserver recognizes geographical map projections, plus some depending libs.

# pkg_add mapserver
## from mapserver MESSAGE file
# mkdir -p /var/www/usr/local/share/{epsg_csv,proj}
# cp /usr/local/share/epsg_csv/* /var/www/usr/local/share/epsg_csv
# cp /usr/local/share/proj/* /var/www/usr/local/share/proj
## grab needed libs
# for i in `ldd /var/www/cgi-bin/mapserv | cut -c57- | grep usr | grep -v libexec` ; do sudo cp $i /var/www/usr/lib/ ; done

Now, time to test mapserver, fire up a browser and point it to http://rhaalovely.net/cgi-bin/mapserv. If the chroot stuff is okay, it should reply :

No query information to decode. QUERY_STRING is set, but empty.

Congratulations, mapserver is correctly installed.

Let's get some free GIS data

Now, i'm using SCAN1000 data available for download at IGN website. That's not a great data, but perfect for this example.

# mkdir /var/www/data ; cd /var/www/data
# ftp http://professionnels.ign.fr/DISPLAY/000/527/535/5275350/SCAN1000_FR_NE_L93.zip
# ftp http://professionnels.ign.fr/DISPLAY/000/527/535/5275350/SCAN1000_FR_NO_L93.zip
# ftp http://professionnels.ign.fr/DISPLAY/000/527/535/5275350/SCAN1000_FR_SO_L93.zip
# ftp http://professionnels.ign.fr/DISPLAY/000/527/535/5275350/SCAN1000_FR_SE_L93.zip
# ftp http://professionnels.ign.fr/DISPLAY/000/527/535/5275350/SCAN1000_Corse_L93.zip
# for i in *.zip ; do unzip $i ; rm $i ; done

Now, some magic with a GDAL tool, gdaltindex creates a vector data (a shapefile here) from the TIFF rasters. This shapefile will say 'ok, for this area, there's data to get from this TIFF file located here'.

# gdaltindex -write_absolute_path scan1000.shp *.TIF

## let's verify the shapefile content with another GDAL/OGR tool
# ogrinfo -al scan1000.shp
INFO: Open of `scan1000.shp'
      using driver `ESRI Shapefile' successful.

Layer name: scan1000
Geometry: Polygon
Feature Count: 5
Extent: (50000.000000, 6030000.000000) - (1250000.000000, 7130000.000000)
Layer SRS WKT:
(unknown)
location: String (255.0)
OGRFeature(scan1000):0
  location (String) = SC1000_0050_6580_L93.TIF
  POLYGON ((50000 6580000,600000 6580000,600000 6030000,50000 6030000,50000 6580000))

OGRFeature(scan1000):1
  location (String) = SC1000_0050_7130_L93.TIF
  POLYGON ((50000 7130000,600000 7130000,600000 6580000,50000 6580000,50000 7130000))

OGRFeature(scan1000):2
  location (String) = SC1000_0600_6580_L93.TIF
  POLYGON ((600000 6580000,1150000 6580000,1150000 6030000,600000 6030000,600000 6580000))

OGRFeature(scan1000):3
  location (String) = SC1000_0600_7130_L93.TIF
  POLYGON ((600000 7130000,1150000 7130000,1150000 6580000,600000 6580000,600000 7130000))

OGRFeature(scan1000):4
  location (String) = SC1000_1150_6240_L93.TIF
  POLYGON ((1150000 6240000,1250000 6240000,1250000 6030000,1150000 6030000,1150000 6240000))

Ok, we have some TIFF rasters, a shapefile to reference them, from now on we can even open it in QGIS. But that's local, and our goal is to go wild on teh intarweb.

Write a mapfile for mapserver

Mapfiles are used by mapserver to read, organize, and display GIS data, served either through WMS, or directly converted to images for web publication. Here's the one we're going to use, comments inline.

MAP
	# our data uses Lambert 93 projection, EPSG code 2154
	PROJECTION
		"init=epsg:2154"
	END
	# bounding box of the data (= area covered)
	EXTENT 50000 6030000 1250000 7130000

	WEB
		METADATA
			# where to ask for images after getCapabilities.. warning, map path is relative to chroot!
			"wms_onlineresource" "http://rhaalovely.net/cgi-bin/mapserv?map=/data/scan1000.map&"
			# necessary since mapserver 6.0
			"ows_enable_request"   "*"
		END
	END

	LAYER
	# serving one layer, named Scan1000
	NAME "Scan1000"
	STATUS ON
	# the 'tile index' file, and where to find the raster files (in 'location' field)
	TILEINDEX "/data/scan1000.shp"
	TILEITEM "location"
	TYPE RASTER
	END
END

That's it ! Now, you can try to get the 'Capabilities' of the mapfile opening this url : http://rhaalovely.net/cgi-bin/mapserv?map=/data/scan1000.map&version=1.1.1&service=WMS&request=GetCapabilities. This will return an xml file, giving all the available layers at this URL.

Now, even crazier, let's try it in QGIS, which can act as WMS client. Fire up QGIS, Layers, Add WMS layer, new, name the layer 'whatever', and enter the following URL : http://rhaalovely.net/cgi-bin/mapserv?map=/data/scan1000.map. Validate, connect, it should propose you the Scan1000 layer. Validate, wait a bit for mapserver to process the request.. BOOM, the france map appears!

Go wild on the web with Openlayers

Finally, let's do some cool stuff with the JS supa-dupa client GIS lib OpenLayers. The following HTML/JS code (check page source if you don't believe it) :

<head>
<script src="http://openlayers.org/api/OpenLayers.js"> </script>
<script type="text/javascript">
var map = null;
function init(){
	map = new OpenLayers.Map('map',
		{projection: 'epsg:2154',
		resolutions: [1000,500,250,100,50],
		maxExtent: new OpenLayers.Bounds(50000,6030000,1250000,7130000)});
	var wms = new OpenLayers.Layer.WMS("Local WMS",
		"http://rhaalovely.net/cgi-bin/mapserv?map=/data/scan1000.map",
		{layers: 'Scan1000'});

	map.addLayers([wms]);
	map.addControl(new OpenLayers.Control.MousePosition());
	map.setCenter(new OpenLayers.LonLat(712000,6508100),3);
}
</script>
</head>
<body onload="init()">
<div id="map" style="padding:10px; display:block; border:1px solid; width:800px; height:600px;"></div>
</body>

produces this funky result :

Check Examples and library doc for more stuff.

Ending words

Some cools things to do from now on : And lots of other stuff..