Publish¶
- HTTPS
You can easily publish your map service via HTTPS.
HTTPS is also required for HTTP/2, which also speeds up the map display by allowing more requests at once.
- CORS
Cross-Origin Resource Sharing restricts the websites that are allowed to embed your hosted resources.
Warning
Avoid wildcards
*
forAccess-Control-Allow-Origin
in productive use.- Map resources
Even if your PMTiles archives or tile endpoints originate from your own infrastructure, other resources on a web map may originate from external providers. These include JavaScript libraries, CSS stylesheets and fonts.
- Content security policy
By defining a content security policy via an HTTP header or an HTML meta tag, you can ensure that all resources on the HTML page come from the same source, for example for MapLibre:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'nonce-n0nce' 'nonce-n0nce1'; worker-src blob: ; child-src blob: ; img-src data: blob: ;" />
Example¶
Below you will find a complete example of a map application in which third-party sources are avoided:
1<html>
2 <head>
3 <meta charset="utf-8"/>
4 <meta
5 http-equiv="Content-Security-Policy"
6 content="default-src 'self' 'nonce-n0nce' 'nonce-n0nce1'; worker-src blob: ; child-src blob: ; img-src data: blob: ;" />
7 <link rel="stylesheet" href="maplibre-gl.css">
8 <script src="maplibre-gl.js"></script>
9 <script src="pmtiles.js"></script>
10 <script src="basemaps.js"></script>
11 </head>
12 <body>
13 <div id="map" style="height: 100%; width: 100%"></div>
14 <script type="text/javascript">
15 let protocol = new pmtiles.Protocol();
16 maplibregl.addProtocol("pmtiles", protocol.tile);
17 maplibregl.setRTLTextPlugin(
18 "mapbox-gl-rtl-text.min.js",
19 true,
20 );
21 const map = new maplibregl.Map({
22 container: "map",
23 zoom: 12,
24 center: [13.424233,52.534675],
25 style: {
26 glyphs: "fonts/{fontstack}/{range}.pbf",
27 sprite: "sprites/v4/light",
28 version: 8,
29 sources: {
30 protomaps: {
31 type: "vector",
32 url: "pmtiles://berlin.pmtiles",
33 attribution: '© <a href="https://openstreetmap.org">OpenStreetMap</a>'
34 },
35 },
36 layers: basemaps.layers("protomaps", basemaps.namedFlavor("light"), {lang: "en"})
37 },
38 });
39 </script>
40 </body>
41</html>
- Lines 7–10
maplibre-gl.js
andmaplibre-gl.css
are JavaScript and CSS for the MapLibre GL rendering library.pmtiles.js
is a JavaScript file for decoding PMTiles archives in the browser.basemaps.js
is a JavaScript file for creating a MapLibre GL style for a base map tile set.- Line 18
mapbox-gl-rtl-text.min. js
a MapLibre plugin for supporting languages written from right to left.- Lines 26–27
fonts/fontstack/range.pbf
are font glyphs for the display of labels, available under protomaps/basemaps-assets.sprites/version/{flavor_name
are Sprites for basemap icons, available under protomaps/basemaps-assets.- Line 32
pmtiles://berlin.pmtiles
is the archive file with the map data.
Cloud storage¶
PMTiles works on any S3-compatible cloud storage platform that supports HTTP Range Requests and `Cross-Origin Resource Sharing (CORS).
Upload¶
The pmtiles command line tool has
the pmtiles upload
command to transfer files to a cloud storage. RClone is another tool for managing large files on S3-compatible
storage:
rclone copyto FILENAME CONFIGURATION:BUCKET/FOLDER/FILENAME.pmtiles --progress --s3-chunk-size=256M
See also
Web-Server¶
Caddy¶
Caddy is highly recommended for the provision of
PMTiles due to its built-in HTTPS support. Uses the file_server
configuration to deploy *.pmtiles
from a static directory with the
following CORS configuration:
header {
Access-Control-Allow-Methods GET,HEAD
Access-Control-Expose-Headers ETag
Access-Control-Allow-Headers Range,If-Match
Access-Control-Allow-Origin https://www.cusy.io
}
Alternatively, you can use the pmtiles_proxy for Caddy.
nginx¶
nginx supports HTTP range requests, whereby the CORS headers and support for CORS preflight requests should be set in the configuration file:
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 3600;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Content-Length' 0;
return 204;
}