## File: README.md

# TileServer GL
[](https://github.com/maptiler/tileserver-gl/actions/workflows/pipeline.yml)
[](https://hub.docker.com/r/maptiler/tileserver-gl/)

Vector and raster maps with GL styles. Server-side rendering by MapLibre GL Native. Map tile server for MapLibre GL JS, Android, iOS, Leaflet, OpenLayers, GIS via WMTS, etc.

Download vector tiles from [OpenMapTiles](https://data.maptiler.com/downloads/planet/).
## Getting Started with Node

Make sure you have Node.js version **20** or above installed. Node 24 is recommended. (running `node -v` it should output something like `v24.x.x`). Running without docker requires [Native dependencies](https://maptiler-tileserver.readthedocs.io/en/latest/installation.html#npm) to be installed first.

Install `tileserver-gl` with server-side raster rendering of vector tiles with npm. 

```bash
npm install tileserver-gl
```

Once installed, you can use it like the following examples.

using a mbtiles file
```bash
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/zurich_switzerland.mbtiles
tileserver-gl --file zurich_switzerland.mbtiles
[in your browser, visit http://[server ip]:8080]
```

using a config.json + style + mbtiles file
```bash
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip
unzip test_data.zip
tileserver-gl
[in your browser, visit http://[server ip]:8080]
```

Alternatively, you can use the `tileserver-gl-light` npm package instead, which is pure javascript, does not have any native dependencies, and can run anywhere, but does not contain rasterization on the server side made with Maplibre GL Native.

## Getting Started with Docker

An alternative to npm to start the packed software easier is to install [Docker](https://www.docker.com/) on your computer and then run from the tileserver-gl directory

Example using a mbtiles file
```bash
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/zurich_switzerland.mbtiles
docker run --rm -it -v $(pwd):/data -p 8080:8080 maptiler/tileserver-gl:latest --file zurich_switzerland.mbtiles
[in your browser, visit http://[server ip]:8080]
```

Example using a config.json + style + mbtiles file
```bash
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip
unzip test_data.zip
docker run --rm -it -v $(pwd):/data -p 8080:8080 maptiler/tileserver-gl:latest
[in your browser, visit http://[server ip]:8080]
```

Example using a different path
```bash
docker run --rm -it -v /your/local/config/path:/data -p 8080:8080 maptiler/tileserver-gl:latest
```
replace '/your/local/config/path' with the path to your config file


Alternatively, you can use the `maptiler/tileserver-gl-light:latest` docker image instead, which is pure javascript, does not have any native dependencies, and can run anywhere, but does not contain rasterization on the server side made with Maplibre GL Native.

## Getting Started with Linux cli

Test from command line
```bash
wget https://github.com/maptiler/tileserver-gl/releases/download/v1.3.0/test_data.zip
unzip -q test_data.zip -d test_data
xvfb-run --server-args="-screen 0 1024x768x24" npm test
```

Run from command line
```bash
xvfb-run --server-args="-screen 0 1024x768x24" node .
```

## Documentation

You can read the full documentation of this project at https://tileserver.readthedocs.io/en/latest/.

## Security: Host header poisoning (HNP) mitigation

When the server is started **without** `--public_url`, URLs in responses (WMTS, TileJSON, style JSON) are built from the request’s `Host` and `X-Forwarded-*` headers. If an attacker can influence these headers, the server may return URLs pointing to an attacker-controlled host (Host header poisoning). Clients that use those URLs can then be directed to malicious servers.

**Recommended for production:**

1. **Set a canonical public URL** so the server never derives host from the request:
   ```bash
   tileserver-gl --public_url https://your-domain.com/ --file your.mbtiles
   ```

2. **Or** restrict which hosts are allowed when not using `--public_url`, via the **allowed-hosts** list (default is `*`, i.e. no restriction):
   - Set the environment variable **`TILESERVER_GL_ALLOWED_HOSTS`** to a comma-separated list of allowed hostnames (e.g. `localhost,myapp.example.com`). If the request’s host (or `X-Forwarded-Host`) is not in this list, the server returns **path-only** URLs instead of absolute URLs, so responses cannot be poisoned with an attacker’s host.
   - Example:
     ```bash
     export TILESERVER_GL_ALLOWED_HOSTS="localhost,map.example.com"
     tileserver-gl --file your.mbtiles
     ```
   - If you do not set this variable (or set it to `*`), behavior is unchanged and all hosts are accepted; for public-facing deployments you should either use `--public_url` or set `TILESERVER_GL_ALLOWED_HOSTS` to your known host(s). See [SECURITY.md](SECURITY.md) for details.

## Alternative

Discover MapTiler Server if you need a [map server with easy setup and user-friendly interface](https://www.maptiler.com/server/).

---

## File: docs/config.rst

==================
Configuration file
==================

The configuration file defines the behavior of the application. It's a regular JSON file.

Example:

.. code-block:: json

  {
    "options": {
      "paths": {
        "root": "",
        "fonts": "fonts",
        "sprites": "sprites",
        "icons": "icons",
        "styles": "styles",
        "mbtiles": "data",
        "pmtiles": "data",
        "files": "files"
      },
      "domains": [
        "localhost:8080",
        "127.0.0.1:8080"
      ],
      "allowedHosts": "localhost,myapp.example.com",
      "formatOptions": {
        "jpeg": {
          "quality": 80
        },
        "webp": {
          "quality": 90
        }
      },
      "maxScaleFactor": 3,
      "maxSize": 2048,
      "pbfAlias": "pbf",
      "serveAllFonts": false,
      "serveAllStyles": false,
      "serveStaticMaps": true,
      "allowRemoteMarkerIcons": true,
      "allowInlineMarkerImages": true,
      "staticAttributionText": "© OpenMapTiles  © OpenStreetMaps",
      "tileMargin": 0
    },
    "styles": {
      "basic": {
        "style": "basic.json",
        "tilejson": {
          "type": "overlay",
          "bounds": [8.44806, 47.32023, 8.62537, 47.43468]
        }
      },
      "hybrid": {
        "style": "satellite-hybrid.json",
        "serve_rendered": false,
        "tilejson": {
          "format": "webp"
        }
      },
      "remote": {
        "style": "https://demotiles.maplibre.org/style.json"
      }
    },
    "data": {
      "zurich-vector": {
        "mbtiles": "zurich.mbtiles"
      }
    }
  }


``options``
===========

``paths``
---------

Defines where to look for the different types of input data.

The value of ``root`` is used as prefix for all data types.

``domains``
-----------

You can use this to optionally specify on what domains the rendered tiles are accessible. This can be used for basic load-balancing or to bypass browser's limit for the number of connections per domain.

``frontPage``
-----------------

Path to the html (relative to ``root`` path) to use as a front page.

Use ``true`` (or nothing) to serve the default TileServer GL front page with list of styles and data.
Use ``false`` to disable the front page altogether (404).

``formatOptions``
-----------------

You can use this to specify options for the generation of images in the supported file formats.
For WebP, the only supported option is ``quality`` [0-100].
For JPEG, the only supported options are ``quality`` [0-100] and ``progressive`` [true, false]. 
For PNG, the full set of options `exposed by the sharp library <https://sharp.pixelplumbing.com/api-output#png>`_ is available, except ``force`` and ``colours`` (use ``colors``). If not set, their values are the defaults from ``sharp``.

For example::

  "formatOptions": {
    "png": {
      "palette": true,
      "colors": 4
    }
  }

Note: ``formatOptions`` replaced the ``formatQuality`` option in previous versions of TileServer GL. 

``maxScaleFactor``
-----------

Maximum scale factor to allow in raster tile and static maps requests (e.g. ``@3x`` suffix).
Also see ``maxSize`` below.
Default value is ``3``, maximum ``9``.

``maxSize``
-----------

Maximum image side length to be allowed to be rendered (including scale factor).
Be careful when changing this value since there are hardware limits that need to be considered.
Default is ``2048``.

``tileMargin``
--------------

Additional image side length added during tile rendering that is cropped from the delivered tile. This is useful for resolving the issue with cropped labels,
but it does come with a performance degradation, because additional, adjacent vector tiles need to be loaded to generate a single tile.
Default is ``0`` to disable this processing.

``minRendererPoolSizes``
------------------------

Minimum amount of raster tile renderers per scale factor.
The value is an array: the first element is the minimum amount of renderers for scale factor one, the second for scale factor two and so on.
If the array has less elements than ``maxScaleFactor``, then the last element is used for all remaining scale factors as well.
Selecting renderer pool sizes is a trade-off between memory use and speed.
A reasonable value will depend on your hardware and your amount of styles and scale factors.
If you have plenty of memory, you'll want to set this equal to ``maxRendererPoolSizes`` to avoid increased latency due to renderer destruction and recreation.
If you need to conserve memory, you'll want something lower than ``maxRendererPoolSizes``, possibly allocating more renderers to scale factors that are more common.
Default is ``[8, 4, 2]``.

``maxRendererPoolSizes``
------------------------

Maximum amount of raster tile renderers per scale factor.
The value and considerations are similar to ``minRendererPoolSizes`` above.
If you have plenty of memory, try setting these equal to or slightly above your processor count, e.g. if you have four processors, try a value of ``[6]``.
If you need to conserve memory, try lower values for scale factors that are less common.
Default is ``[16, 8, 4]``.

``pbfAlias``
------------------------

Some CDNs did not handle .pbf extension as a static file correctly.
The default URLs (with .pbf) are always available, but an alternative can be set.
An example extension suffix would be ".pbf.pict".

``serveAllFonts``
------------------------

If this option is enabled, all the fonts from the ``paths.fonts`` will be served.
Otherwise only the fonts referenced by available styles will be served.

``serveAllStyles``
------------------------

If this option is enabled, all the styles from the ``paths.styles`` will be served. (No recursion, only ``.json`` files are used.)
The process will also watch for changes in this directory and remove/add more styles dynamically.
It is recommended to also use the ``serveAllFonts`` option when using this option.

``leafletRetina``
------------------------

If this option is enabled, the Leaflet raster map viewer will attempt to fetch high-resolution (Retina, ``@2x``) tiles for high-DPI displays.
Disable this if you want to reduce CPU/memory load and bandwidth when users are primarily utilizing the basic raster map viewer.
Default is ``false``.

``serveStaticMaps``
------------------------

If this option is enabled, all the static map endpoints will be served.
Default is ``true``.

``watermark``
-----------

Optional string to be rendered into the raster tiles and static maps as watermark (bottom-left corner).
Not used by default.

``staticAttributionText``
-----------

Optional string to be rendered in the static images endpoint. Text will be rendered in the bottom-right corner,
and styled similar to attribution on web-based maps (text only, links not supported).
Not used by default.

``allowRemoteMarkerIcons``
--------------

Allows the rendering of marker icons fetched via http(s) hyperlinks.
For security reasons only allow this if you can control the origins from where the markers are fetched!
Default is to disallow fetching of icons from remote sources.

``allowInlineMarkerImages``
--------------
Allows the rendering of inline marker icons or base64 urls.
For security reasons only allow this if you can control the origins from where the markers are fetched!
Not used by default.


``styles``
==========

Each item in this object defines one style (map). It can have the following options:

* ``style`` -- name of the style json file or url of a remote hosted style [required]
* ``serve_rendered`` -- whether to render the raster tiles for this style or not
* ``serve_data`` -- whether to allow access to the original tiles, sprites and required glyphs
* ``tilejson`` -- properties to add to the TileJSON created for the raster data

  * ``format`` and ``bounds`` can be especially useful

``data``
========

Each item specifies one data source which should be made accessible by the server. It has to have one of the following options:

* ``mbtiles`` -- name of the mbtiles file
* ``pmtiles`` -- name of the pmtiles file, url, or S3 path.

For example::

  "data": {
    "source1": {
      "mbtiles": "source1.mbtiles"
    },
    "source2": {
      "pmtiles": "source2.pmtiles"
    },
    "source3": {
      "pmtiles": "https://foo.lan/source3.pmtiles"
    },
    "source4": {
      "pmtiles": "s3://my-bucket/tiles/terrain.pmtiles"
    }
  }

The data source does not need to be specified here unless you explicitly want to serve the raw data.

Data Source Options
--------------

Within the top-level ``data`` object in your configuration, each defined data source (e.g., `terrain`, `vector_tiles`) can have several key properties. These properties define how *tileserver-gl* processes and serves the tiles from that source.

For example::

  "data": {
    "terrain": {
      "mbtiles": "terrain1.mbtiles",
      "encoding": "mapbox",
      "tileSize": 512
    },
    "vector_tiles": {
      "pmtiles": "custom_osm.pmtiles"
    },
    "production-s3-tiles": {
      "pmtiles": "s3://prod-bucket/tiles.pmtiles",
      "s3Profile": "production"
    }
  }

Here are the available options for each data source:

``encoding`` (string)
    Applicable to terrain tiles. Configures the expected encoding of the terrain data.
    Setting this to ``mapbox`` or ``terrarium`` enables a terrain preview mode and the ``elevation`` API for the ``data`` endpoint (if applicable to the source).

``tileSize`` (integer)
    Specifies the expected pixel dimensions of the tiles within this data source.
    This option is crucial if your source data uses 512x512 pixel tiles, as *tileserver-gl* typically assumes 256x256 by default.
    Allowed values: ``256``, ``512``.
    Default: ``256``.

``sparse`` (boolean)
    Controls behavior when a tile is not found in the source.

    * ``true`` - Returns HTTP 404, allowing clients like MapLibre to overzoom and use parent tiles. Use this for terrain or datasets with uneven zoom coverage.
    * ``false`` - Returns HTTP 204 (No Content), signaling an intentionally empty tile and preventing overzoom.

    This can be set globally in the top-level options or per-data-source (per-source overrides global).
    Default: Depends on tile format - ``false`` for vector tiles (pbf), ``true`` for raster tiles (png, webp, jpg, etc.).

``s3Profile`` (string)
    Specifies the AWS credential profile to use for S3 PMTiles sources. The profile must be defined in your ``~/.aws/credentials`` file.
    This is useful when you need to access multiple S3 buckets with different credentials.
    Alternatively, you can specify the profile in the URL using ``?profile=profile-name``.
    If both are specified, the configuration ``s3Profile`` takes precedence.
    Optional, only applicable to PMTiles sources using S3 URLs.

``requestPayer`` (boolean)
    Enables support for "requester pays" S3 buckets where the requester (not the bucket owner) pays for data transfer costs.
    Set to ``true`` if accessing a requester pays bucket.
    Can be specified in the URL using ``?requestPayer=true`` or in the configuration.
    If both are specified, the configuration value takes precedence.
    Default: ``false``.
    Optional, only applicable to PMTiles sources using S3 URLs.

``s3Region`` (string)
    Specifies the AWS region for the S3 bucket.
    Important for optimizing performance and reducing data transfer costs when accessing AWS S3 buckets.
    Can be specified in the URL using ``?region=region-name`` or in the configuration.
    If both are specified, the configuration value takes precedence.
    If not specified, uses ``AWS_REGION`` environment variable or defaults to ``us-east-1``.
    Optional, only applicable to PMTiles sources using S3 URLs.

``s3UrlFormat`` (string)
    Specifies how to interpret the S3 URL format.
    
    Allowed values:
    
    * ``aws`` - Interpret as AWS S3 (``s3://bucket/path/file.pmtiles``)
    * ``custom`` - Interpret as custom S3 endpoint (``s3://endpoint/bucket/path/file.pmtiles``)
    * Not specified (default) - Auto-detect based on URL pattern
    
    Can be specified in the URL using ``?s3UrlFormat=aws`` or in the configuration.
    If both are specified, the configuration value takes precedence.
    
    Optional, only applicable to PMTiles sources using S3 URLs.

.. note::
    By default, URLs with dots in the first segment (e.g., ``s3://storage.example.com/bucket/file.pmtiles``) are treated as custom endpoints, while URLs without dots are treated as AWS S3. Use ``s3UrlFormat: "aws"`` if your AWS bucket name contains dots.

.. note::
    These configuration options will be overridden by metadata in the MBTiles or PMTiles file. if corresponding properties exist in the file's metadata, you do not need to specify them in the data configuration.

Referencing local files from style JSON
=======================================

You can link various data sources from the style JSON (for example even remote TileJSONs).

MBTiles
-------

To specify that you want to use local mbtiles, use to following syntax: ``mbtiles://source1.mbtiles``.
TileServer-GL will try to find the file ``source1.mbtiles`` in ``root`` + ``mbtiles`` path.

For example::

  "sources": {
    "source1": {
      "url": "mbtiles://source1.mbtiles",
      "type": "vector"
    }
  }

Alternatively, you can use ``mbtiles://{source1}`` to reference existing data object from the config.
In this case, the server will look into the ``config.json`` to determine what file to use by data id.
For the config above, this is equivalent to ``mbtiles://source1.mbtiles``.

PMTiles
-------

To specify that you want to use local pmtiles, use to following syntax: ``pmtiles://source2.pmtiles``.
TileServer-GL will try to find the file ``source2.pmtiles`` in ``root`` + ``pmtiles`` path.

To specify that you want to use a url based pmtiles, use to following syntax: ``pmtiles://https://foo.lan/source3.pmtiles``.

For example::

  "sources": {
    "source2": {
      "url": "pmtiles://source2.pmtiles",
      "type": "vector"
    },
    "source3": {
      "url": "pmtiles://https://foo.lan/source3.pmtiles",
      "type": "vector"
    }
  }

Alternatively, you can use ``pmtiles://{source2}`` to reference existing data object from the config.
In this case, the server will look into the ``config.json`` to determine what file to use by data id.
For the config above, this is equivalent to ``pmtiles://source2.pmtiles``.

S3 and S3-Compatible Storage
-----------------------------

PMTiles files can be accessed directly from AWS S3 or S3-compatible storage services (such as Contabo, DigitalOcean Spaces, MinIO, etc.) using S3 URLs. This provides better performance and eliminates HTTP rate limiting issues.

**Supported URL Formats:**

1. **AWS S3 (default):**
   ``s3://bucket-name/path/to/file.pmtiles``

2. **S3-compatible storage with custom endpoint:**
   ``s3://endpoint-url/bucket-name/path/to/file.pmtiles``

**AWS Credentials:**

S3 sources require AWS credentials to be configured. The server will automatically use credentials from:

* Environment variables: ``AWS_ACCESS_KEY_ID``, ``AWS_SECRET_ACCESS_KEY``, ``AWS_REGION``
* AWS credentials file: ``~/.aws/credentials`` on Linux/macOS or ``C:\Users\USERNAME\.aws\credentials`` on Windows
* IAM role (when running on AWS EC2, ECS, or Lambda)

For S3-compatible storage providers, use the same AWS credential format with your provider's access keys.

Example using environment variables::

  export AWS_ACCESS_KEY_ID=your_access_key
  export AWS_SECRET_ACCESS_KEY=your_secret_key
  export AWS_REGION=us-west-2

**Multiple AWS Credential Profiles:**

If you need to access S3 buckets with different credentials, you can use AWS credential profiles. Profiles are defined in your AWS credentials file (``~/.aws/credentials`` on Linux/macOS or ``C:\Users\USERNAME\.aws\credentials`` on Windows)::

  [default]
  aws_access_key_id=YOUR_DEFAULT_KEY
  aws_secret_access_key=YOUR_DEFAULT_SECRET

  [production]
  aws_access_key_id=YOUR_PRODUCTION_KEY
  aws_secret_access_key=YOUR_PRODUCTION_SECRET

  [staging]
  aws_access_key_id=YOUR_STAGING_KEY
  aws_secret_access_key=YOUR_STAGING_SECRET

**S3 Configuration Options (Main Config Data Section):**

When configuring S3 sources in the main configuration file's ``data`` section, you can use URL query parameters or configuration properties. Configuration properties take precedence over URL parameters.

*Profile* - Specifies which AWS credential profile to use::

  # URL parameter
  "pmtiles": "s3://bucket/tiles.pmtiles?profile=production"
  
  # Configuration property
  "pmtiles": "s3://bucket/tiles.pmtiles",
  "s3Profile": "production"

Precedence order (highest to lowest): Configuration property ``s3Profile``, URL parameter ``?profile=...``, default AWS credential chain.

*Region* - Specifies the AWS region (important for performance and cost optimization)::

  # URL parameter
  "pmtiles": "s3://bucket/tiles.pmtiles?region=us-west-2"
  
  # Configuration property
  "pmtiles": "s3://bucket/tiles.pmtiles",
  "s3Region": "us-west-2"

Precedence order (highest to lowest): Configuration property ``s3Region``, URL parameter ``?region=...``, Environment variable ``AWS_REGION``, Default: ``us-east-1``.

*RequestPayer* - Enables "requester pays" buckets where you pay for data transfer::

  # URL parameter
  "pmtiles": "s3://bucket/tiles.pmtiles?requestPayer=true"
  
  # Configuration property
  "pmtiles": "s3://bucket/tiles.pmtiles",
  "requestPayer": true

Precedence order (highest to lowest): Configuration property ``requestPayer``, URL parameter ``?requestPayer=true``, Default: ``false``.

*S3UrlFormat* - Specifies how to interpret S3 URLs::

  # URL parameter
  "pmtiles": "s3://my.bucket.name/tiles.pmtiles?s3UrlFormat=aws"
  
  # Configuration property
  "pmtiles": "s3://my.bucket.name/tiles.pmtiles",
  "s3UrlFormat": "aws"

Precedence order (highest to lowest): Configuration property ``s3UrlFormat``, URL parameter ``?s3UrlFormat=...``, Auto-detection.

**Complete Configuration Examples:**

Using URL parameters::

  "data": {
    "us-west-tiles": {
      "pmtiles": "s3://prod-bucket/tiles.pmtiles?profile=production&region=us-west-2"
    },
    "dotted-bucket-name": {
      "pmtiles": "s3://my.bucket.name/tiles.pmtiles?s3UrlFormat=aws&region=us-east-1"
    },
    "eu-requester-pays": {
      "pmtiles": "s3://bucket/tiles.pmtiles?profile=prod&region=eu-central-1&requestPayer=true"
    }
  }

Using configuration properties (recommended)::

  "data": {
    "us-west-tiles": {
      "pmtiles": "s3://prod-bucket/tiles.pmtiles",
      "s3Profile": "production",
      "s3Region": "us-west-2"
    },
    "dotted-bucket-name": {
      "pmtiles": "s3://my.bucket.name/tiles.pmtiles",
      "s3UrlFormat": "aws",
      "s3Region": "us-east-1"
    },
    "eu-requester-pays": {
      "pmtiles": "s3://bucket/tiles.pmtiles",
      "s3Profile": "production",
      "s3Region": "eu-central-1",
      "requestPayer": true
    }
  }

**Using S3 in Style JSON Sources:**

When referencing S3 sources from within a style JSON file, use the ``pmtiles://`` prefix with S3 URLs. You can specify profile, region, requestPayer, and s3UrlFormat using URL query parameters (configuration properties are not available in style JSON)::

  "sources": {
    "aws-tiles": {
      "url": "pmtiles://s3://my-bucket/tiles.pmtiles?profile=production",
      "type": "vector"
    },
    "dotted-bucket": {
      "url": "pmtiles://s3://my.bucket.name/tiles.pmtiles?s3UrlFormat=aws",
      "type": "vector"
    },
    "spaces-tiles": {
      "url": "pmtiles://s3://example-storage.com/my-bucket/tiles.pmtiles?region=nyc3",
      "type": "vector"
    }
  }

Sprites
-------

If your style requires any sprites, make sure the style JSON contains proper path in the ``sprite`` property.

It can be a local path (e.g. ``my-style/sprite``) or remote http(s) location (e.g. ``https://mycdn.com/my-style/sprite``). Several possible extension are added to this path, so the following files should be present:

* ``sprite.json``
* ``sprite.png``
* ``sprite@2x.json``
* ``sprite@2x.png``

You can also use the following placeholders in the sprite path for easier use:

* ``{style}`` -- gets replaced with the name of the style file (``xxx.json``)
* ``{styleJsonFolder}`` -- gets replaced with the path to the style file

Fonts (glyphs)
--------------

Similarly to the sprites, the style JSON also needs to contain proper paths to the font glyphs (in the ``glyphs`` property) and can be both local and remote.

It should contain the following placeholders:

* ``{fontstack}`` -- name of the font and variant
* ``{range}`` -- range of the glyphs

For example ``"glyphs": "{fontstack}/{range}.pbf"`` will instruct TileServer-GL to look for the files such as ``fonts/Open Sans/0-255.pbf`` (``fonts`` come from the ``paths`` property of the ``config.json`` example above).

``allowedHosts``
----------------

Mitigates Host header poisoning (HNP) by restricting which hosts may appear in absolute URLs returned by the server. If set, only the specified hosts (case-insensitive, comma-separated) are allowed; otherwise, path-only URLs are returned when the request host is not in the list. Default is ``*`` (no restriction).

You can set this option in your config file:

.. code-block:: json

  {
    "options": {
      "allowedHosts": "localhost,myapp.example.com"
      // ...other options...
    }
  }

If unset or set to ``*``, behavior is unchanged and all hosts are accepted. For production, set ``allowedHosts`` to your known host(s) or use ``public_url`` for a fixed base URL. This option can also be set via the ``TILESERVER_GL_ALLOWED_HOSTS`` environment variable, but config file takes priority if both are set.

See also: ``public_url`` option and security documentation.

---

## File: docs/deployment.rst

==========
Deployment
==========

Typically, you should use nginx, lighttpd or apache on the frontend. The tileserver-gl server is hidden behind it in production deployment.

.. _security-hnp:

Host header poisoning (HNP) mitigation
-------------------------------------
When tileserver-gl is run **without** ``--public_url``, it builds URLs in responses from the request's Host and X-Forwarded-* headers. If untrusted clients can influence these headers, the server may return URLs pointing to an attacker's host. For production:

1. **Recommended:** Set a canonical public URL so the server never uses the request to build URLs: ``--public_url https://your-domain.com/``.
2. **Or** restrict allowed hosts using either the **allowedHosts** config option or the **TILESERVER_GL_ALLOWED_HOSTS** environment variable:
  - In your config file, set ``allowedHosts`` under ``options`` to a comma-separated list of allowed hostnames (e.g. ``localhost,map.example.com``).
  - Or set the environment variable **TILESERVER_GL_ALLOWED_HOSTS** to a comma-separated list.
  - If the request host is not in this list, the server returns path-only URLs (no host in response).
  - Default is ``*`` (no restriction). The config option takes priority if both are set.
  - See the repository's SECURITY.md for details.

Caching
=======

There is a plenty of options you can use to create proper caching infrastructure: Varnish, Cloudflare, ...

Cloudflare Cache Rules
-----------

Cloudflare supports custom rules for configuring caching:
https://developers.cloudflare.com/cache/about/cache-rules/

tileserver-gl renders tiles in multiple formats - ``.png``, ``.jpg (jpeg)``, ``.webp`` for the raster endpoints, ``.pbf`` for vector endpoint. In addition, style information is generated with ``.json`` format.

Endpoint data can be configured to be cached by Cloudflare. For example to cache vector endpoint you will need to configure Cloudflare rules for the ``.pbf`` and ``.json`` data.

Create a rule which matches ``hostname (equal)`` and ``URI Path (ends with)`` for ``.pbf`` and ``.json`` fields. Set cache status to eligible for cache to enable the caching and overwrite the ``Edge TTL`` with ``Browser TTL`` to be 7 days (depends on your application usage).

This will ensure that your tiles are cached on the client side and by Cloudflare for seven days. If the tileserver is down or user has no internet access it will try to use cached tiles.

Note that ``Browser TTL`` will overwrite expiration dates on the client device. If you rebuild your maps, old tiles will be rendered until it expires or cache is cleared on the client device.

Nginx Cache
-----------

If you have a reverse proxy setup in front of the tileserver you may want to enable caching as it will greatly offload requests from the application.

Configure the proxy cache path directive to initialize your cache store:

::

  proxy_cache_path /var/cache/nginx/tileserver
                   keys_zone=TileserverCache:50m
                   levels=1:2
                   inactive=2w
                   max_size=10g;

Make sure to give proper permissions for the /var/cache/nginx/tileserver folder. Usually nginx is running with www-data user.
Enable caching on specific proxy pass:

::

  location / {
    include proxy_params; 
    proxy_pass http://127.0.0.1:8080/;

    proxy_cache TileserverCache;
    proxy_cache_valid 200 1w;

    # add_header X-Cache-Status $upstream_cache_status;
  }

If you need to confirm whether caching works or not, uncomment the X-Cache-Status header. This will return a header on response with `HIT` or `MISS` header value which indicates if nginx cached the response or not.

Make sure to clean your cache by removing files in the configured directory after you change your styles or tile information. You may experiment with the caching values to fit your needs.

More about Nginx caching: https://docs.nginx.com/nginx/admin-guide/content-cache/content-caching/

Securing
========

Nginx can be used to add protection via https, password, referrer, IP address restriction, access keys, etc.

Running behind a proxy or a load-balancer
=========================================

If you need to run TileServer GL behind a proxy, make sure the proxy sends ``X-Forwarded-*`` headers to the server (most importantly ``X-Forwarded-Host`` and ``X-Forwarded-Proto``) to ensure the URLs generated inside TileJSON, etc. are using the desired domain and protocol.

Nginx Reverse Proxy
-----------

An example nginx reverse proxy server configuration for HTTPS connections. It enables caching, CORS and Cloudflare Authenticated Pulls.

::

  proxy_cache_path /var/cache/nginx/tileserver
                   keys_zone=TileserverCache:50m 
                   levels=1:2
                   inactive=2w
                   max_size=1g;

  map_hash_bucket_size 128;
  map $http_origin $allow_origin {
      https://www.example.com $http_origin;
      default "";
  }

  server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate         /etc/ssl/www.example.com/cert.pem;
    ssl_certificate_key     /etc/ssl/www.example.com/key.pem;

    # https://developers.cloudflare.com/ssl/origin-configuration/authenticated-origin-pull/
    ssl_client_certificate  /etc/ssl/cloudflare.pem;
    ssl_verify_client on;

    server_name www.example.com example.com;

    # Disable root application access. You may want to allow this in development.
    location ~ ^/$ {
      return 404;
    }

    # Disable root application access. You may want to allow this in development.
    location /favicon.ico {
      return 404;
    }

    location / {
      # This include directive sets up required headers for proxy and proxy cache.
      # As well it includes the required ``X-Forwarded-*`` headers for tileserver to properly generate tiles.
      include proxy_params;

      proxy_pass http://127.0.0.1:8080/;

      # Disable default CORS headers
      proxy_hide_header Access-Control-Allow-Origin;

      # Enable proxy cache
      proxy_cache TileserverCache;
      proxy_cache_valid 200 1w;

      # Set our custom CORS
      add_header 'Access-Control-Allow-Origin' $allow_origin;
      
      # If you need to see nginx cache status. Uncomment line below.
      # add_header X-Cache-Status $upstream_cache_status;
    }
  }

---

## File: docs/endpoints.rst

===================
Available endpoints
===================

If you visit the server on the configured port (default 8080) you can see your maps appearing in the browser.

Styles
======
* Styles are served at ``/styles/{id}/style.json`` (+ array at ``/styles.json``)

  * Sprites at ``/styles/{id}/sprite[/spriteID][@2x].{format}``
  * Fonts at ``/fonts/{fontstack}/{start}-{end}.pbf``

Rendered tiles
==============
* Rendered tiles are served at ``/styles/{id}[/{tileSize}]/{z}/{x}/{y}[@2x].{format}``

  * The optional ratio ``@2x`` (ex.  ``@2x``, ``@3x``, ``@4x``) part can be used to render HiDPI (retina) tiles
  * The optional tile size ``/{tileSize}`` (ex. ``/256``, ``/512``). if omitted, tileSize defaults to 256.
  * Available formats: ``png``, ``jpg`` (``jpeg``), ``webp``
  * TileJSON at ``/styles[/{tileSize}]/{id}.json``

* The rendered tiles are not available in the ``tileserver-gl-light`` version.

WMTS Capabilities
==============
* WMTS Capabilities are served at ``/styles/{id}/wmts.xml``

Static images
=============
* Several endpoints:

  * ``/styles/{id}/static/{lon},{lat},{zoom}[@{bearing}[,{pitch}]]/{width}x{height}[@2x].{format}`` (center-based)
  * ``/styles/{id}/static/{minx},{miny},{maxx},{maxy}/{width}x{height}[@2x].{format}`` (area-based)
  * ``/styles/{id}/static/auto/{width}x{height}[@2x].{format}`` (autofit path -- see below)

* All the static image endpoints additionally support following query parameters:

  * ``path`` - ``((fill|stroke|width)\:[^\|]+\|)*(enc:.+|-?\d+(\.\d*)?,-?\d+(\.\d*)?(\|-?\d+(\.\d*)?,-?\d+(\.\d*)?)+)``

    * comma-separated ``lng,lat``, pipe-separated pairs

      * e.g. ``path=5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8``

    * `Google Encoded Polyline Format <https://developers.google.com/maps/documentation/utilities/polylinealgorithm>`_

      * e.g. ``path=enc:_p~iF~ps|U_ulLnnqC_mqNvxq`@``
      * If 'enc:' is used, the rest of the path parameter is considered to be part of the encoded polyline string -- do not specify the coordinate pairs.

    * With options (fill|stroke|width)

      * e.g. ``path=stroke:yellow|width:2|fill:green|5.9,45.8|5.9,47.8|10.5,47.8|10.5,45.8|5.9,45.8`` or ``path=stroke:blue|width:1|fill:yellow|enc:_p~iF~ps|U_ulLnnqC_mqNvxq`@``

    * can be provided multiple times

  * ``latlng`` - indicates coordinates are in ``lat,lng`` order rather than the usual ``lng,lat`` for paths and markers
  * ``fill`` - default color to use as the fill (e.g. ``red``, ``rgba(255,255,255,0.5)``, ``#0000ff``) for all paths
  * ``stroke`` - default color of the path stroke for all paths
  * ``width`` - default width of the stroke for all paths
  * ``linecap`` - rendering style for the start and end points of all paths - see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap
  * ``linejoin`` - rendering style for joining successive segments of all paths when the direction changes - see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
  * ``border`` - color of the optional border stroke for all paths ; the border is like a halo around the stroke
  * ``borderwidth`` - width of the border stroke (default 10% of stroke width) for all paths
  * ``marker`` - Marker in format ``lng,lat|iconPath|option|option|...``

    * Will be rendered with the bottom center at the provided location
    * ``lng,lat`` and ``iconPath`` are mandatory and icons won't be rendered without them
    * ``iconPath`` is either a link to an image served via http(s) or a path to a file relative to the configured icon path
    * ``option`` must adhere to the format ``optionName:optionValue`` and supports the following names

      * ``scale`` - Factor to scale image by

        * e.g. ``0.5`` - Scales the image to half it's original size

      * ``offset`` - Image offset as positive or negative pixel value in format ``[offsetX],[offsetY]``

        * scales with ``scale`` parameter since image placement is relative to it's size
        * e.g. ``2,-4`` - Image will be moved 2 pixel to the right and 4 pixel in the upwards direction from the provided location

    * e.g. ``5.9,45.8|marker-icon.png|scale:0.5|offset:2,-4``
    * can be provided multiple times

  * ``padding`` - "percentage" padding for fitted endpoints (area-based and path autofit)

    * value of ``0.1`` means "add 10% size to each side to make sure the area of interest is nicely visible"

  * ``maxzoom`` - Maximum zoom level (only for auto endpoint where zoom level is calculated and not provided)

* All the static image endpoints support parameters passing using POST with a JSON body:

  * e.g. ``{"path": ["10,10|20,20", "10,20|20,10"]}`` is the equivalent of ``?path=10,10|20,20&path=10,20|20,10``

* You can also use (experimental) ``/styles/{id}/static/raw/...`` endpoints with raw spherical mercator coordinates (EPSG:3857) instead of WGS84.

* The static images are not available in the ``tileserver-gl-light`` version.

Source data
===========
* Source data are served at ``/data/{id}/{z}/{x}/{y}.{format}``

  * Format depends on the source file (usually ``png`` or ``pbf``)

    * ``geojson`` is also available (useful for inspecting the tiles) in case the original format is ``pbf``

  * TileJSON at ``/data/{id}.json``

  * If terrain mbtile data is served and ``encoding`` is configured (see config) the elevation can be queried

    * by ``/data/{id}/elevation/{z}/{x}/{y}`` for the tile

    * or ``/data/{id}/elevation/{z}/{long}/{lat}`` for the coordinate

    * the result will be a json object like ``{"z":7,"x":68,"y":45,"long":46.04798,"lat":11.84069,"elevation":1602,"pixelX":128,"pixelY":256}``

    * for batch requests, POST to ``/data/{id}/elevation`` with a JSON body:

      * Request: ``{"points": [{"lon": 45.5, "lat": 45.5, "z": 1}, ...]}``
      * Response: ``[500, 200, null, ...]`` - array of elevations (or null if no data) in the same order as input

  * The elevation api is not available in the ``tileserver-gl-light`` version.

Static files
===========
* Static files are served at ``/files/{filename}``

  * The source folder can be configured (``options.paths.files``), default is ``public/files``

  * This feature can be used to serve ``geojson`` files for styles and rendered tiles.

    * Keep in mind, that each rendered tile loads the whole geojson file, if performance matters a conversion to a tiled format (e.g. with https://github.com/felt/tippecanoe)may be a better approch.

    * Use ``file://{filename}`` to have matching paths for both endoints

TileJSON arrays
===============
Array of all TileJSONs is at ``[/{tileSize}]/index.json`` (``[/{tileSize}]/rendered.json``; ``/data.json``)

  * The optional tile size ``/{tileSize}`` (ex. ``/256``, ``/512``). if omitted, tileSize defaults to 256.

List of available fonts
=======================
Array of names of the available fonts is at ``/fonts.json``

Health check
============
Endpoint reporting health status is at ``/health`` and currently returns:

  * ``503`` Starting - for a short period before everything is initialized
  * ``200`` OK - when the server is running

---

## File: docs/index.rst

.. TileServer GL documentation master file, created by
   sphinx-quickstart on Thu Aug  4 23:48:49 2016.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to TileServer GL's documentation!
=========================================

Contents:

.. toctree::
   :maxdepth: 2

   installation
   usage
   config
   deployment
   endpoints



Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

---

## File: docs/installation.rst

============
Installation
============

Docker
======

When running docker image, no special installation is needed -- the docker will automatically download the image if not present.

Just run ``docker run --rm -it -v $(pwd):/data -p 8080:8080 maptiler/tileserver-gl``.

Additional options (see :doc:`/usage`) can be passed to the TileServer GL by appending them to the end of this command. You can, for example, do the following:

* ``docker run ... maptiler/tileserver-gl --file my-tiles.mbtiles`` -- explicitly specify which mbtiles to use (if you have more in the folder)
* ``docker run ... maptiler/tileserver-gl --verbose`` -- to see the default config created automatically

npm
===

npm is supported on the following platforms with `Native Dependencies <#id1>`_ installed.

- Operating systems:

  - Ubuntu 24.04 (x64/arm64)
  - macOS 15 (x64/arm64)
  - Windows (x64)

- Node.js 20,22,24
  
Install globally from npmjs.
------------------------------
::

  npm install tileserver-gl
  tileserver-gl

Install locally from source
-------------------
::

  git clone https://github.com/maptiler/tileserver-gl.git
  cd tileserver-gl
  npm install
  node .

Native dependencies
-------------------

Ubuntu 24.04 (x64/arm64)
~~~~~~~~~~~~~~~~~~~~~~~~~~
- apt install build-essential python3-setuptools pkg-config xvfb libglfw3-dev libuv1-dev libjpeg-turbo8 libicu-dev libcairo2-dev libpango1.0-dev libpng-dev libjpeg-dev libgif-dev librsvg2-dev librsvg2-dev libcurl4-openssl-dev libpixman-1-dev

MacOS 15 (x64/arm64)
~~~~~~~~~~~~~~~~~~~~~~
- brew install pkg-config cairo pango libpng jpeg giflib librsvg harfbuzz

Windows (x64)
~~~~~~~~~~~~~~~~~~~~~~~~~
- `Microsoft Visual C++ Redistributable <https://aka.ms/vs/17/release/vc_redist.x64.exe>`_

``tileserver-gl-light`` on npm
==============================

Alternatively, you can use ``tileserver-gl-light`` package instead, which is pure javascript (does not have any native dependencies) and can run anywhere, but does not contain rasterization features.

---

## File: docs/usage.rst

=====
Usage
=====

Getting started
======
::

  Usage: tileserver-gl [file] [options]

  Options:
    --file <file>             MBTiles or PMTiles file (local path, http(s)://, s3://, pmtiles://, or mbtiles:// URL)
                                ignored if the configuration file is also specified
    --mbtiles <file>          (DEPRECIATED) MBTiles file
                                ignored if file is also specified
                                ignored if the configuration file is also specified
    -c, --config <file>       Configuration file [config.json] (default: "config.json")
    -b, --bind <address>      Bind address
    -p, --port          Port [8080] (default: 8080)
    -C|--no-cors              Disable Cross-origin resource sharing headers
    -u|--public_url      Enable exposing the server on subpaths, not necessarily the root of the domain
    --fetch-timeout <ms>      Timeout in milliseconds for fetching remote tiles (default: 15000)
    --ignore-missing-files    Do not exit when referenced data files or remote sources are missing at startup; log a warning and continue running (useful when styles reference optional or not-yet-available sources)
    -V, --verbose [level]     More verbose output (level 1-3)
                                -V, --verbose, -V 1, or --verbose 1: Important operations
                                -V 2 or --verbose 2: Detailed operations  
                                -V 3 or --verbose 3: All requests and debug info
    -s, --silent              Less verbose output
    -l|--log_file <file>      output log file (defaults to standard out)
    -f|--log_format <format>  define the log format:  https://github.com/expressjs/morgan#morganformat-options
    -v, --version             output the version number
    -h, --help                display help for command

Security configuration
--------------------------------

To mitigate Host header poisoning (HNP), you can restrict which hosts are allowed:

- **allowedHosts config option**: Set ``allowedHosts`` under ``options`` in your config file to a comma-separated list of allowed hostnames (e.g. ``localhost,map.example.com``). This takes priority if both config and environment variable are set.
- **TILESERVER_GL_ALLOWED_HOSTS** (default: ``*``): Comma-separated list of allowed hostnames (e.g. ``localhost,map.example.com``). If the request host is not in this list, the server returns path-only URLs instead of absolute URLs. Set to ``*`` or leave unset for original behavior (no restriction).

See :ref:`security-hnp` and the repository's SECURITY.md for details.

File Source Options
======

The `--file` option supports multiple source types:

**Local files:**
::

  tileserver-gl --file ./data/zurich.mbtiles
  tileserver-gl --file ./data/terrain.pmtiles

**HTTP/HTTPS URLs:**
::

  tileserver-gl --file https://example.com/tiles.pmtiles

**S3 URLs:**
::

  # Basic AWS S3
  tileserver-gl --file s3://my-bucket/tiles.pmtiles

  # With AWS credential profile
  tileserver-gl --file "s3://my-bucket/tiles.pmtiles?profile=production"

  # With specific region
  tileserver-gl --file "s3://my-bucket/tiles.pmtiles?region=us-west-2"

  # With profile and region
  tileserver-gl --file "s3://my-bucket/tiles.pmtiles?profile=production&region=eu-central-1"

  # Requester-pays bucket
  tileserver-gl --file "s3://bucket/tiles.pmtiles?requestPayer=true"

  # Bucket name with dots (force AWS S3 interpretation)
  tileserver-gl --file "s3://my.bucket.name/tiles.pmtiles?s3UrlFormat=aws"

  # All options combined
  tileserver-gl --file "s3://bucket/tiles.pmtiles?profile=prod&region=us-west-2&requestPayer=true"

  # S3-compatible storage (e.g., DigitalOcean Spaces, Contabo)
  tileserver-gl --file "s3://example-storage.com/my-bucket/tiles.pmtiles?profile=dev"

**Protocol prefixes:**

You can also use `pmtiles://` or `mbtiles://` prefixes to explicitly specify the file type:
::

  tileserver-gl --file pmtiles://https://example.com/tiles.pmtiles
  tileserver-gl --file "pmtiles://s3://my-bucket/tiles.pmtiles?profile=production"
  tileserver-gl --file mbtiles://./data/zurich.mbtiles

.. note::
    For S3 sources, AWS credentials must be configured via environment variables, AWS credentials file (`~/.aws/credentials` on Linux/macOS or `C:\Users\USERNAME\.aws\credentials` on Windows), or IAM roles. 
    
    The `s3UrlFormat` parameter can be set to `aws` or `custom` to override auto-detection when needed (e.g., for AWS bucket names containing dots).
    
    **When using Docker**, the host credentials file can be mounted to the container's user home directory:

    ::
    
        docker run -v ~/.aws/credentials:/home/node/.aws/credentials:ro ... maptiler/tileserver-gl:latest

    See the Configuration documentation for details on using AWS credential profiles.

Default preview style and configuration
======

- If no configuration file is specified, a default preview style (compatible with openmaptiles) is used.
- If no data file is specified (and is not found in the current working directory), a sample file is downloaded (showing the Zurich area)

Remote tile fetching and timeouts
======

TileServer GL can fetch tiles from remote HTTP/HTTPS sources referenced in your style. The ``--fetch-timeout`` option controls how long the server will wait for remote tile requests before giving up.

**Default behavior:**
- Default timeout is 15 seconds (15000 milliseconds)
- If a remote tile request exceeds this timeout, an error is logged and an empty tile is returned to the renderer

**Tuning the timeout:**

If you notice timeout errors with certain remote sources, you can adjust the timeout:
::

  # Increase timeout to 30 seconds for slower remote sources
  tileserver-gl -c config.json --fetch-timeout 30000

  # Reduce timeout to 5 seconds for faster failure
  tileserver-gl -c config.json --fetch-timeout 5000

Reloading the configuration
======

It is possible to reload the configuration file without restarting the whole process by sending a SIGHUP signal to the node process.

- The `docker kill -s HUP tileserver-gl` command can be used when running the tileserver-gl docker container.
- The `docker-compose kill -s HUP tileserver-gl-service-name` can be used when tileserver-gl is run as a docker-compose service.

Docker and `--port`
======

When running tileserver-gl in a Docker container, using the `--port` option would make the container incorrectly seem unhealthy.
Instead, it is advised to use Docker's port mapping and map the default port 8080 to the desired external port.

---

## File: README_light.md

# TileServer GL light
[](https://travis-ci.org/maptiler/tileserver-gl)
[](https://hub.docker.com/r/maptiler/tileserver-gl/)

Vector maps with GL styles. Map tile server for Mapbox Android, iOS, GL JS, Leaflet, OpenLayers, etc. without server side rendering.

## Quickstart
Use `npm install tileserver-gl-light` to install the package from npm.

Then you can simply run `tileserver-gl-light zurich_switzerland.mbtiles` to start the server for the given mbtiles.

See also `tileserver-gl` which contains server side rendering.

Prepared vector tiles can be downloaded from [OpenMapTiles.com](https://openmaptiles.com/downloads/planet/).

## Building docker image

You can build TileServer GL light image from source.

```
git clone https://github.com/maptiler/tileserver-gl.git
cd tileserver-gl
node publish.js --no-publish
cd light
docker build -t tileserver-gl-light .
```

[Download from OpenMapTiles.com](https://openmaptiles.com/downloads/planet/) or [create](https://github.com/openmaptiles/openmaptiles) your vector tile, and run following in directory contains your *.mbtiles.

```
docker run --rm -it -v $(pwd):/data -p 8080:8080 tileserver-gl-light
```

## Documentation
You can read full documentation of this project at https://maptiler-tileserver.readthedocs.io/