282 lines
10 KiB
Markdown
282 lines
10 KiB
Markdown
+++
|
|
title = "Self-hosting a map tile server for location sharing"
|
|
extra.author = "Andy Balaam"
|
|
aliases = ["/docs/guides/map-tile-server"]
|
|
+++
|
|
|
|
Thanks to
|
|
[MSC3488](https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md),
|
|
the ability to share your location is coming soon to various Matrix clients,
|
|
including FluffyChat (which has had this for some time) and Element.
|
|
|
|
When we are sharing information about our location, we need to be
|
|
extra-cautious that it is kept private. Because Matrix provides robust,
|
|
publicly-audited end-to-end encryption, we can be confident when we share a
|
|
location, that the message we are sending is only going to be readable for
|
|
the people in the room.
|
|
|
|
In addition to the messages we are sending, though, we need to consider other
|
|
ways our information might leak out. In particular, when we are drawing maps
|
|
on the screen, we need to talk to an additional server to fetch the map
|
|
information, and the sections of map we are looking for (known as 'tiles')
|
|
can reveal our approximate location if they get into the wrong hands.
|
|
|
|
Element is funding the hosting of a tile server that will be used by default
|
|
by the Element clients, and will not share information with your homeserver,
|
|
meaning that there is separation between the people who see which tiles are
|
|
being requested, and the people who have access to metadata like the pattern
|
|
of your Matrix activity.
|
|
|
|
But Matrix is all about giving you control over your own information and
|
|
infrastructure, so here is a guide that will help you enjoy fully-featured
|
|
location sharing in the Element client, while ensuring that all the tile
|
|
requests go to servers that you control.
|
|
|
|
We will describe how to run
|
|
[OSM tile server stack](https://github.com/Overv/openstreetmap-tile-server),
|
|
and how to add the config Element needs to use it to display maps.
|
|
|
|
## Not production ready
|
|
|
|
Note: this is not a guide on how to host a robust, production-ready map tile
|
|
server for many users. To do that you will need serious hardware, and further
|
|
research on how to provide high availability, monitoring and everything else
|
|
you will need in your own hosting environment.
|
|
|
|
This guide should give you the information you need to run a tile server
|
|
locally, so you can begin learning what you need to bring one up in production.
|
|
|
|
(For a little more of what you will need for production-readiness, see
|
|
[Self-Host a Matrix Map Server](https://wrily.foad.me.uk/self-host-a-matrix-map-server),
|
|
which includes some ansible scripts and hardware requirements.)
|
|
|
|
## Prerequisites
|
|
|
|
This guide is built on [Docker](https://www.docker.com/get-started), so you
|
|
will need an environment that supports Docker, or a compatible container
|
|
engine.
|
|
|
|
The setup below was tested on a modern (2022) laptop running Ubuntu Linux
|
|
21.10, but should run fine on any Docker-compatible Linux, and maybe even
|
|
elsewhere. For production use by large numbers of users, you will need very
|
|
powerful machines, and lots of bandwidth.
|
|
|
|
All the map information we use below is freely available under open licenses
|
|
from [OpenStreetMap](https://www.openstreetmap.org) and
|
|
[Geofabrik](http://download.geofabrik.de/), and we think what we recommend
|
|
complies with their terms of use - please let us know if not!
|
|
|
|
## Running the tile server
|
|
|
|
The [OSM tile server stack](https://github.com/Overv/openstreetmap-tile-server)
|
|
is a map tile server that provides tiles via HTTP, and provides a simple web UI
|
|
to browse the map data:
|
|
|
|
<iframe
|
|
width="560"
|
|
height="315"
|
|
src="https://www.youtube.com/embed/gngwBZc8lYE"
|
|
title="YouTube video player"
|
|
frameborder="0"
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowfullscreen
|
|
></iframe>
|
|
|
|
### Download the raw data
|
|
|
|
In order to run a tile server, we need some map data, that we will then process
|
|
and provide as map tiles. (Tiles are images of a particular area of the map,
|
|
whereas the raw data contains the exact locations of roads, buildings etc.)
|
|
|
|
You can download map data (PBF files) from
|
|
[download.geofabrik.de](http://download.geofabrik.de/). For example, to
|
|
download data for the UK, run this command:
|
|
|
|
```sh
|
|
wget 'https://download.geofabrik.de/europe/great-britain-latest.osm.pbf'
|
|
```
|
|
|
|
### Import it
|
|
|
|
Once we have the data, we need to import it into the tile server. Run these
|
|
commands:
|
|
|
|
(Change "great-britain" to match what you downloaded.)
|
|
|
|
```sh
|
|
docker volume create openstreetmap-data
|
|
docker volume create openstreetmap-rendered-tiles
|
|
docker run \
|
|
-v $PWD/great-britain-latest.osm.pbf:/data.osm.pbf \
|
|
-v openstreetmap-data:/var/lib/postgresql/12/main \
|
|
-v openstreetmap-rendered-tiles:/var/lib/mod_tile \
|
|
-e THREADS=24 \
|
|
overv/openstreetmap-tile-server:1.3.10 \
|
|
import
|
|
```
|
|
|
|
This expects the downloaded PFB file to be in the current directory, and saves
|
|
the imported data into the two docker volumes created by the first two
|
|
commands.
|
|
|
|
The import process may take quite a while. On a reasonably powerful 2022 laptop
|
|
the UK data took 39 minutes to import.
|
|
|
|
If you are running your tile server as a service, you will probably want to
|
|
automate the process of downloading new data and importing it. Updating should
|
|
involve re-running the download command from "Download the raw data", then
|
|
re-running the `import` command above.
|
|
|
|
### Run the tile server
|
|
|
|
Once the data has been imported, you can run your server like this:
|
|
|
|
```sh
|
|
docker run \
|
|
-p 8080:80 \
|
|
-v openstreetmap-data:/var/lib/postgresql/12/main \
|
|
-v openstreetmap-rendered-tiles:/var/lib/mod_tile \
|
|
-e THREADS=24 \
|
|
-e ALLOW_CORS=enabled \
|
|
-d overv/openstreetmap-tile-server:1.3.10 \
|
|
run
|
|
```
|
|
|
|
This should launch the docker container in the background, which you can check
|
|
with `docker ps`.
|
|
|
|
### Test it
|
|
|
|
Once the server is running, you can grab a single file by going to
|
|
[http://127.0.0.1:8080/tile/0/0/0.png](http://127.0.0.1:8080/tile/0/0/0.png),
|
|
or interact with the web UI at
|
|
[http://127.0.0.1:8080](http://127.0.0.1:8080).
|
|
|
|
When you first start the service, it will take a lot of CPU and be quite
|
|
unresponsive, but after a few minutes it should perform reasonably smoothly.
|
|
|
|
## Providing the JSON file the client needs
|
|
|
|
Once the tile server is running, we need to provide the config so that Element
|
|
(and any similar clients) can use it.
|
|
|
|
Element uses the [MapLibre GL](https://maplibre.org/) library to render maps,
|
|
and MapLibre requires a style file that describes how to find map tiles.
|
|
Here's how it looks:
|
|
|
|
<iframe
|
|
width="560"
|
|
height="315"
|
|
src="https://www.youtube.com/embed/_c-V_kvIVj8"
|
|
title="YouTube video player"
|
|
frameborder="0"
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowfullscreen
|
|
></iframe>
|
|
|
|
The style file is quite simple. To describe a tile server on this machine,
|
|
we need to create a file `style.json` like this:
|
|
|
|
```json
|
|
{
|
|
"version": 8,
|
|
"sources": {
|
|
"localsource": {
|
|
"type": "raster",
|
|
"tiles": [
|
|
"http://127.0.0.1:8080/tile/{z}/{x}/{y}.png"
|
|
],
|
|
"tileSize": 256,
|
|
"attribution": "Maps Copyright 2022 <a href=\"http://www.geofabrik.de/\">Geofabrik GmbH</a> and <a href=\"http://www.openstreetmap.org/\">OpenStreetMap Contributors</a>"
|
|
}
|
|
},
|
|
"layers": [
|
|
{
|
|
"id": "locallayer",
|
|
"source": "localsource",
|
|
"type": "raster"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
We need this file to be served up by the tile server, but that is easily done
|
|
by slightly modifying the command we use to run it.
|
|
|
|
First stop your tile server. Use `docker ps` to find the CONTAINER ID of your
|
|
tile server, then use `docker kill <CID>` (substituting in the CONTAINER ID
|
|
instead of `<CID>`) to stop it.
|
|
|
|
Now re-launch the tile server, asking it to serve up our style file as well:
|
|
|
|
```sh
|
|
docker run \
|
|
-p 8080:80 \
|
|
-v $PWD/style.json:/var/www/html/style.json \
|
|
-v openstreetmap-data:/var/lib/postgresql/12/main \
|
|
-v openstreetmap-rendered-tiles:/var/lib/mod_tile \
|
|
-e THREADS=24 \
|
|
-e ALLOW_CORS=enabled \
|
|
-d overv/openstreetmap-tile-server:1.3.10 \
|
|
run
|
|
```
|
|
|
|
(Notice the extra line mentioning `style.json`. This assumes `style.json` is
|
|
in the current directory.)
|
|
|
|
Now if I edit the config of my Element client to point to that style file,
|
|
it will use our tile server to display its maps.
|
|
|
|
If you are self-hosting Element Web, you can add this to the top level of its
|
|
`config.json` file:
|
|
|
|
```json
|
|
{
|
|
... other config ...
|
|
"map_style_url": "http://127.0.0.1:8080/style.json",
|
|
... other config ...
|
|
}
|
|
```
|
|
|
|
Also, if you run a home server, the Element client will prefer a tile server
|
|
you specify in your `.well-known` area over its own config setting. You should
|
|
serve up a file from your server root called `/.well-known/matrix/client`
|
|
containing information like this:
|
|
|
|
```json
|
|
{
|
|
... other info ...
|
|
"m.tile_server": {
|
|
"map_style_url": "http://mytileserver.example.com/style.json"
|
|
}
|
|
... other info ...
|
|
}
|
|
```
|
|
|
|
Once you have one of those settings in place, your Element client should use
|
|
your very own tile server every time it displays a map!
|
|
|
|
## Further reading and acknowledgements
|
|
|
|
julian posted an excellent guide building on this one, which includes ansible
|
|
scripts and some comments on the hardware needed:
|
|
|
|
* [Self-Host a Matrix Map Server](https://wrily.foad.me.uk/self-host-a-matrix-map-server)
|
|
|
|
This guide was constructed by reading the following links. Credit and thanks
|
|
are due to their authors:
|
|
|
|
* [Switch2OSM - The Basics](https://switch2osm.org/the-basics/) - explanation
|
|
of some of the concepts
|
|
* [Switch2OSM - serving tiles using a Docker container](https://switch2osm.org/serving-tiles/using-a-docker-container)
|
|
- the basis for most of the information in "Running the tile server" above
|
|
* [openstreetmap-tile-server README](https://github.com/Overv/openstreetmap-tile-server/blob/master/README.md)
|
|
- lots of further detail on how to run the tile server
|
|
|
|
Some other useful links:
|
|
|
|
* [Location Guard Firefox Plugin](https://addons.mozilla.org/en-US/firefox/addon/location-guard/)
|
|
- allows setting a hard-coded location instead of sharing your real location.
|
|
* [Implementing Vector Tile Support in Libshumate](https://www.jwestman.net/2021/11/08/implementing-vector-tile-support-in-libshumate.html)
|
|
- explanation of some of the key ideas from James Westman
|