Skip to main content
the packages tilelive and mbtiles have moved
Source Link
  1. Install Node.js

  2. Grab the node packages with npm install @mapbox/tilelive @mapbox/mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

  1. Install Node.js

  2. Grab the node packages with npm install tilelive mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

  1. Install Node.js

  2. Grab the node packages with npm install @mapbox/tilelive @mapbox/mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

  1. Install Node.js

  2. Grab the node packages with npm install tilelive mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

  1. Install Node.js

  2. Grab the node packages with npm install tilelive mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

  1. Install Node.js

  2. Grab the node packages with npm install tilelive mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     //Depending on the OS the path might need to be 'mbtiles:///' on OS X and linux
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.

Source Link
Andreas Bilger
  • 1.9k
  • 2
  • 13
  • 12

As pointed out by @Greg, instead of TileStream (my first attempt) you should use Tilelive to host your own vector tiles.

Tilelive isn't a server itself but a backend framework that deals with tiles in different formats from different sources. But it's based on Node.js so you can turn it into a server in a pretty straight-forward way. To read tiles from a .mbtiles source as exported by Mapbox Studio, you need the node-mbtiles tilelive module.

Side note: Current Mapbox Studio has a bug under Windows and OS X that prevents an exported .mbtiles file to show up at your chosen destination. Workaround: Just grab the latest export-xxxxxxxx.mbtiles file in ~/.mapbox-studio/cache.

I found two server implementations (ten20 tile server by alexbirkett and TileServer by hanchao) who both use Express.js as a web app server.

Here is my minimalistic approach which is loosely based on these implementations:

  1. Install Node.js

  2. Grab the node packages with npm install tilelive mbtiles express

  3. Implement the server in the file server.js:

     var express = require('express');
     var http = require('http');
     var app = express();
     var tilelive = require('tilelive');
     require('mbtiles').registerProtocols(tilelive);
    
     tilelive.load('mbtiles://path/to/osm_roads.mbtiles', function(err, source) {
    
         if (err) {
             throw err;
         }
         app.set('port', 7777);
    
         app.use(function(req, res, next) {
             res.header("Access-Control-Allow-Origin", "*");
             res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
             next();
         });
    
         app.get(/^\/v2\/tiles\/(\d+)\/(\d+)\/(\d+).pbf$/, function(req, res){
    
             var z = req.params[0];
             var x = req.params[1];
             var y = req.params[2];
    
             console.log('get tile %d, %d, %d', z, x, y);
    
             source.getTile(z, x, y, function(err, tile, headers) {
                 if (err) {
                     res.status(404)
                     res.send(err.message);
                     console.log(err.message);
                 } else {
                   res.set(headers);
                   res.send(tile);
                 }
             });
         });
    
         http.createServer(app).listen(app.get('port'), function() {
             console.log('Express server listening on port ' + app.get('port'));
         });
     });
    

    Note: The Access-Control-Allow-... headers enable cross-origin resource sharing (CORS) so webpages served from a different server may access the tiles.

  4. Run it with node server.js

  5. Set up the webpage using Mapbox GL JS in minimal.html:

     <!DOCTYPE html >
     <html>
       <head>
         <meta charset='UTF-8'/>
         <title>Mapbox GL JS rendering my own tiles</title>
         <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.css' rel='stylesheet' />
         <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.4.0/mapbox-gl.js'></script>
         <style>
           body { margin:0; padding:0 }
           #map { position:absolute; top:0; bottom:50px; width:100%; }
         </style>
       </head>
       <body>
         <div id='map'>
         </div>
         <script>
           var map = new mapboxgl.Map({
             container: 'map',
             center: [46.8, 8.5],
             zoom: 7,
             style: 'minimal.json'
           });
         </script>
       </body>
     </html>
    
  6. Indicate the location of the tile source and style the layers with the following minimal.json:

     {
       "version": 6,
       "constants": {
         "@background": "#808080",
         "@road": "#000000"
       },
       "sources": {
         "osm_roads": {
           "type": "vector",
           "tiles": [
             "http://localhost:7777/v2/tiles/{z}/{x}/{y}.pbf"
           ],
           "minzoom": 0,
           "maxzoom": 12
         }
       },
       "layers": [{
         "id": "background",
         "type": "background",
         "paint": {
           "background-color": "@background"
         }
       }, {
         "id": "roads",
         "type": "line",
         "source": "osm_roads",
         "source-layer": "roads",
         "paint": {
           "line-color": "@road"
         }
       }]
     }
    
  7. Serve the webpage and rejoice.