<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Noan</title>
    <description>The latest articles on DEV Community by Noan (@noan).</description>
    <link>https://dev.to/noan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1712392%2Fd3a6f3d9-72f2-4d92-9d3f-d9d950085fcd.png</url>
      <title>DEV Community: Noan</title>
      <link>https://dev.to/noan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noan"/>
    <language>en</language>
    <item>
      <title>How to georeference a map with QGIS</title>
      <dc:creator>Noan</dc:creator>
      <pubDate>Wed, 08 Apr 2026 09:29:22 +0000</pubDate>
      <link>https://dev.to/noan/how-to-georeference-a-map-with-qgis-4if9</link>
      <guid>https://dev.to/noan/how-to-georeference-a-map-with-qgis-4if9</guid>
      <description>&lt;p&gt;This tutorial is for you if you have a map you obtained from some website or some book, you need to produce a &lt;code&gt;.tiff&lt;/code&gt; file which is a localised version of your a mapping. E.g. to display  it in a &lt;a href="https://leafletjs.com/examples/overlays/" rel="noopener noreferrer"&gt;mapping system such as leaflet&lt;/a&gt; but you do not know how to do it. You mya have read notes about projection systems, but the &lt;a href="https://en.wikipedia.org/wiki/Mercator_projection#Mathematics" rel="noopener noreferrer"&gt;calculous&lt;/a&gt;  got complicated and you may not even know what projection system your map is using.&lt;br&gt;
QGIS can help you to geo reference a map even without knowing the projection system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Geo-reference the image
&lt;/h2&gt;

&lt;p&gt;Once you have &lt;a href="https://qgis.org/resources/installation-guide/" rel="noopener noreferrer"&gt;installed QGIS&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the GeoReferencer tool &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5mf96eqvo79yijdbbmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5mf96eqvo79yijdbbmi.png" alt="Cursor clicking on Layer &amp;gt; Georeferencer" width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load your image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F363rk5jqy9mxw54jgjir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F363rk5jqy9mxw54jgjir.png" alt="Cursor clicking on open raster" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on add a point&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5pc4y3m5p1tfmou96on.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5pc4y3m5p1tfmou96on.png" alt="Cursor clicking on add a point" width="433" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find a point of your map from which you can deduce the coordinate, e.g. a building, a place, a confluence of 2 rivers, a specific point on a coast. You can find its coordinates on OpenStreetMap. Fill in the coordinates (X = longitude, Y = latitude).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6duygct089ghngoyt2if.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6duygct089ghngoyt2if.png" alt="Window to add map coordinates" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find another point and repeat step 4 at least once, the more location you fill, the more precise the georeferencing.&lt;/li&gt;
&lt;li&gt;Click on Transformation Settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6huzujs8dsbhh5ka8t6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6huzujs8dsbhh5ka8t6j.png" alt="Cursor clicking on transformation settings" width="455" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In transformation type, choose &lt;a href="https://docs.qgis.org/3.34/en/docs/user_manual/working_with_raster/georeferencer.html#available-transformation-algorithms" rel="noopener noreferrer"&gt;Linear projection&lt;/a&gt; which is the simplest geo referencing algorithm and is relevant if your map is not distorted. This algorithm may produce unexpected result if your image is distorted (e.g. if it's a picture of a book the page may be curved on the corners). To optimize the result you can find out about &lt;a href="https://docs.qgis.org/3.34/en/docs/user_manual/working_with_raster/georeferencer.html#available-transformation-algorithms" rel="noopener noreferrer"&gt;other algorithms&lt;/a&gt; to find the most appropriate to your map.&lt;/li&gt;
&lt;li&gt;Click Run, QGIS will produce a &lt;code&gt;.tiff&lt;/code&gt; file in the same folder as your input image. Which is your geo referenced map.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  (Optional) Verify your geo-referencing with OpenStreetMap
&lt;/h2&gt;

&lt;p&gt;After you have runned the geo-referencing process QGIS should open the &lt;code&gt;.tiff&lt;/code&gt; file. You may want to open it over a map to make sure the geographic elements of the maps stand at the right coordinates.&lt;br&gt;
In order to create the OpenStreetMap layer in QGIS you can&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add an XYZ layer 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmh680iv7gusvvja7ybio.png" alt="Cursor clicking on add XYZ layer" width="800" height="461"&gt;
&lt;/li&gt;
&lt;li&gt;Choose OpenStreetMap as the source, add it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxle8fwp8ifzt5ay1jnj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxle8fwp8ifzt5ay1jnj.png" alt="add an XYZ layer window" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure to move your image layer on top of the OSM layer to view it 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5x2jxclbb90mwide12xf.png" alt="Cursor clicking on Move to top" width="800" height="790"&gt;
&lt;/li&gt;
&lt;li&gt;Right-click on the image layer and in the layer properties choose an opacity lower than 100% to see both your image and OpenStreetMap 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkb8yxlhda2f20ge8d0l.png" alt="Image layer transparency window" width="800" height="724"&gt;
&lt;/li&gt;
&lt;li&gt;You may now compare your image geo referenced with the real map 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr6niy1a9qyvtkg84b0n.png" alt="View of Paris map over the OpenStreetMap layer" width="684" height="350"&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>beginners</category>
      <category>opensource</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to create a blog with GitLab Pages</title>
      <dc:creator>Noan</dc:creator>
      <pubDate>Wed, 08 Apr 2026 08:41:37 +0000</pubDate>
      <link>https://dev.to/noan/how-to-create-a-blog-with-gitlab-pages-35b3</link>
      <guid>https://dev.to/noan/how-to-create-a-blog-with-gitlab-pages-35b3</guid>
      <description>&lt;p&gt;If you to need to host a blog, GitLab can help to build and host it with GitLab Pages. In this tutorial we'll use GitLab CI and Jekyll to deploy your blog. This is the configuration I use for my &lt;a href="https://noancloarec.fr" rel="noopener noreferrer"&gt;personal website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Have a project hosted on GitLab&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create and build your blog locally
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 Create a homepage and an article
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;---
---
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My first blog&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- {{ link | absolute_url}} is a 'Liquid' expression Jekyll will interpret to prefix the link with the url and the base_url previously defined  --&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{'/articles/my-first-article.html' | absolute_url}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My first article&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The 2 dashed lines at the top of the markdown file define your &lt;a href="https://jekyllrb.com/docs/front-matter/" rel="noopener noreferrer"&gt;Front Matter&lt;/a&gt;, this is a &lt;code&gt;.yml&lt;/code&gt; configuration section for your page we will talk about later&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In &lt;code&gt;articles/my-first-article.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;---
---
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My first article&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hi Mom&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;Gemfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source "https://rubygems.org"

gem "jekyll"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;_config.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;baseurl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&amp;lt;name_of_your_gitlab_project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 Test locally with Jekyll
&lt;/h3&gt;

&lt;p&gt;So you do not have to run the GitLab pipeline to ensure your blog's code does not have bugs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This tutorial has been tested on Ubuntu 24.04 (some commands in this section may not be adapted to your OS)&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Useful links:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://jekyllrb.com/docs/installation/windows/" rel="noopener noreferrer"&gt;Install Jekyll on Windows&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;a href="https://jekyllrb.com/docs/installation/windows/" rel="noopener noreferrer"&gt;Install Jekyll on macOS&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Install ruby (via rbenv) and Jekyll
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install dependencies to run ruby&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; git curl build-essential libz-dev libffi-dev libssl-dev libyaml-dev

&lt;span class="c"&gt;# Clone rbenv and install it&lt;/span&gt;
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
~/.rbenv/bin/rbenv init
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
git clone https://github.com/rbenv/ruby-build.git &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;rbenv root&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/plugins/ruby-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then find the latest stable release of ruby with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rbenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will remember it as &lt;code&gt;RUBY_VERSION&lt;/code&gt;, replace &lt;code&gt;RUBY_VERSION&lt;/code&gt; in the following commands with the version you have found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install and use a ruby environment&lt;/span&gt;
rbenv &lt;span class="nb"&gt;install &lt;/span&gt;RUBY_VERSION
rbenv global RUBY_VERSION

&lt;span class="c"&gt;# Install bundler and install the blog's dependencies&lt;/span&gt;
gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler
bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Serve the blog
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your changes are visible at &lt;a href="http://localhost:4000/&amp;lt;name_of_your_gitlab_project" rel="noopener noreferrer"&gt;http://localhost:4000/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3. Ignore the files Jekyll has created
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;.gitignore&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_site/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Use GitLab CI to build and deploy your website
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ruby:RUBY_VERSION&lt;/span&gt;

&lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install bundler&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle exec jekyll build -d public&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And push&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Gitlab pages setup"&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline deploying your project is visible on your project's home on GitLab, under Build/Pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Visit your website
&lt;/h2&gt;

&lt;p&gt;On your project's home on GitLab, navigate to Deploy/Pages to see your website's URL. &lt;/p&gt;

&lt;p&gt;Uncheck &lt;em&gt;Use unique domain&lt;/em&gt; if you want your blog to be accessible from a more user-friendly URL, but keep in mind HTTPS &lt;a href="https://docs.gitlab.com/ee/user/project/pages/introduction.html#subdomains-of-subdomains" rel="noopener noreferrer"&gt;won't work for.gitlab.io domains&lt;/a&gt; if your username or project name contains a dot (you can still set up your own domain).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. (Optional) Write your blog in Markdown
&lt;/h2&gt;

&lt;p&gt;One major feature of Jekyll is to translate Markdown files into an HTML website.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Tell Jekyll you'll be using Markdown
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;_config.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;markdown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kramdown&lt;/span&gt;
&lt;span class="na"&gt;baseurl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&amp;lt;name_of_your_gitlab_project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2. Change your article to Markdown
&lt;/h3&gt;

&lt;p&gt;Remove the file &lt;code&gt;articles/my-first-article.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;articles/my-first-article.md&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Hi Mom&lt;/span&gt;
Hope you're fine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;bundle exec jekyll build&lt;/code&gt; and you should find your translated HTML file under &lt;code&gt;_site/articles/my-first-article.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hi-mom"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hi Mom&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hope you’re fine&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This page is missing basic HTML structure and metadata. We could write our Markdown inside an HTML canvas, but this would lead in repetitions in our code, let's take advantage of Jekyll layout features.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Define a layout for your posts
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;_layouts/default.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ page.title }}&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--
        You may add any stylesheet or script you'd like to use
        &amp;lt;link rel="stylesheet" href="'/assets/main.css'"&amp;gt; 
        --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{'/' | absolute_url}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My first blog&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
        {{ content }} &lt;span class="c"&gt;&amp;lt;!-- Your content will go here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then edit the file &lt;code&gt;articles/my-first-article.md&lt;/code&gt; and make use of the Front Matter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My first article&lt;/span&gt;
&lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Hi Mom&lt;/span&gt;

Hope you're fine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it with &lt;code&gt;bundle exec jekyll build&lt;/code&gt; or &lt;code&gt;bundle exec jekyll serve&lt;/code&gt;, once you're confident in your changes push them and let GitLab do the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. (Optional) Preview your changes before publishing them
&lt;/h2&gt;

&lt;p&gt;In a development process, we usually want to review changes we have made before publishing them. This could also apply to a blog.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1. Prevent the pages' publication if the pipeline does not belong to the main branch
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ruby:RUBY_VERSION&lt;/span&gt;

&lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install bundler&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle exec jekyll build -d public&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH&lt;/span&gt; &lt;span class="c1"&gt;# This rule prevents the pages job from being executed for a commit that is not made on the main branch&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2. Create another job only for MR which will upload a preview version of the blog
&lt;/h3&gt;

&lt;p&gt;Add a file named &lt;code&gt;generate_pipeline_config.sh&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Outputs a configuration which will later be used by jekyll to generate the website and make links that points to the website-as-artifact generated&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"url: https://&lt;/span&gt;&lt;span class="nv"&gt;$CI_PROJECT_NAMESPACE&lt;/span&gt;&lt;span class="s2"&gt;.gitlab.io"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"baseurl: /-/&lt;/span&gt;&lt;span class="nv"&gt;$CI_PROJECT_NAME&lt;/span&gt;&lt;span class="s2"&gt;/-/jobs/&lt;/span&gt;&lt;span class="nv"&gt;$CI_JOB_ID&lt;/span&gt;&lt;span class="s2"&gt;/artifacts/public"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And make it executable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x generate_pipeline_config.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# This is new&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pages&lt;/span&gt;
&lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pages&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install bundler&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle exec jekyll build -d public&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH&lt;/span&gt; &lt;span class="c1"&gt;# This rule prevent the pages job to be executed for commit not made on the main branch&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;

&lt;span class="na"&gt;preview-pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# This is almost the same job, as it is not named 'pages' the job will not publish its result on GitLab Pages&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;staging&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install bundler&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle install&lt;/span&gt;
    &lt;span class="c1"&gt;# The 2 following lines are modified&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./generate_pipeline_config.sh &amp;gt; pipeline_config.yml&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bundle exec jekyll build -c _config.yml,pipeline_config.yml -d public&lt;/span&gt; &lt;span class="c1"&gt;# pipeline_config.yml redefines some variable from _config.yml&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_MERGE_REQUEST_IID&lt;/span&gt; &lt;span class="c1"&gt;# This rule to execute the job only if it is part of a merge request&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_REF_NAME&lt;/span&gt;
    &lt;span class="c1"&gt;# The environment is a link to the artifact produced by the pipeline&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://$CI_PROJECT_NAMESPACE.gitlab.io/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/public/index.html&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an MR with your changes.&lt;br&gt;
The &lt;code&gt;environment&lt;/code&gt; section tells GitLab you have deployed something at a certain URL. &lt;br&gt;
On the MR overview it suggests the reader to visit the website you have just deployed.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8r12vu4bmueel6gyauq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8r12vu4bmueel6gyauq.png" alt="Overview of the MR in GitLab" width="764" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Some links will not work in the preview. The artifact browsing server we are using is not made to be a web server. Contrary to the GitLab Pages server it will not return &lt;code&gt;/index.html&lt;/code&gt; if you ask for &lt;code&gt;/&lt;/code&gt;, neither will it return &lt;code&gt;/articles/my-first-article.html&lt;/code&gt; you requested &lt;code&gt;/articles/my-first-article&lt;/code&gt;. You can choose between writing exclusively explicit links or rewrite the url in your browser when browsing the preview&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>gitlab</category>
      <category>jekyll</category>
    </item>
    <item>
      <title>How to build and serve custom simplified maps with OpenMapTiles</title>
      <dc:creator>Noan</dc:creator>
      <pubDate>Tue, 13 Jan 2026 08:32:21 +0000</pubDate>
      <link>https://dev.to/zenika/how-to-build-and-serve-custom-simplified-maps-with-openmaptiles-hfn</link>
      <guid>https://dev.to/zenika/how-to-build-and-serve-custom-simplified-maps-with-openmaptiles-hfn</guid>
      <description>&lt;p&gt;If you need to display a map on your website and do not plan to use online mapping services such as MapTiler or Mapbox, you may want to use &lt;a href="https://openmaptiles.org/" rel="noopener noreferrer"&gt;OpenMapTiles&lt;/a&gt; to generate and serve custom tiles. This approach is also useful when you are not interested in all the features a map can display. &lt;br&gt;
In this tutorial, we will create a map featuring only water, such as coastlines, lakes and rivers.&lt;br&gt;
This tutorial was tested on Ubuntu 24.04.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://osmcode.org/osmium-tool/" rel="noopener noreferrer"&gt;Osmium&lt;/a&gt;: a tool used to process OpenStreetMap data.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/openmaptiles/openmaptiles" rel="noopener noreferrer"&gt;OpenMapTiles repository&lt;/a&gt; cloned on your computer.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, to run the OpenMapTiles containers.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;build-essential&lt;/code&gt; package (to run the &lt;code&gt;make&lt;/code&gt; command).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1. Download the source data
&lt;/h2&gt;

&lt;p&gt;OpenStreetMap provides an &lt;a href="https://planet.openstreetmap.org/" rel="noopener noreferrer"&gt;up-to-date export of the entire planet&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Pay attention to the licenses of the tools and data used. For OpenStreetMap and OpenMapTiles, proper attribution must be displayed on your map, for example: &lt;a href="http://openmaptiles.org/" rel="noopener noreferrer"&gt;© OpenMapTiles&lt;/a&gt; &lt;a href="http://www.openstreetmap.org/copyright" rel="noopener noreferrer"&gt;© OpenStreetMap contributors&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;planet.osm.pbf&lt;/code&gt; file is about 85GB. This is very large and can take hours to process even you are when only interested in the water data. During development, it is recommended to use an extract from &lt;a href="https://download.geofabrik.de/" rel="noopener noreferrer"&gt;GeoFabrik&lt;/a&gt; covering a smaller region that you know well.&lt;br&gt;
In my case, I used the file &lt;a href="https://download.geofabrik.de/europe/france/bretagne.html" rel="noopener noreferrer"&gt;&lt;code&gt;bretagne.osm.pbf&lt;/code&gt;&lt;/a&gt; and then the file &lt;a href="https://download.geofabrik.de/europe/france.html" rel="noopener noreferrer"&gt;&lt;code&gt;france.osm.pbf&lt;/code&gt;&lt;/a&gt;. They can be processed in a few seconds or minutes.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A &lt;code&gt;.osm.pbf&lt;/code&gt; file is a compressed format for OpenStreetMap data, if you decompress it with the command &lt;code&gt;osmium cat &amp;lt;your-region&amp;gt;.osm.pbf --output &amp;lt;your-region&amp;gt;.osm&lt;/code&gt; you will find that the &lt;code&gt;.osm&lt;/code&gt; file is an XML file listing nodes, ways, and polygons. The documentation for this format is available on the &lt;a href="//wiki.openstreetmap.org/wiki/OSM_XML"&gt;OpenStreetMap wiki&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  2. Extract the relevant data
&lt;/h2&gt;

&lt;p&gt;Since we are only interested in water data, the process can be sped up by reducing the input file size. Let's filter out everything that is not related to water:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osmium tags-filter &amp;lt;your-region&amp;gt;.osm.pbf  rw/waterway rw/water &lt;span class="nt"&gt;-o&lt;/span&gt; water.osm.pbf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Generate the vector tiles
&lt;/h2&gt;

&lt;p&gt;At the root of the OpenMapTiles repository, edit the file &lt;code&gt;openmaptiles.yaml&lt;/code&gt; to comment out all layers except those related to water:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tileset&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;layers/water/water.yaml&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;layers/waterway/waterway.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# All other layers are commented out&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/landcover/landcover.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/landuse/landuse.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/mountain_peak/mountain_peak.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/park/park.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/boundary/boundary.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/aeroway/aeroway.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/transportation/transportation.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/building/building.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/water_name/water_name.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/transportation_name/transportation_name.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/place/place.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/housenumber/housenumber.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/poi/poi.yaml&lt;/span&gt;
    &lt;span class="c1"&gt;# - layers/aerodrome_label/aerodrome_label.yaml&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OpenMapTiles&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.15.0&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openmaptiles&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tileset&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;showcasing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;layers&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;OpenMapTiles.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;https://openmaptiles.org"&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, edit the &lt;code&gt;.env&lt;/code&gt; file to specify the zoom levels to generate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;...
&lt;span class="c"&gt;# Which zooms to generate with make generate-tiles-pg
&lt;/span&gt;&lt;span class="n"&gt;MIN_ZOOM&lt;/span&gt;=&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;MAX_ZOOM&lt;/span&gt;=&lt;span class="m"&gt;10&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Move the &lt;code&gt;water.osm.pbf&lt;/code&gt; you generated earlier into the &lt;code&gt;data/&lt;/code&gt; directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;openmaptiles/data/
&lt;span class="nb"&gt;mv &lt;/span&gt;water.osm.pbf openmaptiles/data/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run OpenMapTiles to generate the tiles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;openmaptiles
./quickstart.sh water
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, this process will: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Populate a PostGIS database with map features. Note that the &lt;a href="https://hub.docker.com/r/openmaptiles/postgis-preloaded" rel="noopener noreferrer"&gt;database&lt;/a&gt; already contains &lt;a href="https://www.naturalearthdata.com/" rel="noopener noreferrer"&gt;Natural Earth&lt;/a&gt; data for low zoom levels. At low zoom levels, coastlines in the resulting map will come frome Natural Earth data.&lt;/li&gt;
&lt;li&gt;Create views and functions in this database responsible for querying each layer for each zoom level.&lt;/li&gt;
&lt;li&gt;Query the PostGIS database to create a file named &lt;code&gt;tiles.mbtiles&lt;/code&gt;.  It is a SQLite database containing vector tile data for each &lt;a href="https://dev.to/geoapify-maps-api/understanding-map-zoom-levels-and-xyz-tile-coordinates-55da"&gt;(x, y, z) coordinate&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. Serve the tiles
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make start-tileserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And visit &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yf6q4vacqcvsmlbjb1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yf6q4vacqcvsmlbjb1t.png" alt="Preview of the water map on localhost:8080" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or if you want to serve the tiles on a server without the whole OpenMapTiles project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Make sure you have Node.js version 18.17.0 or later installed&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; tileserver-gl
tileserver-gl &lt;span class="nt"&gt;--file&lt;/span&gt; tiles.mbtiles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we have introduced techniques for generating simple vector maps: where to retrieve the data, how it can be filtered with Osmium, how OpenMapTiles processes it to generate vector tiles, and finally how tileserver-gl can serve them (although &lt;a href="https://tileserver.readthedocs.io/en/latest/deployment.html" rel="noopener noreferrer"&gt;it is not  production-ready&lt;/a&gt; on its own).&lt;br&gt;&lt;br&gt;
From here, you may then want to style your map with &lt;a href="https://maputnik.github.io/" rel="noopener noreferrer"&gt;Maputnik&lt;/a&gt;, explore the user interactions provided by &lt;a href="https://maplibre.org/" rel="noopener noreferrer"&gt;MapLibre&lt;/a&gt;, or dig deeper into the &lt;a href="https://github.com/openmaptiles/openmaptiles/tree/master/layers" rel="noopener noreferrer"&gt;transformations&lt;/a&gt; performed by OpenMapTiles for each layer.&lt;/p&gt;

</description>
      <category>map</category>
      <category>openmaptiles</category>
    </item>
  </channel>
</rss>
