Setting up my federated fleamarket with flohmarkt

12 min read Original article ↗

tl;dr: I set up fleamarket.neilzone.co.uk using flohmarkt.

Over the years, I appear to have acquired quite a lot of tech-related stuff.

I’m sure it all had a purpose - or, at least, the promise of a plan - when I got it but, well, some stuff has been sitting around for a while now, and could do with going to a new home.

But how to get rid of it? I can’t be bothered with the hassle of eBay. Facebook Marketplace at a pinch (as I’m not a particular fan of Facebook). Some kind of freecycle / freegle group which is not on Facebook?

Or just post it on the fediverse? Yes, I know that not everyone is in the fediverse, but if I can move on at least some of this stuff, I’d be happy. Plus, of the people with whom I interact in the fediverse, quite a few have some kind of tech-related leaning.

Enter flohmarkt

The ThinkPad Museum - cue envy and jealousy on my part - mentioned flohmarkt, a federated “fleamarket” system.

(Apparently, the name “flohmarkt” means “fleamarket” in German. I have managed to confuse myself throughout my installation of it by sometimes using “flohmarkt” and sometimes using “fleamarket”. I’m an idiot who should have standardised on one approach.)

flohmarkt is a platform which integrates with the fediverse using ActivityPub (but also allows browsing via a web browser too), and lets me advertise items for sale / gifting, and for people to request them.

There’s no payment mechanisms or anything complicated like that.

I have set this up with the intention of it being just a single user instance - i.e. I am the only person who can post ads to it - but that was just a case of closing registration at the end.

Depending on how it goes, there’s a possibility that I could open it up to other people that I know but, well, sharing computers with others these days leads to unwanted stress and hassle. So, for now, just me.

Setting up flohmarkt on a Raspberry Pi 4

I set up flohmarkt on a Raspberry Pi 4.

The instructions for Debian Bookworm mostly worked, but there were some areas where that was more challenging.

So, as much for my notes as anything, here’s what I did.

(I set up a Raspberry Pi 4, using Raspbian Lite 64 bit, and then did my usual hardening of it. So this assumes that there’s a working, Internet-connected, Raspberry Pi.)

Apparently there is a package for flohmarkt for Yunohost so, if you use Yunohost, that’s probably an easier way of doing it.

Create a user

sudo useradd -m -s /bin/bash -c "flohmarkt" flohmarkt

Install couchdb

sudo apt install python3-pip python3-full curl apt-transport-https gnupg git -y

sudo curl https://couchdb.apache.org/repo/keys.asc | sudo gpg --dearmor | sudo tee /usr/share/keyrings/couchdb-archive-keyring.gpg

source /etc/os-release

sudo echo "deb [signed-by=/usr/share/keyrings/couchdb-archive-keyring.gpg] https://apache.jfrog.io/artifactory/couchdb-deb/ ${VERSION_CODENAME} main"     | sudo tee /etc/apt/sources.list.d/couchdb.list >/dev/null

sudo apt update && sudo apt install couchdb -y

There’s a TUI for configuring couchdb, and I had to guess a bit what I wanted, as the instructions do not say (I’ll send in a pull request in due course).

I picked “standalone mode” for the first screen.

Per the instructions, for the Erlang “magic cookie” (who names these things?!), I went for couchdb@fleamarket.neilzone.co.uk, on the basis that that was the FQDN I was going to be using later.

I also set a password for the admin user, which is needed later too.

Create the storage directory (for images and other bits) - note that this is different to the venv directory:

sudo mkdir -p /var/lib/flohmarkt && sudo chown flohmarkt:flohmarkt /var/lib/flohmarkt 

Install flohmarkt into a venv

sudo bash

su - flohmarkt

cd /home/flohmarkt

git clone https://codeberg.org/flohmarkt/flohmarkt.git

python3 -m venv venv-flohmarkt

source venv-flohmarkt/bin/activate

pip install -r flohmarkt/requirements.txt

Annoyingly, I couldn’t use pipx here (which is my preferred way of doing this kind of thing), because it does not yet - AFAIK, anyway - support installing packages from a text file. So pip it was.

Configure flohmarkt

First, copy the example config file into place:

cd flohmarkt

cp flohmarkt.conf.example flohmarkt.conf

Before editing the actual config file, you’ll need:

  • to know the URL you want to use (I went for https://fleamarket.neilzone.co.uk) - it is important to use https.
  • to generate a token for the JwtSecret field. (openssl rand 256 | base64 -w 0)
  • to generate a password for the database user (different to the password for the database’s admin user that you created earlier)

For the database configuration, the instructions bear no resemblance to the template file. There’s no “Server” key value pair, and the port used in the documentation is different to the port in the template.

I used:

[Database]
UseHttps = 0
Host = 127.0.01
User = flohmarkt
Password = NotMyActualPassword
Port = 5984
Database = flohmarkt

(I disabled https, as this is “just” an internal communication within the system; I’ll be doing TLS using an nginx reverse proxy, later.)

In the Email.STMP bit, the field CAFile is mandatory, even if your mailserver does not need it. I left it as /path/to/foo.pem, as apparently being there but wrong/invalid is fine, but not being there is not.

And with that, I was done with the config file.

Initialise the database, using the two passwords you created earlier

python3 initialize_couchdb.py <couchdb-admin-password> <couchdb-user-password>

Initialise the application

LANG=en_US.UTF-8 uvicorn --port 8000 --reload flohmarkt.web:start

Note that it does not currently support en_GB and, if you specify this, it will throw an error later.

The output of this command was a one-time setup link, that I needed to access… except that, at this point, I had not set up the reverse proxy / opened it up to the Internet. So time to do that.

Don’t worry: when, after I’d done that, I re-ran the application initalisation script, it gave me the same “one-time” setup link.

Configure nginx and http/https access

I set up nginx by hand, as a reverse proxy to port 8000, as I had not realised that, in the flohmarkt folder, there’s an example nginx config file that is not mentioned in the documentation :)

When I discovered that, I re-did my nginx setup, although it was not massively different.

For posterity, it should be something like this. Replace flohmarket.example.com with whatever domain you are actually using.

Install nginx, certbot, and python3-certbot-nginx:

sudo apt install nginx certbot python3-certbot-nginx -y

Set up A/AAAA records with your DNS provider for your domain (e.g. flohmarkt.example.com)

Allow in ports 80 and 443 on your firewalls

Configure nginx minimally to allow you to generate a Let’s Encrypt TLS cert:

sudo tee /etc/nginx/sites-available/flohmarkt.conf <<EOF
server {
    listen         80;
    listen [::]:80;
    server_name    flohmarkt.example.com;
}
EOF

Symlink the config:

sudo ln -s /etc/nginx/sites-available/flohmarkt.conf /etc/nginx/sites-enabled/

Reload nginx:

sudo service nginx reload

Run certbot to generate a Let’s Encrypt TLS certificate:

certbot --nginx -d flohmarkt.example.com

Finish the configuration of nginx by adding the example config supplied at flohmarkt/nginx.conf.example to your /etc/nginx/sites-available/flohmarkt.conf to set up the reverse proxying. If you have used certbot to generate TLS certs, adding in the relevant bits of the config should leave you with a file looking like this:

server {
    server_name    flohmarkt.example.com;
    root	/var/www/html;

    listen [::]:443 http2 ssl ipv6only=on; # managed by Certbot
    listen 443 http2 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/flohmarkt.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/flohmarkt.example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

     location / {
      proxy_pass          http://127.0.0.1:8000;
      proxy_redirect    off;
      proxy_set_header  Host $host;
      proxy_set_header  X-Real-IP $remote_addr;
      proxy_set_header  X-Forwarded-Proto $scheme;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Host $server_name;
    
      proxy_http_version 1.1;
      proxy_set_header Connection "upgrade";
      proxy_set_header Upgrade $http_upgrade;
    
      # setup for image upload
      client_max_body_size 256M;
      proxy_max_temp_file_size 1024M;
    
      proxy_read_timeout 300;
      proxy_connect_timeout 300;
    
     }

}

server {
    if ($host = flohmarkt.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen         80;
    listen [::]:80;
    server_name    flohmarkt.example.com;
    return 404; # managed by Certbot

}

Reload nginx:

sudo service nginx reload

At this stage, I set up an admin user, and then left registrations open, so that I could register a normal, unprivileged user for me.

I spent a fair amount of time looking for the config file option to close registration, and I didn’t find it. Instead, log back in as the admin user, and it is under Settings / Administration.

Run flohmarkt

su - flohmarkt
cd /home/flohmarkt
source venv-flohmarkt/bin/activate
cd flohmarkt

LANG=en_US.UTF-8 uvicorn --port 8000 --reload flohmarkt.web:start

And there it was!

Setting up a systemd service

While one can run it in screen/tmux like that, I wanted a systemd service, so that it would start automatically.

The systemd sample unit file was broadly fine for my needs.

First, I created the log directory:

mkdir -p /var/log/flohmarkt/
chown -R flohmarkt:flohmarkt /var/log/flohmarkt/

Then I created the systemd unit file, in /etc/systemd/system/flohmarkt.service, tweaked in line with my installation:

[Unit]
Description=flohmarkt server
After=network.target couchdb.service

[Service]
Type=simple
User=flohmarkt
Group=flohmarkt
WorkingDirectory=/home/flohmarkt/flohmarkt
Environment="VENV_DIR=/home/flohmarkt/venv-flohmarkt"
ExecStart=/bin/bash -c "set -o pipefail; /home/flohmarkt/venv-flohmarkt/bin/uvicorn --factory --host 127.0.0.1 --port 8000 flohmarkt.web:start  2>&1 | /usr/bin/ts '%%Y-%%m-%%d %%H:%%M:%%S'"
Restart=on-failure
RestartSec=5s 
StandardOutput=append:/var/log/flohmarkt/app.log
StandardError=inherit
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
DevicePolicy=closed
ProtectSystem=full
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
LockPersonality=yes
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
CapabilityBoundingSet=~CAP_RAWIO CAP_MKNOD
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_TIME CAP_SYS_MODULE CAP_SYS_PACCT
CapabilityBoundingSet=~CAP_LEASE CAP_LINUX_IMMUTABLE CAP_IPC_LOCK
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_WAKE_ALARM
CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE
CapabilityBoundingSet=~CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW
CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYSLOG

[Install]
WantedBy=multi-user.target

And then:

systemctl daemon-reload

sudo systemctl enable --now flohmarkt.service

I tested it via web browser, and I could access flohmarkt, so good so far!

Fixing the lack of /usr/bin/ts on my Raspberry Pi

The unit file uses /usr/bin/ts for time logging, and /usr/bin/ts was not on my Raspberry Pi, so I got errors in /var/log/flohmarkt/app.log.

To fix this, I copied it in place from a machine running Debian (not shown, as it is a big file), and make it globally executable:

chown root:root /usr/bin/ts

chmod 755 /usr/bin/ts

I restarted the systemd service, and everything was happy:

sudo systemctl restart flohmarkt.service

Update: it looks like I could have fixed this by doing sudo apt install moreutils -y.

The federated bit

The really cool thing about this?

While one can post items and browse items using the web interface, it also posts directly to the fediverse, via ActivityPub.

So, for instance, if you follow @neil@fleamarket.neilzone.co.uk / https://fleamarket.neilzone.co.uk/~neil, you can see my posts, via your chosen AP client/server.

You might even be able to reply to one of my posts via a direct message (and only a direct message) to request an item. If you do, I should then see your message within the flohmarkt system.

However, based on my limited testing so far, neither following nor replying works from instances which have Authorized Fetch enabled (as my personal Mastodon instance does). Which is a bit of a pain.

If you send a public reply, flohmarkt sends an automated response to the user:

You’ve made a public post to a item on flohmarkt. This post is going to be ignored by the system. Please use private posting e.g. ‘Only mentioned’ in mastodon. (This is a system-generated message)

Thanks to Edent for letting me know that it did this :)

One quirk - or, at least, a function that I’ve yet to spot - is how to delete messages. One can use the blocking functionality if someone turns abusive or DDoSy, but I can’t find a way to delete messages from users.

It is quite possible that there is an RSS feed too, but I haven’t worked this out yet. No, no rss feed yet.

One can federate with other instances of flohmarkt - there’s a geographic element to this, but this can be overcome if desired - which I think means that I could then see what users of the other instance were offering, and vice versa. I have not done this yet, mainly as this is just a “me” project, but also because I don’t know anyone else running flohmarkt.

Update: Simon Phipps has set up an instance of flohmartk too, and so we worked out how to federate with each other. First, we set the geographic constraints quite broadly, so that we were definitely within overlapping zones. Then, Simon federated with me (and so could see my adverts), and I federated with him (and so could see his adverts). I needed to approach his request to federate with me, and he with mine. And then it worked: we could see each others’ adverts. Nifty.

So what’s it like

It is… alpha beta.

And that’s absolutely fine. I went into it knowing this, and I was not disappointed.

But if you are looking for a polished, ready-for-all-users, system, it is not there yet.

I’ve quite a few bits and pieces to raise with the project when I get some time, especially around the authorised fetch bit to see what the options are there, and to help with the documentation for installations.

But, it seems to be working, and I’ll see what I can do with it.

Updating flohmarkt

I have updated the wiki page on updating to cover updating a Debian Bookworm manual installation but, for my own notes, it is:

# stop the systemd service

sudo systemctl stop flohmarkt

# switch to your flohmarkt user, update from git, and re-initalise the database

sudo su - flohmarkt

cd /home/flohmarkt/flohmarkt

git pull origin master

python3 initialize_couchdb.py <couchdb-admin-password> <couchdb-user-password>

# restart flohmarkt via systemd

exit

sudo systemctl start flohmarkt

You may also like: