<?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: Jon Neverland</title>
    <description>The latest articles on DEV Community by Jon Neverland (@joenas).</description>
    <link>https://dev.to/joenas</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%2F103307%2F863565a9-39bf-446d-acc1-1bb302c70666.png</url>
      <title>DEV Community: Jon Neverland</title>
      <link>https://dev.to/joenas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joenas"/>
    <language>en</language>
    <item>
      <title>Pixelfed (beta) with Docker and Traefik</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Tue, 09 Jul 2019 14:32:19 +0000</pubDate>
      <link>https://dev.to/joenas/pixelfed-beta-with-docker-and-traefik-35hm</link>
      <guid>https://dev.to/joenas/pixelfed-beta-with-docker-and-traefik-35hm</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VyeIPekf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/07/pixelfed-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VyeIPekf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/07/pixelfed-2.png" alt="Pixelfed (beta) with Docker and Traefik" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you sick of data mining and ads? Want to share photos in an Instagram like way with friends and keep control over your data? &lt;a href="https://pixelfed.org"&gt;Pixelfed&lt;/a&gt; is an open source alternative that's fairly easy to self host.&lt;/p&gt;

&lt;p&gt;This guide will show you an easy way to get an instance up in no time with the help of Traefik and Docker. If you &lt;strong&gt;already have&lt;/strong&gt; a server with Traefik running then continue. Otherwise I recommend you read my &lt;a href="https://dev.to/joenas/traefik-with-docker-and-lets-encrypt-35if"&gt;previous post&lt;/a&gt; and you'll be back here soon.&lt;/p&gt;

&lt;p&gt;It's also possible to skip using Traefik and put your own &lt;em&gt;reverse proxy&lt;/em&gt; (f.e nginx) in front of Pixelfed. Using https is a must today.&lt;/p&gt;

&lt;p&gt;Bear in mind that the current &lt;a href="https://github.com/pixelfed/pixelfed/releases/tag/v0.9.4"&gt;release&lt;/a&gt; is &lt;code&gt;v0.9.4&lt;/code&gt;, so things are still a &lt;em&gt;work in progress&lt;/em&gt;. With that said, it's working fine for me and my group of friends.&lt;/p&gt;

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

&lt;p&gt;This guide assumes some general knowledge of Linux and that you have a server available with these services installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/"&gt;docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/install/"&gt;docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;domain&lt;/strong&gt; to host your apps on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For cheap and good servers, checkout &lt;a href="https://www.digitalocean.com"&gt;DigitalOcean&lt;/a&gt; or &lt;a href="https://www.hetzner.com/cloud"&gt;Hetzner&lt;/a&gt;. Also I always recommend &lt;a href="https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers"&gt;this guide&lt;/a&gt; when setting up a new VPS.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to use Digital Ocean feel free to use my &lt;a href="https://m.do.co/c/37d221e6802a"&gt;referral link&lt;/a&gt; to get $10 for your server&lt;/em&gt; 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We start with cloning the repository to its own directory and build the docker image from there. There are pre-built ones, like &lt;a href="https://hub.docker.com/r/tedomum/pixelfed"&gt;this&lt;/a&gt;, but in this case I recommend building your own.&lt;/p&gt;

&lt;p&gt;Let's make a directory for your data to live in, as sudo if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /opt/pixelfed_source
sudo chown $USER:$USER /opt/pixelfed_source

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

&lt;/div&gt;



&lt;p&gt;Fetch the repo, checkout the commit of the release then build the image (replace &lt;code&gt;v0.9.4&lt;/code&gt; in the tag with whatever the latest version is for easy rollback) and wait...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:pixelfed/pixelfed.git /opt/pixelfed_source
# OR 
git clone https://github.com/pixelfed/pixelfed.git /opt/pixelfed_source
cd /opt/pixelfed_source
git checkout v0.9.4
docker build -t pixelfed:v0.9.4 . 

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

&lt;/div&gt;



&lt;p&gt;Now we can create a directory for the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /opt/pixelfed
sudo chown $USER:$USER /opt/pixelfed
cd /opt/pixelfed

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Next, let's edit the configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp ../pixelfed_source/.env.example .env
nano .env

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

&lt;/div&gt;



&lt;p&gt;Replace all &lt;code&gt;*_DOMAIN&lt;/code&gt; with your hostname and &lt;code&gt;APP_URL=http://localhost&lt;/code&gt; with your full hostname including protocol.&lt;/p&gt;

&lt;p&gt;We will have Pixelfed generate an &lt;code&gt;APP_KEY&lt;/code&gt; for us later, so don't touch that one.&lt;/p&gt;

&lt;p&gt;I'm using Postgres, mostly because MySQL was throwing weird errors but also because it's what I generally use, so these need to change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=pixelfed
DB_USERNAME=pixelfed
DB_PASSWORD=USE_A_PROPER_PASSWORD

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

&lt;/div&gt;



&lt;p&gt;Since we are using docker and an internal network for the database and Redis, also change this: &lt;code&gt;REDIS_HOST=redis&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you &lt;strong&gt;don't want&lt;/strong&gt; federation, change the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ACTIVITY_PUB=false
REMOTE_FOLLOW=false

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

&lt;/div&gt;



&lt;p&gt;You can also edit these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For a personal server, I don't really feel this is necessary
ENFORCE_EMAIL_VERIFICATION=false
# I had trouble running Horizon (background jobs) embedded in Docker
HORIZON_EMBED=false

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;Next we need that internal network for docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create pixelfed

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

&lt;/div&gt;



&lt;p&gt;And now we can add a &lt;code&gt;docker-compose&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch docker-compose.yml
nano docker-compose.yml

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

&lt;/div&gt;



&lt;p&gt;Copy and paste this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:

  app:
    image: pixelfed:v0.9.4
    restart: unless-stopped
    # This is for Traefik
    labels:
       - traefik.enable=true
       - traefik.frontend.rule=Host:pixelfed.example.com
       - traefik.port=80
       - traefik.docker.network=web
    env_file:
      - ./.env
    volumes:
      - "app-storage:/var/www/storage"
      - "app-bootstrap:/var/www/bootstrap"
      # We can remove this after generating APP_KEY
      - ./.env:/var/www/.env
    networks:
      - web
      - pixelfed

  db:
    image: postgres:9.6.4
    restart: unless-stopped
    networks:
      - pixelfed
    volumes:
     - db-data:/var/lib/postgresql/data
    environment:
     - POSTGRES_PASSWORD=${DB_PASSWORD}
     - POSTGRES_USER=${DB_USERNAME}

  worker:
    image: pixelfed:v0.9.4
    restart: unless-stopped
    env_file:
      - ./.env
    volumes:
      - "app-storage:/var/www/storage"
      - "app-bootstrap:/var/www/bootstrap"
    networks:
      - web # Required for ActivityPub
      - pixelfed
    command: gosu www-data php artisan horizon

  redis:
    image: redis:5-alpine
    restart: unless-stopped
    volumes:
      - "redis-data:/data"
    networks:
      - pixelfed

# Adjust your volume data in order to store data where you wish
volumes:
  redis-data:
  db-data:
  app-storage:
  app-bootstrap:

networks:
  pixelfed:
    internal: true
  web:
    external: true

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

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember to replace&lt;/strong&gt; &lt;code&gt;pixelfed.example.com&lt;/code&gt; in &lt;code&gt;traefik.frontend.rule&lt;/code&gt; with your hostname. Also make sure to add/replace your &lt;strong&gt;Traefik network&lt;/strong&gt; (in my case &lt;code&gt;web&lt;/code&gt;) in &lt;code&gt;networks&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you &lt;strong&gt;are not&lt;/strong&gt; using Traefik, replace the &lt;code&gt;labels&lt;/code&gt; section for &lt;code&gt;app&lt;/code&gt; with this to be able to reverse proxy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ports:
    - "127.0.0.1:8080:80"

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

&lt;/div&gt;



&lt;p&gt;Now we should be able to start the services and generate an &lt;code&gt;APP_KEY&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;docker-compose up -d
docker-compose exec app php artisan key:generate
# Make sure there's a value
cat .env | grep APP_KEY 

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

&lt;/div&gt;



&lt;p&gt;And now we can restart, clear the cache and run the migrations on the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose restart app
docker-compose exec app php artisan config:cache
docker-compose exec app php artisan migrate
# Answer yes

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

&lt;/div&gt;



&lt;p&gt;That's it 👏 Your Pixelfed instance should be up and running. Now go register a user! You can do that either on the web or through your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose exec app php artisan user:create

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bf-MNIiu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/07/pixelfed-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bf-MNIiu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/07/pixelfed-1.png" alt="Pixelfed (beta) with Docker and Traefik" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Site admin
&lt;/h3&gt;

&lt;p&gt;Then you probably want to make yourself an admin of the site...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose exec app php artisan user:admin [username]

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  The end
&lt;/h2&gt;

&lt;p&gt;I hope you enjoy your social photo sharing and don't hesitate to drop me a line for help (with this guide, for Pixelfed issues check out their &lt;a href="https://pixelfed.social/site/help"&gt;Help center&lt;/a&gt;).&lt;/p&gt;

</description>
      <category>pixelfed</category>
      <category>docker</category>
      <category>traefik</category>
      <category>selfhost</category>
    </item>
    <item>
      <title>Adding webhooks to Matrix</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Wed, 27 Feb 2019 12:00:34 +0000</pubDate>
      <link>https://dev.to/joenas/adding-webhooks-to-matrix-396n</link>
      <guid>https://dev.to/joenas/adding-webhooks-to-matrix-396n</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W814MmV2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.03.38-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W814MmV2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.03.38-1.png" alt="Adding webhooks to Matrix" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you got your &lt;a href="https://dev.to/joenas/matrix-homeserver-synapse-v09911-with-traefik-35ja"&gt;homeserver&lt;/a&gt; you want some integrations right? Webhooks seems like a great place to start - it's fairly easy to set up and the use cases are virtually unlimited.&lt;/p&gt;

&lt;p&gt;I have a couple of scenarios in &lt;a href="https://dev.to/joenas/my-two-favourite-services-30km-temp-slug-492995"&gt;Huginn&lt;/a&gt; for posting tomorrows weather, top voted posts from various &lt;a href="https://www.reddit.com/me/m/devsnack/"&gt;subreddits&lt;/a&gt; and alerts from Grafana, to mention a few.&lt;/p&gt;

&lt;p&gt;In this guide we will use an &lt;a href="https://matrix.org/docs/guides/application_services.html"&gt;application service&lt;/a&gt; (👈 &lt;em&gt;read this if you haven't&lt;/em&gt;) called &lt;a href="https://github.com/turt2live/matrix-appservice-webhooks"&gt;matrix-appservice-webhooks&lt;/a&gt; to be able to add webhooks to a room by just issuing a command. It has a Docker image so it fits right into my standard Traefik setup. If your Synapse isn't set up like &lt;a href="https://dev.to/joenas/matrix-homeserver-synapse-v09911-with-traefik-35ja"&gt;mine&lt;/a&gt; you'll have to make some adjustments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First let's get the files we need for the appservice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /opt/matrix # or wherever your stuff is 
mkdir matrix-appservice-webhooks
cd matrix-appservice-webhooks
curl https://raw.githubusercontent.com/turt2live/matrix-appservice-webhooks/master/config/database.json -o database.json
curl https://raw.githubusercontent.com/turt2live/matrix-appservice-webhooks/master/config/sample.yaml -o config.yaml

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

&lt;/div&gt;



&lt;p&gt;Then we replace paths in &lt;code&gt;database.json&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;sed -i 's/db\//\/data\//' database.json

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

&lt;/div&gt;



&lt;p&gt;... so that it looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "defaultEnv": {
    "ENV": "NODE_ENV"
  },
  "development": {
    "driver": "sqlite3",
    "filename": "/data/development.db"
  },
  "production": {
    "driver": "sqlite3",
    "filename": "/data/production.db"
  }
}

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

&lt;/div&gt;



&lt;p&gt;We edit &lt;code&gt;config.yaml&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;nano config.yaml

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

&lt;/div&gt;



&lt;p&gt;... and put in the (internal) URL to Synapse - accessible via our Docker network - the public URL for our webhooks and our Matrix domain name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;homeserver:
  # The name here is from docker-compose.yaml
  url: "http://synapse:8008"

  # Domain for you matrix server, with subdomain if needed
  domain: "example.com"

web:
  # This domain will be proxied via Traefik
  hookUrlBase: 'https://webhooks.example.com'
  # Because we're in a container
  bind: '0.0.0.0'

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

&lt;/div&gt;



&lt;p&gt;☝️ I only included the settings that needs to be changed for this guide. Edit the others according to comments in the file and remember to replace &lt;code&gt;example.com&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registration file
&lt;/h3&gt;

&lt;p&gt;Then we need to generate a registration file to add to Synapse via &lt;code&gt;homeserver.yaml&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;docker run --rm \
  -v /opt/matrix/matrix-appservice-webhooks:/data \
  turt2live/matrix-appservice-webhooks \
  node index.js -r \
  -f /data/appservice-registration-webhooks.yaml \
  -u "http://webhooks:9000" \
  -c /data/config.yaml

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

&lt;/div&gt;



&lt;p&gt;Now you should have a file called &lt;code&gt;appservice-registration-webhooks.yaml&lt;/code&gt; in your appservice directory. Copy that file to your Synapse dir (&lt;code&gt;/opt/matrix/synapse&lt;/code&gt; in my case).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cp appservice-registration-webhooks.yaml ../synapse

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

&lt;/div&gt;



&lt;p&gt;Add/edit the line below in your &lt;code&gt;homeserver.yaml&lt;/code&gt;, so that Synapse is aware of the appservice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app_service_config_files: ['/data/appservice-registration-webhooks.yaml']

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  docker-compose
&lt;/h3&gt;

&lt;p&gt;Time to add the container to our &lt;code&gt;docker-compose.yaml&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;  webhooks:
    image: turt2live/matrix-appservice-webhooks
    restart: unless-stopped
    depends_on:
      - synapse
    networks:
      - web
      - default
    volumes:
      - "/opt/matrix/matrix-appservice-webhooks:/data"
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:webhooks.example.com"
      - "traefik.port=9000"
      - "traefik.docker.network=web"

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

&lt;/div&gt;



&lt;p&gt;☝️ If you've followed my previous guide, this should be enough. Remember to replace &lt;code&gt;example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we're all set and ready to start the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up -d webhooks
docker-compose restart synapse

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding hook to a room
&lt;/h3&gt;

&lt;p&gt;Go to a room where you want to have a webhook, invite the bot user &lt;code&gt;@_webhook:example.com&lt;/code&gt; (adjust handle if you changed it in &lt;code&gt;config.yaml&lt;/code&gt;), send the message &lt;code&gt;!webhook&lt;/code&gt; in the room and you should see something like this 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oCSAHVUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.03.38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oCSAHVUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.03.38.png" alt="Adding webhooks to Matrix" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Posting them hooks
&lt;/h3&gt;

&lt;p&gt;Test your webhook with an app like &lt;a href="https://insomnia.rest"&gt;Insomnia&lt;/a&gt; / &lt;a href="https://www.getpostman.com"&gt;Postman&lt;/a&gt; or just use &lt;code&gt;curl&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;curl --header "Content-Type: application/json" \
     --data '{
       "text": "Hello world!",
       "format": "plain",
       "displayName": "My Cool Webhook",
       "avatarUrl": "http://i.imgur.com/IDOBtEJ.png"
     }' \
   YOUR_URL

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hfj4-M4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.11.57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hfj4-M4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/02/Screenshot-2019-02-26-at-00.11.57.png" alt="Adding webhooks to Matrix" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating hooks
&lt;/h3&gt;

&lt;p&gt;The first time you post the appservice will invite a &lt;em&gt;virtual user&lt;/em&gt; with the name and avatar you set. If you change &lt;code&gt;displayName&lt;/code&gt; on succeeding posts another user will join and if you change &lt;code&gt;avatarUrl&lt;/code&gt; but not &lt;code&gt;displayName&lt;/code&gt; the avatar will update.&lt;/p&gt;

&lt;p&gt;That's it! Have fun 🎉&lt;/p&gt;

</description>
      <category>matrix</category>
      <category>docker</category>
      <category>traefik</category>
      <category>webhooks</category>
    </item>
    <item>
      <title>Matrix homeserver (Synapse v1.0.0) with Traefik</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Wed, 20 Feb 2019 22:21:58 +0000</pubDate>
      <link>https://dev.to/joenas/matrix-homeserver-synapse-v09911-with-traefik-35ja</link>
      <guid>https://dev.to/joenas/matrix-homeserver-synapse-v09911-with-traefik-35ja</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgvdqfeqg94koyiv0q7n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgvdqfeqg94koyiv0q7n.jpg" alt="Matrix homeserver (Synapse v0.99.1.1) with Traefik" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Update 🚀
&lt;/h3&gt;

&lt;p&gt;Synapse &lt;code&gt;v1.0.0&lt;/code&gt; is now &lt;a href="https://matrix.org/blog/2019/06/11/synapse-1-0-0-released" rel="noopener noreferrer"&gt;released&lt;/a&gt;! I have upgraded my server without any problems and therefore updated the guide with the latest version.&lt;/p&gt;




&lt;p&gt;So our good friends at matrix.org &lt;a href="https://matrix.org/blog/2019/02/14/synapse-0-99-1-1-released/" rel="noopener noreferrer"&gt;released&lt;/a&gt; a &lt;code&gt;v0.99.1.1&lt;/code&gt; of Synapse as a precursor for a much anticipated 1.0 release. A big change in the upcoming release is that federation between servers will now require a proper TLS certificate and the current self signed cert that Synapse provides won't work. Homeserver owners are advised to make that change &lt;strong&gt;as soon as possible&lt;/strong&gt;, as v1 is supposed to be released in March. &lt;/p&gt;

&lt;p&gt;I've been running my Synapse behind Traefik for quite some time now but never bothered to replace the certificate for federation, although I have proper TLS on the client side. Once I figured out the &lt;a href="https://github.com/matrix-org/synapse/blob/master/docs/MSC1711_certificates_FAQ.md#configuring-certificates-for-compatibility-with-synapse-100" rel="noopener noreferrer"&gt;different options&lt;/a&gt; it was pretty straight forward to find one that worked with Traefik. &lt;/p&gt;

&lt;p&gt;In this guide we are going to put both the client side and federation of Synapse on a non-subdomain - ie &lt;code&gt;example.com&lt;/code&gt; - and use port &lt;code&gt;443&lt;/code&gt; for both, so no &lt;code&gt;8448&lt;/code&gt; for federation. If you have another setup - for example &lt;code&gt;matrix.example.com&lt;/code&gt; - it should be possible with some adjustments. &lt;/p&gt;

&lt;p&gt;We'll achive this by using both a SRV record and a &lt;code&gt;.well-known/matrix/server&lt;/code&gt; file to delegate federation to &lt;code&gt;example.com&lt;/code&gt;. Synapse itself will be available on &lt;code&gt;synapse.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'm also using &lt;code&gt;postgres&lt;/code&gt; as the database for Synapse.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;If you &lt;strong&gt;already have&lt;/strong&gt; a server with Traefik running then continue. Otherwise I recommend you read my &lt;a href="https://jonnev.se/traefik-with-docker-and-lets-encrypt/" rel="noopener noreferrer"&gt;previous post&lt;/a&gt; and you'll be back here soon.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Let's make a directory for your data to live in, as sudo if needed.&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; /opt/matrix
&lt;span class="c"&gt;# If you had to use sudo, set permissons&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$GROUP&lt;/span&gt; /opt/matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need an internal docker network for the services to communicate on&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  docker-compose.yml
&lt;/h3&gt;

&lt;p&gt;We'll put our services in a docker-compose file to be able to easily manage things. We'll start with Synapse. I'm using the &lt;a href="https://hub.docker.com/r/avhost/docker-matrix" rel="noopener noreferrer"&gt;avhost/docker-matrix&lt;/a&gt; image but it should be possible to use the &lt;a href="https://hub.docker.com/r/matrixdotorg/synapse/" rel="noopener noreferrer"&gt;official&lt;/a&gt; one too I'm sure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /opt/matrix/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:9.6.4&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/opt/matrix/pgdata:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=SECRET&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=synapse&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=false"&lt;/span&gt;

  &lt;span class="na"&gt;synapse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;avhost/docker-matrix:v1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="c1"&gt;# Coturn&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3478:3478"&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5349:5349"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/opt/matrix/synapse:/data&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.backend=synapse"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.port=8008"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend.rule=Host:synapse.example.com"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.docker.network=web"&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&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;matrix&lt;/span&gt;
  &lt;span class="c1"&gt;# Traefiks network&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ Remember to replace &lt;code&gt;example.com&lt;/code&gt; in &lt;code&gt;traefik.frontend.rule&lt;/code&gt;. That is where we do the reverse proxy for servers. Also change the &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; env.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx
&lt;/h3&gt;

&lt;p&gt;To be able to serve the &lt;code&gt;.well-known&lt;/code&gt; path on our domain we need Nginx. We're also going to use nginx to proxy clients to Synapse. With this setup you have the options to also serve static files on your domain, like &lt;code&gt;example.com/some-site&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's make a directory for nginx with a subdirectory for &lt;a href="http://www" rel="noopener noreferrer"&gt;www&lt;/a&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="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/matrix/nginx/www
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need a &lt;a href="https://ma.ttias.be/well-known-directory-webservers-aka-rfc-5785/" rel="noopener noreferrer"&gt;.well-known&lt;/a&gt; directory to put files in, for both our server and for clients.&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; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/matrix/nginx/www/.well-known/matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start with the server file. This will take care of proxying federation to your subdomain so you'll be able to have usernames in Matrix like &lt;code&gt;@me:example.com&lt;/code&gt;, while actually hosting Synapse at &lt;code&gt;synapse.example.com&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;nano /opt/matrix/nginx/www/.well-known/matrix/server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here you place a JSON formatted file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"m.server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"synapse.example.com:443"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ Replace &lt;code&gt;example.com&lt;/code&gt; above and make sure to &lt;strong&gt;NOT include&lt;/strong&gt; &lt;code&gt;https&lt;/code&gt; or anything like that.&lt;/p&gt;

&lt;p&gt;Next up is a &lt;code&gt;client&lt;/code&gt; file, which makes it possible to sign in to your Riot with &lt;a href="https://jonnev.se/riot-web-for-matrix-with-docker-and-traefik/" rel="noopener noreferrer"&gt;custom domain&lt;/a&gt; configured by only using your &lt;code&gt;username&lt;/code&gt; and not full MXID (&lt;code&gt;@username:example.com&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;nano /opt/matrix/nginx/www/.well-known/matrix/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another JSON formatted file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"m.homeserver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"base_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ Here you include the full URL. You can also add &lt;code&gt;m.identity_server&lt;/code&gt; if you have your own.&lt;/p&gt;

&lt;p&gt;Now we need a config file for &lt;code&gt;nginx&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;nano /opt/matrix/nginx/matrix.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;listen&lt;/span&gt;         &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="s"&gt;default_server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;server_name&lt;/span&gt;    &lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="c1"&gt;# Traefik -&amp;gt; nginx -&amp;gt; synapse&lt;/span&gt;
 &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/_matrix&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://synapse:8008&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;client_max_body_size&lt;/span&gt; &lt;span class="mi"&gt;128m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/.well-known/matrix/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;default_type&lt;/span&gt; &lt;span class="nc"&gt;application/json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Access-Control-Allow-Origin&lt;/span&gt;  &lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add nginx to our &lt;code&gt;docker-compose.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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;synapse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="c1"&gt;# Add this&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.12-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend.rule=Host:example.com"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend.passHostHeader=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.port=80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.docker.network=web"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx/www:/var/www/&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Synapse config
&lt;/h3&gt;

&lt;p&gt;Now we are ready to configure our Synapse so we can get it up and running.&lt;/p&gt;

&lt;p&gt;This will create a &lt;code&gt;homeserver.yaml&lt;/code&gt; in our &lt;code&gt;synapse&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;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; /opt/matrix/synapse:/data &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SERVER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;REPORT_STATS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  avhost/docker-matrix:v0.99.1.1 &lt;span class="se"&gt;\&lt;/span&gt;
  generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ Replace &lt;code&gt;example.com&lt;/code&gt; with your "short" domain, no subdomains.&lt;/p&gt;

&lt;p&gt;We then need to edit some stuff.&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;sudo &lt;/span&gt;nano /opt/matrix/synapse/homeserver.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;not a complete&lt;/strong&gt; configuration file, just the parts that needs editing.&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="c1"&gt;## Server ##&lt;/span&gt;

&lt;span class="na"&gt;server_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ Since we are using a proxy for federation we only use the "short" domain here, without the subdomain (&lt;code&gt;synapse.example.com&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;listeners&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8008&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="c1"&gt;# Since it's running in a container we need to listen to 0.0.0.0&lt;/span&gt;
    &lt;span class="c1"&gt;# The port is only exposed on the host and put behind reverse proxy&lt;/span&gt;
    &lt;span class="na"&gt;bind_addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# Previous&lt;/span&gt;
    &lt;span class="c1"&gt;# bind_addresses: ['::1', '127.0.0.1']&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http&lt;/span&gt;
    &lt;span class="na"&gt;x_forwarded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;federation&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;compress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We change from &lt;code&gt;sqlite&lt;/code&gt; to &lt;code&gt;postgres&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="c1"&gt;# Database configuration&lt;/span&gt;
&lt;span class="na"&gt;database&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;psycopg2&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;synapse&lt;/span&gt;
    &lt;span class="c1"&gt;# From your docker-compose.yml&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YOUR_PASSWORD_HERE&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;synapse&lt;/span&gt;

    &lt;span class="c1"&gt;# This hostname is accessible through the docker network and is set &lt;/span&gt;
    &lt;span class="c1"&gt;# by docker-compose. If you change the name of the service it will be different&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll enable registration to be able to test. You can change this later on.&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="c1"&gt;# Enable registration for new users.&lt;/span&gt;
&lt;span class="na"&gt;enable_registration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should be it. I do recommend reading through the config and perhaps another &lt;a href="https://matrix.org/docs/guides/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to checkout all the options but for now let's try and start up our services...&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; /opt/matrix
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
docker-compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and you should get something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;      Name                     Command              State                            Ports
&lt;span class="nt"&gt;--------------------------------------------------------------------------------------------------------------------&lt;/span&gt;
matrix_nginx_1      nginx &lt;span class="nt"&gt;-g&lt;/span&gt; daemon off&lt;span class="p"&gt;;&lt;/span&gt;            Up      80/tcp
matrix_postgres_1   docker-entrypoint.sh postgres   Up      5432/tcp
matrix_synapse_1    /start.sh autostart             Up      0.0.0.0:3478-&amp;gt;3478/tcp, 0.0.0.0:5349-&amp;gt;5349/tcp, 8448/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the services are not &lt;code&gt;up&lt;/code&gt; have a look at the logs with &lt;code&gt;docker-compose logs&lt;/code&gt; (start with &lt;code&gt;docker-compose logs synapse&lt;/code&gt; if the wall of text is too much).&lt;/p&gt;

&lt;h3&gt;
  
  
  Register account and login
&lt;/h3&gt;

&lt;p&gt;If everything looks good, you can now use &lt;a href="https://riot.im/app" rel="noopener noreferrer"&gt;Riot&lt;/a&gt; to create an account and login. You need to select "Advanced" and then change Homeserver URL to your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8szafdc6wjksoo9e8ha.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8szafdc6wjksoo9e8ha.jpg" alt="create-matrix-account-1" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SRV Record
&lt;/h3&gt;

&lt;p&gt;You should also add a &lt;a href="https://github.com/matrix-org/synapse/blob/master/docs/MSC1711_certificates_FAQ.md#if-you-do-have-an-srv-record-currently" rel="noopener noreferrer"&gt;SRV record&lt;/a&gt; to support older homeservers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_matrix._tcp.example.com. IN SRV 10 5 443 synapse.example.com.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;p&gt;If it seems like people on other homeservers can't see your messages, or the other way around, your federation might be broken. &lt;a href="https://matrix.org/federationtester/" rel="noopener noreferrer"&gt;Matrid Federation Tester&lt;/a&gt; is a good first place to check. If you want to see the actual data from the tester, use &lt;a href="https://matrix.org/federationtester/api/report?server_name=matrix.org" rel="noopener noreferrer"&gt;this link&lt;/a&gt; instead but replace the hostname.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hosting Riot
&lt;/h3&gt;

&lt;p&gt;If you want your own Riot you can use this &lt;a href="https://jonnev.se/riot-web-for-matrix-with-docker-and-traefik/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; I've written. It should also possible be to add Riot to the setup above with some modifications to your &lt;code&gt;docker-compose.yml&lt;/code&gt; (add &lt;code&gt;riot.example.com&lt;/code&gt; to &lt;code&gt;traefik.frontend.rule&lt;/code&gt;) and your &lt;code&gt;nginx.conf&lt;/code&gt; (add a new &lt;code&gt;location&lt;/code&gt; and directory to &lt;code&gt;nginx/www/&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks!
&lt;/h3&gt;

&lt;p&gt;If you have any questions or feedback please comment below or hit me up on &lt;a href="https://twitter.com/jonnever" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; 🙌&lt;/p&gt;

</description>
      <category>matrix</category>
      <category>element</category>
      <category>traefik</category>
      <category>docker</category>
    </item>
    <item>
      <title>Element (Riot) web for Matrix with Docker and Traefik</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Sat, 12 Jan 2019 18:24:10 +0000</pubDate>
      <link>https://dev.to/joenas/riot-web-for-matrix--with-docker-and-traefik-50il</link>
      <guid>https://dev.to/joenas/riot-web-for-matrix--with-docker-and-traefik-50il</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewdrqvmhjh7cpryac025.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewdrqvmhjh7cpryac025.png" alt="Element web for Matrix with Docker and Traefik" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So &lt;a href="https://element.io/" rel="noopener noreferrer"&gt;Element&lt;/a&gt; &lt;del&gt;Riot&lt;/del&gt; is the "glossy" web client for Matrix that I prefer to use, at least when not using the desktop one. I've previously written &lt;a href="https://dev.to/joenas/matrix-homeserver-with-docker-5dfn"&gt;a guide&lt;/a&gt; on how to set up your own homeserver and now I thought I'd share how I deploy my Element instance.&lt;/p&gt;

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

&lt;p&gt;As always this guide assumes some general knowledge of Linux and also that you have a server available with these services installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/" rel="noopener noreferrer"&gt;docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/joenas/traefik-with-docker-and-lets-encrypt-35if"&gt;Traefik&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;domain&lt;/strong&gt; to host your Element on*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ The domain needs to be &lt;strong&gt;different than your homeserver domain&lt;/strong&gt;. Read more &lt;a href="https://github.com/vector-im/element-web/blob/17e84bf81574a76c7d5522275585786b115a5e11/README.md#important-security-note" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Using a subdomain &lt;em&gt;should be&lt;/em&gt; fine, ie if your homeserver is at &lt;code&gt;example.com&lt;/code&gt; you could use &lt;code&gt;element.example.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you don't want to use Traefik you could use any other reverse proxy to forward the traffic to the docker container. Be sure to add SSL/TLS to that proxy with for example Let's Encrypt!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're setting up a new VPS feel free to use my &lt;a href="https://m.do.co/c/37d221e6802a" rel="noopener noreferrer"&gt;referral link&lt;/a&gt; at Digital Ocean to get $10 for your server&lt;/em&gt; 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We'll create a directory for Element to live in and some supporting files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p /opt/element 

# If you had to use sudo above, set the permissions to your user to make life easier
sudo chmod -R $USER:$USER -R /opt/element

mkdir /opt/element/config
mkdir /opt/element/versions
touch /opt/element/docker-compose.yml

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  docker-compose, with Traefik
&lt;/h3&gt;

&lt;p&gt;Let's start with our &lt;code&gt;docker-compose&lt;/code&gt;. Scroll down a bit for an example not using Traefik.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano /opt/element/docker-compose.yml


version: '2'

services:
  web:
    image: nginx:1.12-alpine
    container_name: element
    restart: unless-stopped
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:element.example.com"
      - "traefik.port=80"
      - "traefik.docker.network=web"
    volumes:
      - ./element-web:/usr/share/nginx/html/
      - ./config/config.json:/usr/share/nginx/html/config.json

networks:
  web:
    external: true

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

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember&lt;/strong&gt; to replace &lt;code&gt;element.example.com&lt;/code&gt; in &lt;code&gt;traefik.frontend.rule&lt;/code&gt; and change the name of the external &lt;code&gt;network&lt;/code&gt; if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Traefik
&lt;/h3&gt;

&lt;p&gt;Use or modify this if using another reverse proxy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '2'

services:
  web:
    image: nginx:1.12-alpine
    container_name: element
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - ./element-web:/usr/share/nginx/html/
      - ./config/config.json:/usr/share/nginx/html/config.json

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fetch latest Element version
&lt;/h2&gt;

&lt;p&gt;Now we fetch the tarball of the lastest Element release, extract it and put it in the &lt;code&gt;versions&lt;/code&gt; folder. Then we create symlink to be able to update the version in an easy way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget -qO- https://github.com/vector-im/element-web/releases/download/v0.17.8/riot-v0.17.8.tar.gz | tar xvz -C /opt/element/versions
ln -s /opt/element/versions/riot-v0.17.8 /opt/element/element-web

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

&lt;/div&gt;



&lt;p&gt;☝️ Be sure to check the &lt;a href="https://github.com/vector-im/element-web/releases" rel="noopener noreferrer"&gt;releases&lt;/a&gt; page and update the commands above accordingly if there is a newer release!&lt;/p&gt;

&lt;h2&gt;
  
  
  Config
&lt;/h2&gt;

&lt;p&gt;Copy the &lt;a href="https://github.com/vector-im/element-web/blob/master/config.sample.json" rel="noopener noreferrer"&gt;sample config&lt;/a&gt; and edit it to your needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp element-web/riot-v0.17.8/config.sample.json /opt/element/config/config.json
nano /opt/element/config/config.json

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

&lt;/div&gt;



&lt;p&gt;I only changed these values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "default_hs_url": "https://matrix.example.com",
    "brand": "Custom Brand",
    "roomDirectory": {
        "servers": [
            "matrix.example.com",
            "matrix.org"
        ]
    }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run it!
&lt;/h2&gt;

&lt;p&gt;And we're good to go. Run &lt;code&gt;docker-compose up -d&lt;/code&gt; and you should be able to access your domain and login 😃&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating
&lt;/h2&gt;

&lt;p&gt;To update to a new Element version check the releases page, fetch the new version by modifying these commands. Then link the new release, stop and start your container again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget -qO- https://github.com/vector-im/element-web/releases/download/v0.17.8/VERSION.tar.gz | tar xvz -C /opt/element/versions
docker-compose stop
rm element-web
ln -s /opt/element/versions/VERSION /opt/element/element-web
docker-compose up -d

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

&lt;/div&gt;



</description>
      <category>matrix</category>
      <category>element</category>
      <category>docker</category>
      <category>traefik</category>
    </item>
    <item>
      <title>Web client for Gammu SMSD</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Tue, 01 Jan 2019 16:55:00 +0000</pubDate>
      <link>https://dev.to/joenas/web-client-for-gammu-smsd-3n94</link>
      <guid>https://dev.to/joenas/web-client-for-gammu-smsd-3n94</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b8s66tp0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/01/Screenshot-2019-01-01-at-14.06.59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b8s66tp0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://jonnev.se/content/images/2019/01/Screenshot-2019-01-01-at-14.06.59.png" alt="Web client for Gammu SMSD" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally I have released the client I've written for &lt;a href="https://wammu.eu/smsd/"&gt;Gammu SMSD&lt;/a&gt;, which I use on my Raspberry Pi Zero &lt;a href="https://dev.to/joenas/raspberry-pi-zero-as-sms-gateway-58gk"&gt;SMS gateway&lt;/a&gt;. It's a React app with a Node Express backend to fetch the stored messages from a Postgres database. While still a &lt;em&gt;WIP&lt;/em&gt; (needs auth and some UI love) it works fine for receiving and sending/replying to SMS.&lt;/p&gt;

&lt;p&gt;💻👉 The &lt;strong&gt;source code&lt;/strong&gt; is &lt;a href="https://github.com/joenas/gammu-client"&gt;here&lt;/a&gt; with instructions for the different ways of deploying.&lt;/p&gt;

&lt;p&gt;I myself run it directly on my Raspberry Pi with Docker but it's also possible to have it connect to an existing Postgres instance in case you already have that set up. Or just run it on a separate machine, preferably with &lt;code&gt;docker-compose&lt;/code&gt; and have your &lt;code&gt;gammu-smsd&lt;/code&gt; connect to the database container.&lt;/p&gt;

&lt;p&gt;I learnt quite a lot building this, both about some Gammu internals and React/Node. My first try was to build the backend in &lt;a href="https://crystal-lang.org/"&gt;Crystal&lt;/a&gt; because I figured having a small binary to ship would be perfect for a RPi but that turned out being harder then expected. That might be content for another blog post...&lt;/p&gt;

&lt;p&gt;It &lt;strong&gt;also&lt;/strong&gt; turned out building Docker images on a RPi was messy which led me to the discovery I wrote about in my &lt;a href="https://dev.to/joenas/building-node-docker-images-for--raspberry-pi-zero-2hfm"&gt;last post&lt;/a&gt;. I included a version of the script from my example in this repository too, to make it easy for others to build and deploy the &lt;code&gt;armv6&lt;/code&gt; version of the Docker image.&lt;/p&gt;

&lt;p&gt;Anyways I hope someone finds this useful and please drop me a line with any feedback you might have!&lt;/p&gt;

</description>
      <category>gammu</category>
      <category>sms</category>
      <category>rpizero</category>
      <category>raspberrypi</category>
    </item>
    <item>
      <title>Building Node Docker images for Raspberry Pi Zero</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Sun, 02 Dec 2018 16:00:00 +0000</pubDate>
      <link>https://dev.to/joenas/building-node-docker-images-for--raspberry-pi-zero-2hfm</link>
      <guid>https://dev.to/joenas/building-node-docker-images-for--raspberry-pi-zero-2hfm</guid>
      <description>&lt;p&gt;While developing a web app for my &lt;a href="https://dev.to/joenas/raspberry-pi-zero-as-sms-gateway-4ihl-temp-slug-4032545"&gt;Raspberry Pi Zero SMS gateway&lt;/a&gt; I ran into trouble. I wanted to be able to run the app in Docker but building an image from a Dockerfile on the RPi0 was incredibly slow and I didn't manage to complete it because my Pi ran out of memory.&lt;/p&gt;

&lt;p&gt;I thought about creating the image locally and pushing it to Docker Hub but it felt a bit overkill for small, personal apps. After some thinking and googling I realised that you can &lt;a href="https://docs.docker.com/engine/reference/commandline/save/"&gt;save&lt;/a&gt; docker images and then &lt;a href="https://docs.docker.com/engine/reference/commandline/load/"&gt;load&lt;/a&gt; them on another computer.&lt;/p&gt;

&lt;p&gt;There are 2 ways to go about this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;npm&lt;/code&gt; on your computer, fetch all dependencies (&lt;code&gt;node_modules&lt;/code&gt;) and copy them together with the code into the &lt;code&gt;armv6&lt;/code&gt; image.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm&lt;/code&gt; in a container with a &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;multistage build&lt;/a&gt; and then copy the files to image.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  With local NPM
&lt;/h3&gt;

&lt;p&gt;This is more useful and faster with an app you're developing yourself, since you probably have &lt;code&gt;npm&lt;/code&gt; installed.&lt;/p&gt;

&lt;p&gt;Fetch the deps as usual with &lt;code&gt;npm install&lt;/code&gt; then add a &lt;code&gt;Dockerfile&lt;/code&gt; (and possibly a &lt;code&gt;.dockerignore&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;# Check for your version: https://hub.docker.com/r/arm32v6/node/tags/
FROM arm32v6/node:8.14.0-alpine
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH

# Either be specific with what to add, docker caches every step
ADD package.json /app/package.json
ADD package-lock.json /app/package-lock.json
ADD node_modules /app/node_modules
ADD app.js /app/app.js

# Or add the whole dir, I always use a .dockerignore file when doing that
ADD . /app

ENV PORT=5000
EXPOSE 5000
CMD ["npm", "start"]

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multistage build
&lt;/h3&gt;

&lt;p&gt;This is useful when you want to make an image of someone elses project and/or don't want to install &lt;code&gt;npm&lt;/code&gt; on your machine.&lt;/p&gt;

&lt;p&gt;Since you can't run the &lt;code&gt;arm32v6/node&lt;/code&gt; on your computer, you need to first use a working node image to fetch/build your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Fetch node_modules for backend, nothing here except 
# the node_modules dir ends up in the final image
FROM node:8.14.0-alpine as builder
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json /app/package.json
RUN npm install

# Add the files to arm image
FROM arm32v6/node:8.14.0-alpine
RUN mkdir /app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH

# Same as earlier, be specific or copy everything
ADD package.json /app/package.json
ADD package-lock.json /app/package-lock.json
ADD . /app

COPY --from=builder /app/node_modules /app/node_modules

ENV PORT=5000
EXPOSE 5000
CMD ["npm", "start"]

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building
&lt;/h3&gt;

&lt;p&gt;Then you can build and save your image...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t my-app -f Dockerfile .
docker save -o my-app.tar my-app
ls
# my-app.tar

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

&lt;/div&gt;



&lt;p&gt;... transfer it to your RPi (with &lt;code&gt;scp&lt;/code&gt; or whatever) and load it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# On RPi
docker load -i my-app.tar
docker run --rm -p 5000:5000 my-app

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automation
&lt;/h2&gt;

&lt;p&gt;Doing this can get tedious if you make a lot of changes to your app, so I created a simple bash script that you can use: &lt;a href="https://github.com/joenas/node-docker-raspberry-zero"&gt;https://github.com/joenas/node-docker-raspberry-zero&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : In my repo I've named the file &lt;code&gt;Dockerfile.armv6&lt;/code&gt; because I already have a &lt;code&gt;Dockerfile&lt;/code&gt; for running the app on other architectures that doesn't require a specific docker image. I also tag the image with the suffix &lt;code&gt;:armv6&lt;/code&gt;. The commands above would then be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Build &amp;amp; save
docker build -t my-app:armv6 -f Dockerfile.armv6 .
docker save -o my-app.tar my-app:armv6

# Load &amp;amp; run
docker load -i my-app.tar
docker run --rm -p 5000:5000 my-app:armv6

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sample .dockerignore
&lt;/h3&gt;

&lt;p&gt;Here's a sample &lt;code&gt;.dockerignore&lt;/code&gt; file you can use to not include all the files in your image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/.git/
.gitignore

docker-compose.yml
Dockerfile*
LICENSE
README.md
*.tar

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sharing is caring
&lt;/h2&gt;

&lt;p&gt;I hope you have any use for this and I'd love to see more stuff for the RPi0/1 so please comment below if you create something! 🙏&lt;/p&gt;

</description>
      <category>docker</category>
      <category>rpizero</category>
      <category>node</category>
      <category>armv6</category>
    </item>
    <item>
      <title>Easy InfluxDB &amp; Grafana setup with Traefik</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Wed, 15 Aug 2018 20:42:03 +0000</pubDate>
      <link>https://dev.to/joenas/easy-influxdb--grafana-setup-with-traefik-172j</link>
      <guid>https://dev.to/joenas/easy-influxdb--grafana-setup-with-traefik-172j</guid>
      <description>&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%2F3t2c7vlu7mrdxzytpxe2.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%2F3t2c7vlu7mrdxzytpxe2.png" alt="Easy InfluxDB &amp;amp; Grafana setup with Traefik" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is more exciting than staring at graphs? Nothing right. If you just love some system metrics or want to display the temperature in your home over time, a time series database like &lt;a href="https://www.influxdata.com/time-series-platform/influxdb/" rel="noopener noreferrer"&gt;InfluxDB&lt;/a&gt; combined with &lt;a href="https://grafana.com/grafana" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; is the way to go!&lt;/p&gt;

&lt;p&gt;This guide will show you an easy way to get both of these systems up in no time with the help of Traefik and Docker. If you &lt;strong&gt;already have&lt;/strong&gt; a server with Traefik running then continue. Otherwise I recommend you read my &lt;a href="https://dev.to/joenas/traefik-with-docker-and-lets-encrypt-pon-temp-slug-5403439"&gt;previous post&lt;/a&gt; and you'll be back here soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Let's make a directory for your data to live in, as sudo if needed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su
mkdir /opt/influx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need an internal docker network for the services to communicate on&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create influx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  docker-compose.yml
&lt;/h3&gt;

&lt;p&gt;We'll put our services in a docker-compose file to be able to easily manage things. We'll put the basics in first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano /opt/influx/docker-compose.yml

version: "2"
services:
  influxdb:
    # We'll add stuff here
  grafana:
    # and here

networks:
  default:
    external:
      name: influx # The network we created
  web:
    external: true # For traefik
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  InfluxDB
&lt;/h3&gt;

&lt;p&gt;There are a number of &lt;a href="https://jonnev.se/easy-influxdb-grafana-setup-with-traefik/(https://hub.docker.com/_/influxdb/)" rel="noopener noreferrer"&gt;environment variables&lt;/a&gt; available for the image of which we'll use a few.&lt;/p&gt;

&lt;p&gt;If you want to send data to Influx from the outside world you need to have a &lt;em&gt;frontend&lt;/em&gt; in Traefik with the port and hostname, if not then remove the &lt;code&gt;labels&lt;/code&gt; section. You can also remove &lt;code&gt;- web&lt;/code&gt; under &lt;code&gt;networks&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also need a user with write access and a database to write to. For some nice system metrics I use &lt;a href="https://www.influxdata.com/time-series-platform/telegraf/" rel="noopener noreferrer"&gt;telegraf&lt;/a&gt; so here we'll have the InfluxDB image create that database and user initially. If you want to use something else as input just change the values accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;influxdb:
    image: influxdb:1.5.4-alpine
    restart: unless-stopped
    ports:
      - "127.0.0.1:8086:8086"
    volumes:
      - ./influxdb:/var/lib/influxdb
    environment:
      - INFLUXDB_DB=telegraf 
      - INFLUXDB_USER=telegraf
      - INFLUXDB_USER_PASSWORD=secretpassword
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:influxdb.example.com"
      - "traefik.port=8086"
      - "traefik.docker.network=web"
    networks:
      - web
      - default # The external "influx" network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember to replace&lt;/strong&gt; &lt;code&gt;example.com&lt;/code&gt; in &lt;code&gt;traefik.frontend.rule&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grafana
&lt;/h3&gt;

&lt;p&gt;Now let's add the Grafana service so that we have something to display our future stats with. First let's add a volume for persistent storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker volume create grafana-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this to &lt;code&gt;docker-compose.yml&lt;/code&gt; between &lt;code&gt;influxdb&lt;/code&gt; and &lt;code&gt;networks&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;grafana:
    image: grafana/grafana:4.4.1
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
     - grafana-storage:/var/lib/grafana
     - ./log/grafana:/var/log/grafana
    environment:
     - GF_SECURITY_ADMIN_PASSWORD=supersecret
     # Comment out if you have users that should sign up
     - GF_USERS_ALLOW_SIGN_UP=false 
     - GF_SERVER_ROOT_URL=https://grafana.example.com
    labels:
      - "traefik.enable=true"
      - "traefik.frontend.rule=Host:grafana.example.com"
      - "traefik.port=3000"
      - "traefik.docker.network=web"
    networks:
      - web
      - default

volumes:
  grafana-storage:
    external: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember to replace&lt;/strong&gt; &lt;code&gt;grafana.example.com&lt;/code&gt; in the 2 places above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grafana UI
&lt;/h3&gt;

&lt;p&gt;Now you should be able to run the services!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# To start
docker-compose up -d
# Check logs
docker-compose logs
# Check processes
docker-compose ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything looks alright, open up your Grafana URL and you should be greeted with a login screen. Use &lt;code&gt;admin&lt;/code&gt; and the password you set as &lt;code&gt;GF_SECURITY_ADMIN_PASSWORD&lt;/code&gt;. After logging in click "Add data source" and fill out the fields like this.&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%2Ff91gvi831e4q49f5cqt7.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%2Ff91gvi831e4q49f5cqt7.png" alt="Easy InfluxDB &amp;amp; Grafana setup with Traefik" width="800" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hostname &lt;code&gt;influx_influxdb_1&lt;/code&gt; in the Url setting is from the docker network &lt;code&gt;influx&lt;/code&gt;, since the services are in separate containers you can't use &lt;code&gt;localhost&lt;/code&gt; here.&lt;/p&gt;

&lt;p&gt;If you're getting &lt;strong&gt;error messages when saving/testing the data source and using Safari&lt;/strong&gt; , try another browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting some data in there
&lt;/h3&gt;

&lt;p&gt;If you already have a way to send data to Influx, then you're done! If not then previously mentioned &lt;code&gt;telegraf&lt;/code&gt; is just as easy to set up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /opt/telegraf
cd /opt/telegraf
nano docker-compose.yml

version: "2"
services:
  telegraf:
    image: telegraf:1.5.2
    restart: unless-stopped
    volumes:
      - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
      # For docker stats
      - /var/run/docker.sock:/var/run/docker.sock:ro
    labels:
      - "traefik.enable=false"
    networks:
      - default

networks:
  default:
    external:
      name: influx

nano telegraf.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a very simple conf just to get up and running. Feel free to use the &lt;a href="https://github.com/influxdata/telegraf/blob/master/etc/telegraf.conf" rel="noopener noreferrer"&gt;default one&lt;/a&gt; for more options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Configuration for telegraf agent
[agent]
  interval = "10s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "10s"
  flush_jitter = "0s"
  precision = ""
  debug = false
  quiet = false
  logfile = ""
  hostname = "MYHOST"

###############################################################################
# OUTPUT PLUGINS #
###############################################################################

# Configuration for influxdb server to send metrics to
[[outputs.influxdb]]
  urls = ["http://influxdb:8086"] # required
  database = "telegraf" # required
  username = "telegraf"
  password = "secretpassword"
  retention_policy = ""
  write_consistency = "any"
  timeout = "5s"

###############################################################################
# INPUT PLUGINS #
###############################################################################

# Read metrics about cpu usage
[[inputs.cpu]]
  ## Whether to report per-cpu stats or not
  percpu = true
  ## Whether to report total system cpu stats or not
  totalcpu = true
  ## If true, collect raw CPU time metrics.
  collect_cpu_time = false

# Read metrics about disk usage by mount point
[[inputs.disk]]
  ## Ignore some mountpoints by filesystem type. For example (dev)tmpfs (usually
  ## present on /run, /var/run, /dev/shm or /dev).
  ignore_fs = ["tmpfs", "devtmpfs"]

# Read metrics about disk IO by device
[[inputs.diskio]]
  ## Setting devices will restrict the stats to the specified devices.
  # devices = ["sda", "sdb"]

# Get kernel statistics from /proc/stat
[[inputs.kernel]]
  # no configuration

# Read metrics about memory usage
[[inputs.mem]]
  # no configuration

# Get the number of processes and group them by status
[[inputs.processes]]
  # no configuration

# Read metrics about swap memory usage
[[inputs.swap]]
  # no configuration

# Read metrics about system load &amp;amp; uptime
[[inputs.system]]
  # no configuration

# # Read metrics about docker containers
[[inputs.docker]]
  endpoint = "unix:///var/run/docker.sock"
  timeout = "5s"

# # Read metrics about network interface usage
[[inputs.net]]
  interfaces = ["eth*"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the service and you'll have some data coming in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up -d
docker-compose logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go back to your Grafana instance and create some &lt;a href="https://grafana.com/dashboards?dataSource=influxdb" rel="noopener noreferrer"&gt;dashboards&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%2F19irsmcbtub7pw9r9sts.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%2F19irsmcbtub7pw9r9sts.png" alt="Easy InfluxDB &amp;amp; Grafana setup with Traefik" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;☝️ &lt;a href="https://grafana.com/dashboards/4823" rel="noopener noreferrer"&gt;Telegraf sysstats&lt;/a&gt; by &lt;a href="https://grafana.com/orgs/broferek" rel="noopener noreferrer"&gt;broferek&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;If you noticed any factual errors, spelling mistakes (yes), best practises I'm not aware of or run into any trouble please comment below or hit me up on &lt;a href="https://twitter.com/jonnever" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; 🙌&lt;/p&gt;

</description>
      <category>influxdb</category>
      <category>grafana</category>
      <category>traefik</category>
      <category>docker</category>
    </item>
    <item>
      <title>Traefik with Docker and Let's Encrypt</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Wed, 14 Mar 2018 17:25:00 +0000</pubDate>
      <link>https://dev.to/joenas/traefik-with-docker-and-lets-encrypt-35if</link>
      <guid>https://dev.to/joenas/traefik-with-docker-and-lets-encrypt-35if</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4py0sig4yrtvwpdxavtn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4py0sig4yrtvwpdxavtn.png" alt="Traefik with Docker and Let's Encrypt" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I run most of my services in Docker and previously I was using &lt;code&gt;nginx&lt;/code&gt; as a reverse and TLS termination proxy together with Let's Encrypt. That worked great but everytime I wanted to try something new I had to copy-paste another conf and change a few values. I probably could have automated that to some extent and there are others who have but with my recent migration to VPSes I figured I'd give &lt;a href="https://traefik.io" rel="noopener noreferrer"&gt;Traefik&lt;/a&gt; a try, if nothing else for their &lt;strong&gt;awesome&lt;/strong&gt; logo!&lt;/p&gt;

&lt;p&gt;Here I'll show you how to set up Traefik with GUI, http redirection and automatic Let's Encrypt certificates. We'll also add &lt;em&gt;basic auth&lt;/em&gt; to the Traefik GUI. &lt;/p&gt;

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

&lt;p&gt;This guide assumes some general knowledge of Linux and that you have a server available with these services installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/" rel="noopener noreferrer"&gt;docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;domain&lt;/strong&gt; to host your apps on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For cheap and good servers, checkout &lt;a href="https://www.digitalocean.com" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; or &lt;a href="https://www.hetzner.com/cloud" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt;. Also I always recommend &lt;a href="https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; when setting up a new VPS.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to use Digital Ocean feel free to use my &lt;a href="https://m.do.co/c/37d221e6802a" rel="noopener noreferrer"&gt;referral link&lt;/a&gt; to get $10 for your server&lt;/em&gt; 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;This is based on the &lt;a href="https://docs.traefik.io/user-guide/docker-and-lets-encrypt/" rel="noopener noreferrer"&gt;official guide&lt;/a&gt; but with a few additions. I will show you how to add the web dashboard and API - protected by Basic Auth - mostly because it's fun. If you have no use for it or believe it to be &lt;a href="https://docs.traefik.io/configuration/api/#security" rel="noopener noreferrer"&gt;unsafe&lt;/a&gt;, you can skip that part.&lt;/p&gt;

&lt;p&gt;First start with creating a network for your web-facing containers to connect to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we create a directory and the necessary files, as sudo if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su
mkdir -p /opt/traefik
touch /opt/traefik/docker-compose.yml
touch /opt/traefik/acme.json &amp;amp;&amp;amp; chmod 600 /opt/traefik/acme.json
touch /opt/traefik/traefik.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add our &lt;code&gt;docker-compose&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;nano /opt/traefik/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v1.7.12-alpine&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--configFile=/traefik.toml&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/opt/traefik/traefik.toml:/traefik.toml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/opt/traefik/acme.json:/acme.json&lt;/span&gt;
    &lt;span class="c1"&gt;# REMOVE this section if you don't want the dashboard/API&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend.rule=Host:example.com"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.port=8080"&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember to replace &lt;code&gt;example.com&lt;/code&gt; in &lt;code&gt;traefik.frontend.rule&lt;/code&gt;&lt;/strong&gt; if you keep the API.&lt;/p&gt;

&lt;p&gt;... and the config for Traefik...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano /opt/traefik/traefik.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Change this if needed&lt;/span&gt;
&lt;span class="s"&gt;logLevel = "ERROR"&lt;/span&gt;
&lt;span class="s"&gt;defaultEntryPoints = ["https","http"]&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;entryPoints&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;entryPoints.http&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="s"&gt;address = ":80"&lt;/span&gt;
    &lt;span class="s"&gt;[entryPoints.http.redirect]&lt;/span&gt;
    &lt;span class="s"&gt;entryPoint = "https"&lt;/span&gt;
  &lt;span class="s"&gt;[entryPoints.https]&lt;/span&gt;
    &lt;span class="s"&gt;address = ":443"&lt;/span&gt;
  &lt;span class="s"&gt;[entryPoints.https.tls]&lt;/span&gt;

&lt;span class="c1"&gt;# REMOVE this section if you don't want the dashboard/API&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;entryPoint = "api"&lt;/span&gt;
&lt;span class="s"&gt;dashboard = &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;retry&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;endpoint = "unix:///var/run/docker.sock"&lt;/span&gt;
&lt;span class="s"&gt;domain = "mydomain"&lt;/span&gt;
&lt;span class="s"&gt;watch = &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="c1"&gt;# I prefer to expose my containers explicitly&lt;/span&gt;
&lt;span class="s"&gt;exposedbydefault = &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acme&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;email = "myemail"&lt;/span&gt;
&lt;span class="s"&gt;storage = "acme.json"&lt;/span&gt;
&lt;span class="s"&gt;entryPoint = "https"&lt;/span&gt;
&lt;span class="s"&gt;OnHostRule = &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acme.httpChallenge&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;entryPoint = "http"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Add your domain and email under &lt;code&gt;[docker]&lt;/code&gt; and &lt;code&gt;[acme]&lt;/code&gt;, respectively.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;... and we should be good to go!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /opt/traefik/
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the logs (&lt;code&gt;docker-compose logs&lt;/code&gt;) and head to your configured domain and you should see something like this (screenshot was taken a few versions back, it's been redesigned).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3neio6am1cqbdo8dxkdf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3neio6am1cqbdo8dxkdf.png" alt="Screen-Shot-2018-03-13-at-22.19.45" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic auth
&lt;/h3&gt;

&lt;p&gt;Since we have exposed the API of Traefik we'd like to have some authentication. Basic auth is supported so let's add that. Run this for the username you want - for example &lt;code&gt;admin&lt;/code&gt; - and enter your password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install apache2-utils
htpasswd -n username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what I got for admin/admin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;admin:$apr1$IBj9Hfsd$kf7vXLpY4/9XD365jcp/n1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that needs to go in the &lt;code&gt;traefik.toml&lt;/code&gt; but to work any &lt;code&gt;$&lt;/code&gt; signs have to be escaped with another &lt;code&gt;$&lt;/code&gt;.&lt;br&gt;
Add this to the &lt;code&gt;[entrypoints]&lt;/code&gt;-section...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  [entryPoints.api]
    address = ":8080"
    [entryPoints.api.auth]
     [entryPoints.api.auth.basic]
       users = [
         "admin:$$apr1$$IBj9Hfsd$$kf7vXLpY4/9XD365jcp/n1"
       ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now stop and rebuild your service...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose stop
docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and you should have basic auth!&lt;/p&gt;

&lt;p&gt;&lt;a href="/content/images/2018/03/Screen-Shot-2018-03-13-at-22.30.58.png" class="article-body-image-wrapper"&gt;&lt;img src="/content/images/2018/03/Screen-Shot-2018-03-13-at-22.30.58.png" alt="Screen-Shot-2018-03-13-at-22.30.58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a container
&lt;/h2&gt;

&lt;p&gt;Now of course to have any use for this we need a container! Why not a blog with &lt;code&gt;ghost&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;Create a directory and a &lt;code&gt;docker-compose.yml&lt;/code&gt;, remember to change the domain and add the hostname to your DNS! 👍&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p /opt/ghost
nano /opt/ghost/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost:alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# This one is important since we default to not expose&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.frontend.rule=Host:blog.example.com"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.port=2368"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.docker.network=web"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/opt/ghost/blog:/var/lib/ghost/content&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;url=https://blog.example.com&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the usual &lt;code&gt;docker-compose up -d&lt;/code&gt; and &lt;em&gt;voilà&lt;/em&gt; blog up with SSL/TLS and all, pure magic 😀&lt;/p&gt;

&lt;h3&gt;
  
  
  Updates
&lt;/h3&gt;

&lt;p&gt;2019-07-15: Updated to newest version (&lt;code&gt;v1.7.12&lt;/code&gt;) and also changed to only using &lt;code&gt;traefik.toml&lt;/code&gt; instead of mixing with a &lt;code&gt;command&lt;/code&gt; in &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

</description>
      <category>traefik</category>
      <category>docker</category>
      <category>https</category>
    </item>
    <item>
      <title>High memory usage in Influxdb</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Sun, 11 Mar 2018 17:14:46 +0000</pubDate>
      <link>https://dev.to/joenas/high-memory-usage-in-influxdb-5bl5</link>
      <guid>https://dev.to/joenas/high-memory-usage-in-influxdb-5bl5</guid>
      <description>&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%2Fks74n61zqciiam0s53zr.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%2Fks74n61zqciiam0s53zr.png" alt="High memory usage in Influxdb" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently moved my various services from a bare metal server at Hetzner to their new &lt;a href="https://www.hetzner.com/cloud" rel="noopener noreferrer"&gt;cloud&lt;/a&gt; and a couple of different VPSes, which saves me quite a few dollars (kronor actually but...) a month. Most of my services run in Docker and I've got &lt;a href="https://www.influxdata.com/time-series-platform/telegraf/" rel="noopener noreferrer"&gt;telegraf&lt;/a&gt; running on all servers to monitor my stuff. Mostly because I enjoy looking at all them dashboards in &lt;a href="https://grafana.com" rel="noopener noreferrer"&gt;grafana&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;After my migration one of the servers started reporting very high memory usage and it turned out to be the InfluxDB container growing more or less indefinitely. I didn't have that problem before, not that I was aware of atleast, but then again I had 32GB of memory on the old server and wasn't really paying as much attention to the resource consumption of each service.&lt;/p&gt;

&lt;p&gt;Anywho, after some research I found &lt;a href="http://puyuan.github.io/influxdb-tag-cardinality-memory-performance" rel="noopener noreferrer"&gt;this article&lt;/a&gt; explaining the problem. The takeaway is that &lt;strong&gt;Influx creates an in-memory index with all tags&lt;/strong&gt; and that quickly grows with a lot of data.&lt;/p&gt;

&lt;p&gt;So how to fix? In my case I only have two services I've written myself sending data to Influx and neither were using tags excessively so I started examining the telegraf plugins I had enabled. I'm not 100% certain but I'm pretty sure the culprit was the &lt;a href="https://github.com/influxdata/telegraf/tree/master/plugins/inputs/docker" rel="noopener noreferrer"&gt;docker plugin&lt;/a&gt;. That plugin paired with my &lt;code&gt;dokku&lt;/code&gt; host which creates new containers in abundance with each deploy of a service made up for quite a lot of data. Fortunally the plugin has a setting &lt;code&gt;container_name_include = []&lt;/code&gt; that accepts globs, so limiting the amount of containers reported made a big difference. Especially since the docker telegraf data has a lot of &lt;code&gt;tags&lt;/code&gt; in it.&lt;/p&gt;

&lt;p&gt;I also set a new &lt;a href="https://docs.influxdata.com/influxdb/v0.9/query_language/database_management/#create-retention-policies-with-create-retention-policy" rel="noopener noreferrer"&gt;retention policy&lt;/a&gt; on my database like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE RETENTION POLICY one_month ON telegraf DURATION 4w REPLICATION 1 DEFAULT;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and deleted a lot of old data, for example from the docker plugin with a simple &lt;code&gt;DROP SERIES docker&lt;/code&gt; (etc, there are about 4 series).&lt;/p&gt;

&lt;p&gt;The result? Pretty good.&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%2Fmctv7tahgs2wq2rl0diu.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%2Fmctv7tahgs2wq2rl0diu.png" alt="High memory usage in Influxdb" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>influxdb</category>
      <category>grafana</category>
      <category>docker</category>
    </item>
    <item>
      <title>Raspberry Pi Zero as SMS gateway</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Tue, 23 Jan 2018 16:00:00 +0000</pubDate>
      <link>https://dev.to/joenas/raspberry-pi-zero-as-sms-gateway-58gk</link>
      <guid>https://dev.to/joenas/raspberry-pi-zero-as-sms-gateway-58gk</guid>
      <description>&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%2Fk85ohr701pmod0izhj0m.JPG" 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%2Fk85ohr701pmod0izhj0m.JPG" alt="Raspberry Pi Zero as SMS gateway" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've previously written about setting up a &lt;a href="https://dev.to/joenas/sms-gateway-and-push-notifications-4432-temp-slug-2187664"&gt;SMS gateway&lt;/a&gt; using a 3G modem. I had that plugged into my HTPC and honestly it just didn't look good next to the TV. I figured using a Raspberry Pi and just stash it away somewhere would be better. At the same time I was preparing to create a &lt;a href="https://magicmirror.builders" rel="noopener noreferrer"&gt;Magic Mirror&lt;/a&gt; of sorts (without the actual mirror) and I accidentally (?) stumbled across the &lt;a href="https://www.adafruit.com/product/2542" rel="noopener noreferrer"&gt;Adafruit Fona 808&lt;/a&gt; when doing my regular window shopping for Pi stuff.&lt;/p&gt;

&lt;p&gt;After some reading up - there are a lot of great tutorials I'll link to at the end of the post - I felt that there should be something a bit easier and I found a couple of HATs designed for the Pi.&lt;/p&gt;

&lt;p&gt;I ended up buying one from &lt;a href="http://sixfab.com/product/gsmgprs-shield/" rel="noopener noreferrer"&gt;Sixfab&lt;/a&gt; but either of &lt;a href="https://garatronic.fr/index.php/en/nadhat-en" rel="noopener noreferrer"&gt;these&lt;/a&gt; &lt;a href="https://www.waveshare.com/gsm-gprs-gnss-hat.htm" rel="noopener noreferrer"&gt;two&lt;/a&gt; should work as well. (If you try one of those I'd love to hear about it!)&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%2F7t6b0n298f07w8plxj6s.jpg" 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%2F7t6b0n298f07w8plxj6s.jpg" alt="Raspberry Pi Zero as SMS gateway" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Assembling
&lt;/h3&gt;

&lt;p&gt;I own a soldering iron but prefer not to use it unless necessary so imagine my joy when I found the &lt;a href="https://thepihut.com/products/gpio-hammer-header-solderless" rel="noopener noreferrer"&gt;solderless GPIO header&lt;/a&gt;. While at it I also bought a nice little &lt;a href="https://thepihut.com/products/zebra-zero-for-raspberry-pi-zero-black-ice" rel="noopener noreferrer"&gt;case&lt;/a&gt;. Assembling the header and case was pretty easy and the result great! Just follow &lt;a href="https://learn.pimoroni.com/tutorial/sandyj/fitting-hammer-headers" rel="noopener noreferrer"&gt;this guide&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%2F59vm0myb2cj1x0kmtsqu.JPG" 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%2F59vm0myb2cj1x0kmtsqu.JPG" alt="Raspberry Pi Zero as SMS gateway" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Zero mounted in the rig&lt;/em&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%2F3m3m8dwdhank8hqi3d6d.JPG" 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%2F3m3m8dwdhank8hqi3d6d.JPG" alt="Raspberry Pi Zero as SMS gateway" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Header attached&lt;/em&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%2F0ld20hzd9c0hd6oirbv0.JPG" 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%2F0ld20hzd9c0hd6oirbv0.JPG" alt="Raspberry Pi Zero as SMS gateway" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Case assembled&lt;/em&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%2F30pi6u31004fmbfdvnmg.JPG" 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%2F30pi6u31004fmbfdvnmg.JPG" alt="Raspberry Pi Zero as SMS gateway" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;and finally GSM pHAT added&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Now to getting the thing to work! There's a &lt;a href="http://sixfab.com/updated-tutorial-2-make-a-ppp-internet-connection-with-sixfab-gprs-shield-on-raspberry-pi/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; at Sixfab, but it's aimed at setting up a GRPS connection. I was just interested in sending and receiving sms with &lt;code&gt;gammu&lt;/code&gt; which I already had installed (with &lt;code&gt;postgres&lt;/code&gt; as backend this time).&lt;/p&gt;

&lt;p&gt;First you need to disable the serial console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl stop serial-getty@ttyAMA0.service
sudo systemctl disable serial-getty@ttyAMA0.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one worked for me. Depending on your Pi you might need to do this instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl stop serial-getty@ttyS0.service
sudo systemctl disable serial-getty@ttyS0.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then remove the corresponding line in boot commandline&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /boot/cmdline.txt
# Remove "console=serial0, 115200" or "console=ttyAMA0, 115200"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable UART and disable Bluetooth on serial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /boot/config.txt
# Add these
enable_uart=1
dtoverlay=pi3-disable-bt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last bit with disabling BT did the trick for me and took a reasonable amount of googling to find out. I don't use BT but if you do I recall seeing a solution somewhere...&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Reboot your Pi&lt;/strong&gt; and to test the connection to the pHat do this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/gammurc
# Add 
[gammu]
device = /dev/serial0
connection = at115200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And gammu should find your device&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo gammu --identify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also interact with the shield via &lt;code&gt;screen&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;sudo screen /dev/serial0 115200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type &lt;code&gt;AT&lt;/code&gt;, press enter and you should get &lt;code&gt;OK&lt;/code&gt; back. &lt;code&gt;Ctrl-A, D&lt;/code&gt; to exit.&lt;/p&gt;

&lt;p&gt;If everything is ok you should now be able to use &lt;code&gt;gammu-smsd&lt;/code&gt; to send and receive SMS. First &lt;strong&gt;power up the shield&lt;/strong&gt; by pressing POWER-UP for a few seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/gammu-smsdrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is my entire config with postgres and all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[gammu]
port = /dev/serial0
connection = at115200

# SMSD configuration, see gammu-smsdrc(5)
[smsd]
service = sql
driver = native_pgsql
host = localhost
user = smsd
password = SUPERSECRET
database = smsd
RunOnReceive = python /opt/gammu/receivesms.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sending SMS!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo service gammu-smsd restart
gammu-smsd-inject TEXT 123456 -unicode -text "Oh hai"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've also written a small html client with an API backend for &lt;code&gt;gammu&lt;/code&gt; that I'll (probably) publish soon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading list
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/InitialState/fona-pi-zero/wiki" rel="noopener noreferrer"&gt;Fona + Pi Zero&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/benstr/TUT-raspi-cellular-gateway/blob/master/readme.md" rel="noopener noreferrer"&gt;Pi Wifi gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.adafruit.com/adafruit-fona-3g-cellular-gps-breakout/overview" rel="noopener noreferrer"&gt;Another Fona&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.itead.cc/blog/raspberry-pi-sim900-gsmgprs-module-adapter-kit" rel="noopener noreferrer"&gt;SIM900&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://garretlabs.wordpress.com/2014/06/05/raspberry-and-the-remote-controlled-relay-a-low-level-approach-a-k-a-at-modem-commands-the-usual-suspects/" rel="noopener noreferrer"&gt;AT commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.instructables.com/id/RASPBERRY-PI-3-and-RASPBIAN-JESSIE-GSM-3G-SERIAL-H/" rel="noopener noreferrer"&gt;More on serial and BT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sms</category>
      <category>rpizero</category>
      <category>gammu</category>
    </item>
    <item>
      <title>Matrix homeserver with Docker</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Fri, 15 Sep 2017 14:12:00 +0000</pubDate>
      <link>https://dev.to/joenas/matrix-homeserver-with-docker-5dfn</link>
      <guid>https://dev.to/joenas/matrix-homeserver-with-docker-5dfn</guid>
      <description>&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%2Fe524zsje8mbae8buezv0.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%2Fe524zsje8mbae8buezv0.png" alt="Matrix homeserver with Docker" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many good reasons to switch to Matrix from whatever proprietary monolith chat system you are using today. As others have written about that I'm not gonna delve on those now.&lt;/p&gt;

&lt;p&gt;I'm a big Docker fan so when I decided to setup my own Synapse homeserver I was glad to find an &lt;a href="https://github.com/silvio/docker-matrix" rel="noopener noreferrer"&gt;image&lt;/a&gt; ready to use. I'll take you through setting up Synapse together with Postgres and a Let's Encrypt certificate. With this setup adding additional services like bots or bridges is easy.&lt;/p&gt;

&lt;p&gt;Before we start here are some general points about Matrix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Matrix is the &lt;em&gt;protocol&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There are a couple of &lt;a href="https://matrix.org/docs/projects/try-matrix-now.html#servers" rel="noopener noreferrer"&gt;servers&lt;/a&gt; available but Synapse is AFAIK the only (more or less) production ready. It will eventually be replaced by Dendrite (written in Go).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://matrix.org/docs/projects/try-matrix-now.html#clients" rel="noopener noreferrer"&gt;Clients&lt;/a&gt; are plenty so you should be able to find one to your liking. I prefer Riot both for desktop and mobile.&lt;/li&gt;
&lt;li&gt;There are also a lot of bridges (called &lt;em&gt;Application Services&lt;/em&gt;) to other networks like IRC, Slack and Gitter to name a few.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This guide assumes some general knowledge of Linux and that you have a server available with these services installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/" rel="noopener noreferrer"&gt;docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Let's Encrypt &lt;a href="https://certbot.eff.org" rel="noopener noreferrer"&gt;certbot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nginx.org/en/download.html" rel="noopener noreferrer"&gt;nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;domain&lt;/strong&gt; to host your homeserver on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use &lt;strong&gt;Ubuntu 16.04&lt;/strong&gt; , most of this should work just fine for other distros but you know, YMMV.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're gonna start up a new server - like a VPS - I recommend &lt;a href="https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; for some basic security.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Also, I used &lt;a href="https://www.digitalocean.com" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt; to follow my own guide and make sure everything worked. I think they are great and if you haven't tried it already feel free to use this &lt;a href="https://m.do.co/c/37d221e6802a" rel="noopener noreferrer"&gt;referral link&lt;/a&gt; to get $10 for your Matrix server :D&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt; : For those unfamiliar with &lt;code&gt;nginx&lt;/code&gt; &lt;a href="https://twitter.com/MartialLienert" rel="noopener noreferrer"&gt;Martial Lienert&lt;/a&gt; suggested &lt;a href="https://caddyserver.com" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;. I haven't tried it myself but for serving a single host like Synapse it looks pretty neat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We'll be using &lt;code&gt;docker-compose&lt;/code&gt; to be able to easily change options for the containers or adding new services. The default database is &lt;code&gt;sqlite&lt;/code&gt; but even with a small homeserver like mine I noticed a big difference in responsiveness with &lt;code&gt;postgres&lt;/code&gt;. And if you plan on joining big rooms like &lt;a href="https://matrix.to/#/#matrix:matrix.org" rel="noopener noreferrer"&gt;#matrix:matrix.org&lt;/a&gt; it's a must since Matrix will federate data to all servers with at least one user in a room. So in a room with 10000+ users there will be a lot of writes to the database.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Clicking on the #matrix link above will display a page where you can pick a client and join directly. Although I recommend not creating an account on &lt;a href="http://matrix.org" rel="noopener noreferrer"&gt;matrix.org&lt;/a&gt; if you plan on running your own homeserver, since migration isn't available at the moment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It might be a good idea to read through the Synapse &lt;a href="https://github.com/matrix-org/synapse/blob/master/README.rst" rel="noopener noreferrer"&gt;README&lt;/a&gt; if you haven't already. &lt;strong&gt;Note that the parts about which ports to use&lt;/strong&gt; is kinda confusing. This guide will have everything setup the recommended way but if you're curious about the details you should read &lt;a href="https://github.com/matrix-org/synapse/issues/2438" rel="noopener noreferrer"&gt;this issue&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Base directory
&lt;/h3&gt;

&lt;p&gt;To keep the different services grouped together and for a more manageable &lt;code&gt;docker-compose.yaml&lt;/code&gt; we'll create a base directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir /opt/matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating Synapse files
&lt;/h3&gt;

&lt;p&gt;Next we will generate the required files for Synapse. This will add a self-signed certificate used for federation, a &lt;code&gt;homeserver.yaml&lt;/code&gt; config file and a log config.&lt;/p&gt;

&lt;p&gt;You need to decide on what hostname to use. It's possible to host Synapse on a subdomain (f.e &lt;code&gt;matrix.example.com&lt;/code&gt;) and still have clients connect to &lt;code&gt;example.com&lt;/code&gt;, but it requires some &lt;a href="https://github.com/matrix-org/synapse#id34" rel="noopener noreferrer"&gt;extra setup&lt;/a&gt;. I'd recommend having a dedicated domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This will create /opt/matrix/synapse
docker run -v /opt/matrix/synapse:/data --rm \
    -e SERVER_NAME=example.com -e REPORT_STATS=yes silviof/docker-matrix generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Remember to replace &lt;code&gt;example.com&lt;/code&gt; in the command.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; I've changed the &lt;code&gt;REPORT_STATS&lt;/code&gt; above from &lt;code&gt;no&lt;/code&gt; after discussion since I think it's important to support Matrix in any way possible. Originally I just copied the command from the image README and gave it no further thought. If you are interested in what's being shared, have a look &lt;a href="https://github.com/matrix-org/synapse/blob/24df57679521925a16595423d0b37db58668dcd7/synapse/app/homeserver.py#L407-L439" rel="noopener noreferrer"&gt;here&lt;/a&gt;. (Thanks Rob!)&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a docker network
&lt;/h3&gt;

&lt;p&gt;To have the containers talk to each other and also the ability to add other services to the same network without including them in the &lt;code&gt;docker-compose.yaml&lt;/code&gt; (bots for example), we'll create a docker network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create matrix-network
# To see what containers are connected (none atm..)
docker network inspect matrix-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up docker-compose
&lt;/h3&gt;

&lt;p&gt;Now we create a &lt;code&gt;docker-compose.yaml&lt;/code&gt; with our two services. Some options here are rather important to the setup so I've commented them in the file. &lt;a href="https://gist.github.com/joenas/be7e1ca587301b8910c9fd44c3751c08" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is a gist with the contents as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /opt/matrix
sudo nano docker-compose.yaml

version: "2"
services:
  postgres:
    image: postgres:9.6.4
    restart: always

    # I like to be able to use psql on the host to connect to the database 
    # for maintenance. If you already have a postgres running you should remove 
    # the 'ports' section and uncomment 'expose'
    # expose:
    # - 5432

    # Adding 127.0.0.1 ensures the port isn't exposed ON the host
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
     - /opt/matrix/pgdata:/var/lib/postgresql/data

    # These will be used in homeserver.yaml later on
    environment:
     - POSTGRES_PASSWORD=YOUR_PASSWORD_HERE
     - POSTGRES_USER=synapse

  synapse:
    image: silviof/docker-matrix
    # Exposing 8008 (no TLS) on localhost means we can reverse proxy with nginx
    # 8448 is for federation and should be exposed on host
    # 3478 is for TURN (voip calls)
    ports:
     - "127.0.0.1:8008:8008"
     - "8448:8448"
     - "3478:3478"
    volumes:
     - /opt/matrix/synapse:/data

# Our docker network!
networks:
  default:
    external:
      name: matrix-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Editing homeserver.yaml
&lt;/h3&gt;

&lt;p&gt;There are a couple of places we need to make &lt;strong&gt;modifications&lt;/strong&gt;. We want to disable the built-in &lt;code&gt;webclient&lt;/code&gt; and make sure port &lt;code&gt;8008&lt;/code&gt; is accessible from the host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /opt/matrix/synapse/homeserver.yaml

# I've remove default comments and added mine
listeners:
  -
    port: 8448

    bind_addresses:
      - '0.0.0.0'

    type: http
    tls: true

    resources:
      -
        names:
          - client
          #- webclient # I've disabled this
        compress: true

      - names: [federation] # Federation APIs
        compress: false

  # Unsecure HTTP listener,
  - port: 8008
    tls: false

    # Since it's running in a container we need to listen to 0.0.0.0
    # The port is only exposed on the host and put behind reverse proxy
    bind_addresses:
      - '0.0.0.0'

    type: http
    x_forwarded: true
    resources:
      # I've removed webclient here as well
      - names: [client]
        compress: true
      - names: [federation]
        compress: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We change from default &lt;code&gt;sqlite&lt;/code&gt; database to &lt;code&gt;postgres&lt;/code&gt; with our credentials from &lt;code&gt;docker-compose.yaml&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;# Database configuration
database:
  name: psycopg2
  args:
    user: synapse
    password: YOUR_PASSWORD_HERE
    database: synapse

    # This hostname is accessible through the docker network and is set 
    # by docker-compose. If you change the name of the service it will be different
    host: postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll enable registration to be able to test. You can change this later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Enable registration for new users.
enable_registration: True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;☝️ &lt;strong&gt;Don't replace the entire &lt;code&gt;homeserver.yaml&lt;/code&gt; with this, just make sure the corresponding sections are correct&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editing log config (optional)
&lt;/h3&gt;

&lt;p&gt;I prefer to have the logs in a separate directory so let's change that. There should be a file in your &lt;code&gt;/opt/matrix/synapse&lt;/code&gt; called &lt;code&gt;yourhostname.log.config&lt;/code&gt;. Edit it and change to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;handlers:
  file:
    filename: /data/log/homeserver.log

# Create the directory
sudo mkdir /opt/matrix/synapse/log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Obtaining Let's Encrypt cert
&lt;/h3&gt;

&lt;p&gt;You need to have &lt;a href="https://certbot.eff.org" rel="noopener noreferrer"&gt;certbot&lt;/a&gt; installed!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo service nginx stop
sudo letsencrypt certonly --standalone -d yourhostname.com
sudo service nginx start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nginx configuration
&lt;/h3&gt;

&lt;p&gt;Here's the &lt;a href="https://gist.github.com/joenas/194af2f7c2ccf2b04b0a8472974c2447" rel="noopener noreferrer"&gt;gist&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/nginx/sites-available/example.com # or whatever

server {
       listen 80;
       server_name example.com www.example.com;
       return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # If you don't wanna serve a site, comment this out
    root /var/www/example.com;
    index index.html index.htm;

    location /_matrix {
      proxy_pass http://0.0.0.0:8008;
      proxy_set_header X-Forwarded-For $remote_addr;
    }
 }

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start all the things!
&lt;/h3&gt;

&lt;p&gt;Now we should be ready to go so let's try.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /opt/matrix
docker-compose up -d
docker-compose ps

# Something like this 
matrix_postgres_1 docker-entrypoint.sh postgres Up 127.0.0.1:5432-&amp;gt;5432/tcp
matrix_synapse_1 /start.sh start Up 0.0.0.0:3478-&amp;gt;3478/tcp, 127.0.0.1:8008-&amp;gt;8008/tcp, 0.0.0.0:8448-&amp;gt;8448/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything looks good&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo service nginx reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Register account and login
&lt;/h3&gt;

&lt;p&gt;Here comes the fun part! Let's create an account :)&lt;/p&gt;

&lt;p&gt;Any client would do but for this let's use Riot. Click &lt;a href="https://riot.im/app/#/register" rel="noopener noreferrer"&gt;here&lt;/a&gt;, fill in your info and change the &lt;em&gt;"Custom server"&lt;/em&gt; to the hostname of your newly created one. Adding an email is optional but if you &lt;strong&gt;ever need to reset your password you can't without it&lt;/strong&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%2Fw34ug2reyim0iqs8dxcd.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%2Fw34ug2reyim0iqs8dxcd.png" alt="Matrix homeserver with Docker" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  If everything is ok you should be greeted by the friendly &lt;code&gt;@riot-bot&lt;/code&gt;!
&lt;/h3&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%2F8xmofzcczaaaygu42hr4.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%2F8xmofzcczaaaygu42hr4.png" alt="Matrix homeserver with Docker" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy happy joy joy
&lt;/h2&gt;

&lt;p&gt;So, hopefully you've made it this far and now have your own Matrix homeserver. There are a lot of neat things to do with Matrix and I'll be posting more about that, bots and other integrations for example. But for now enjoy your awesome federated open source chat and invite some friends!&lt;/p&gt;

&lt;p&gt;If you found any errors in this guide or just feel like sharing your appreciation, drop me an email or tweet :)&lt;/p&gt;

</description>
      <category>docker</category>
      <category>matrix</category>
      <category>chat</category>
      <category>element</category>
    </item>
    <item>
      <title>SMS gateway and push notifications</title>
      <dc:creator>Jon Neverland</dc:creator>
      <pubDate>Sun, 27 Aug 2017 20:35:36 +0000</pubDate>
      <link>https://dev.to/joenas/sms-gateway-and-push-notifications-48ni</link>
      <guid>https://dev.to/joenas/sms-gateway-and-push-notifications-48ni</guid>
      <description>&lt;p&gt;A lot of services today either require or &lt;strong&gt;really want&lt;/strong&gt; you to provide a cellphone number when signing up. I prefer not sharing my private number with these services and I also prefer not having these texts clog up my inbox.&lt;/p&gt;

&lt;p&gt;First I thought I could do this with Twilio but apparently they don't allow receiving texts from &lt;strong&gt;short codes&lt;/strong&gt; like Twitter and Facebook uses. So I decided to build an SMS gateway! You don't really need much to do this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 3G/4G modem&lt;/li&gt;
&lt;li&gt;A sim card, preferably prepaid&lt;/li&gt;
&lt;li&gt;A computer :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few frameworks if you want more advanced features, for example &lt;a href="https://playsms.org" rel="noopener noreferrer"&gt;playSMS&lt;/a&gt; or &lt;a href="https://github.com/n0r1sk/smsgateway" rel="noopener noreferrer"&gt;smsgateway&lt;/a&gt;. I haven't tried any of these myself but they look great! Since I only really wanted to &lt;strong&gt;receive&lt;/strong&gt; texts I went with &lt;a href="https://wammu.eu/gammu/" rel="noopener noreferrer"&gt;gammu&lt;/a&gt;. I found this &lt;a href="https://andypi.co.uk/2017/05/06/raspberry-pi-sms-to-email-gateway-part-1/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; which explained most of what I had to do.&lt;/p&gt;

&lt;p&gt;I had an old &lt;em&gt;Huawei E398&lt;/em&gt; laying around at home. I got it working with the instructions below &lt;strong&gt;but after a few hours it would disconnect and I had to reinsert it&lt;/strong&gt;. I'm not sure if this was due to a faulty modem or something else.. So YMMV!&lt;/p&gt;

&lt;p&gt;Now I'm using a &lt;em&gt;Huawei E122&lt;/em&gt; and it worked OOTB. &lt;code&gt;lsusb&lt;/code&gt; for that modem gives&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ID 12d1:1001 Huawei Technologies Co., Ltd. E169/E620/E800 HSDPA Modem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have another modem it might be worth checking out the &lt;a href="http://www.draisberghof.de/usb_modeswitch/device_reference.txt" rel="noopener noreferrer"&gt;device reference&lt;/a&gt; for &lt;code&gt;usb_modeswitch&lt;/code&gt; if it's supported. There's also a &lt;a href="http://www.draisberghof.de/usb_modeswitch/parameter_reference.txt" rel="noopener noreferrer"&gt;parameter reference&lt;/a&gt; for those who don't like &lt;code&gt;man-pages&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching usb mode
&lt;/h2&gt;

&lt;p&gt;Most modems will present themselves as a USB storage when you insert them, mostly for Windows users to they can install drivers. So you need to tell it to switch to modem mode and for this we use &lt;code&gt;usb-modeswitch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instructions for Huawei E398
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install gammu usb-modeswitch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check what mode we're in, for my modem &lt;strong&gt;storage mode&lt;/strong&gt; looked like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lsusb
=&amp;gt; Bus 002 Device 019: ID 12d1:1505 Huawei Technologies Co., Ltd. E398 LTE/UMTS/GSM Modem/Networkcard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;12d1&lt;/code&gt; above is the &lt;em&gt;vendor ID&lt;/em&gt; and &lt;code&gt;1505&lt;/code&gt; the &lt;em&gt;product ID&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now you need to find the product ID of the &lt;strong&gt;modem mode&lt;/strong&gt;. Some guides recommended restarting the computer with the modem plugged in but that didn't help for me so I had to google a bit. There are tons of forum posts for different modems and in my case I found the correct ID to be &lt;code&gt;1506&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
You also need to find the &lt;em&gt;"message-content"&lt;/em&gt; to send the modem with the &lt;code&gt;-M&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Switch the modem mode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# -v is current vendor ID
# -p is current product ID
# -V is target vendor ID (usually the same)
# -P is target product ID
# -M is the message
sudo usb_modeswitch -v 12d1 -p 1505 -V 12d1 -P 1506 -M 
"55534243123456780000000000000011062000000100000000000000000000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that the modem has switched mode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lsusb
=&amp;gt; Bus 002 Device 005: ID 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There should now be one or more devices to use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dmesg | grep tty
# Should give something like
GSM modem (1-port) converter now attached to ttyUSB0
GSM modem (1-port) converter now attached to ttyUSB1
GSM modem (1-port) converter now attached to ttyUSB2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the gammu config and set &lt;code&gt;port&lt;/code&gt; to &lt;code&gt;/dev/ttyUSB0&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;sudo gammu-config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check if gammu can identify the modem&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo gammu --identify
Device : /dev/ttyUSB0
Manufacturer : Huawei
Model : unknown (E398)
Firmware : xxx
IMEI : yyy
SIM IMSI : zzz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All good! Now you should be able to send an sms like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo gammu sendsms TEXT [phonenumber] -text "Ohhai"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatically switch mode when inserted or after reboot
&lt;/h3&gt;

&lt;p&gt;After a reboot or unplug and reinsert the modem usually switches mode again. To make sure we always are in &lt;strong&gt;modem mode&lt;/strong&gt; you need to create a config for &lt;code&gt;usb_modeswitch&lt;/code&gt; matching the &lt;em&gt;vendor ID&lt;/em&gt; and &lt;em&gt;product ID&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/usb_modeswitch.d/12d1:1505

DefaultVendor=0x12d1
DefaultProduct=0x1505
TargetVendor=0x12d1
TargetProduct=0x1506
MessageContent="55534243123456780000000000000011062000000100000000000000000000"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Symlink to /dev/sms for consistency
&lt;/h3&gt;

&lt;p&gt;It might be a good idea to create a symlink for your device so your settings for &lt;code&gt;gammu&lt;/code&gt; always works, otherwise sometimes after reboot it might switch to &lt;code&gt;/dev/ttyUSB1&lt;/code&gt; or whatever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/udev/rules.d/999-sms-gateway.rules
# Add this line 
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", SYMLINK+="sms"
# Then
sudo udevadm control --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Forward texts with WebHook
&lt;/h2&gt;

&lt;p&gt;I wanted to send all received texts to my &lt;a href="https://github.com/huginn/huginn" rel="noopener noreferrer"&gt;Huginn&lt;/a&gt; instance and from there to &lt;a href="https://pushover.net" rel="noopener noreferrer"&gt;Pushover&lt;/a&gt;. Huginn supports a bunch of services so if you prefer Slack or even Twitter that's no problem!&lt;/p&gt;

&lt;p&gt;I'm using a modified version of &lt;a href="https://github.com/andy-pi/rpi-sms-gateway/blob/master/receivesms.py" rel="noopener noreferrer"&gt;this script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;gammu-smsd&lt;/code&gt; and configure it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install gammu-smsd
sudo pip install requests

sudo nano /etc/gammu-smsdrc
# Change the port in the [gammu] section to your device
# Add the RunOnReceive in the [smsd] section.
# RunOnReceive = python /opt/gammu/receivesms.py

sudo service gammu-smsd restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to change the path of the script, I put in it &lt;code&gt;/opt/gammu&lt;/code&gt; and &lt;code&gt;chown&lt;/code&gt;:ed the dir to gammu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modified version of the script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python

from __future__ import print_function
import os, sys, re, requests

def get_message():
    files = [os.path.join('/var/spool/gammu/inbox/', m) for m in sys.argv[1:]]
    files.sort() # make sure we get the parts in the right order
    number = re.match(r'^IN\d+_\d+_\d+_(.*)_\d+\.txt', os.path.split(files[0])[1]).group(1)
    text = ''
    for f in files:
        text += open(f, 'r').read()
    try:
        text = text.decode('UTF-8', 'strict')
    except UnicodeDecodeError:
        text = text.decode('UTF-8', 'replace')
    return number, text

number, text = get_message()

request = requests.post('YOUR_HUGINN_URL', data={
    'from': number,
    'message': text
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the url for Huginn, all you need to do is to create a &lt;a href="https://github.com/huginn/huginn/wiki/Using-a-Webhook-Agent-with-external-software" rel="noopener noreferrer"&gt;Webhook Agent&lt;/a&gt;. Now try sending a text to your phonenumber and it should show up in Huginn! From there you can forward it to whatever service you prefer, either with one of the built-in Agents or a regular WebHook with &lt;a href="https://github.com/huginn/huginn/wiki/Agent-Types-&amp;amp;-Descriptions#post-agent" rel="noopener noreferrer"&gt;Post Agent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions drop me an email or tweet me.&lt;/p&gt;

</description>
      <category>sms</category>
      <category>notifications</category>
      <category>gammu</category>
    </item>
  </channel>
</rss>
