Deploying Shynet

I wanted to keep track of how many people read these posts. So I've set up privacy-friendly Shynet to count my visitors.

Deploying Shynet
Photo by Andrew Masters / Unsplash

Having a website can be fun. But I do am a bit curious of how many people read what. That's why I wanted to integrate some tracking. However privacy is important to me, so Google Analytics was out of the window. Luckily there are multiple self-hosted, privacy respecting alternatives. After comparing a few, I chose Shynet. Thanks to docker, setup was simple.

The Shynet Service

As always we will be using docker-compose to run our services. We will attach the container to the same network we created last time. This allows us to create a new revers proxy inside Nginx Proxy Manager (NPM), without having to expose the ports on our host.

So the first part will be the same as always. Create a new folder with a docker-compose.yml and a .env file. The first few rules of the docker-compose.yml will be the same as previous posts. We define the syntax version, and set the default network to the same as NPM.

version: '3'

networks:
  default:
    external:
      name: npm_network

Next we need to define 2 services. The Shynet app itself, and a database.

services:
  shynet-app:
    image: milesmcc/shynet:latest
    restart: unless-stopped
    depends_on:
      - shynet-db
    environment:
      DB_HOST: shynet-db
      DB_NAME: ${POSTGRES_DB}
      DB_USER: ${POSTGRES_USER}
      DB_PASSWORD: ${POSTGRES_PW}
      DJANGO_SECRET_KEY: ${DJANGO_SECRET}
      TIME_ZONE: ${TZ}
      SHOW_SHYNET_VERSION: "False"

  shynet-db:
    image: postgres:13-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PW}
    volumes:
      - ${DATADIR}/db/data:/var/lib/postgresql/data

Again all environment variables are self-explanatory. I've set SHOW_SHYNET_VERSION to false. If Shynet ever has a bug in a specific version, and I forget to update, attackers could see I have this version and abuse it. DB_HOST refers to the 2nd service. The other DB_*, TIME_ZONE and DJANGO_SECRET_KEY variables are set in the .env file. More variables and examples can be found in the example .env file.

The volumes are used to store persistent data. So nothing gets lost when a container crashes.

Fill in your .env file with all the needed variables:

DATADIR=/media/docker/shynet
DJANGO_SECRET=*****
SHY_URL=*****
POSTGRES_DB=*****
POSTGRES_PW=*****
POSTGRES_USER=*****
TZ=*****

Replace the ***** values with your own.

When this is done you can use docker-compose config to verify your file and see the result. If everything seems good run docker-compose up -d to start the service in the background.

Reverse Proxy

Now let's set up the reverse proxy to the shynet service.

Open up your NPM instance and go to Proxy Hosts. Create a new proxy host, fill in the service name (shynet-app in our compose file) as the forward hostname, and 8080 (default shynet port) as forward port.

Screen-Shot-2021-10-29-at-14.53.40

If you want to use SSL (which you want), go to the SSL tab and request a certificate from Let's Encrypt.

Screen-Shot-2021-10-29-at-14.55.19

Now save the proxy, and you should be able to access your Shynet instance; Make sure that url/domain, resolves to the public IP of your server.

Connecting to Ghost

Now go to your Shynet instance and create a new service. Fill in a name and the web address. In advanced settings I checked Respect DNT and disabled Collect ips,as I don't need that information.

Screen-Shot-2021-10-29-at-14.59.24

Once this is created, you can see a block of code you should add to your webpage.

Screen-Shot-2021-10-29-at-15.02.00

As I use Ghost, I will show you how to add it there. Go to your Ghost admin page, and open Settings > Advanced > Code Injection. Copy the HTML code from Shynet and paste it in the Site Footer.

Et voila, you're done!

Now I know if someone reads this...