Pixelfed is a federated photo sharing service that is an alternative to Instagram and uses ActivityPub to share posts across other services such as Mastodon, Pleroma and indeed WordPress. It is one of the more mature Fediverse apps and has been in continuous development for several years.

As with Mastodon and other apps that can share images and other larger media files, it supports saving attachments to S3-compatible cloud storage. However, this isn't well documented so far, so here's a few notes on getting it to work, specifically with iDrive E2, a low cost E2 storage provider.

Pixelfed is a Laravel application and its user config is stored in a .env file in the application root. The S3 section looks like this:

## S3 Configuration (Post-Installer)

IDrive E2 appears to be based on Minio but the priniciple is broadly similar for all S3 compatible services:

  1. Create a bucket
  2. Create credentials for that bucket
  3. Configure the application with those credentials

I think they're fairly self-explanatory in that the service will usually present them in the same way. The default region can be a bit of odd one but the naming seems to be arbitrary - I'm using iDrive's London region, which is labelled LDN, so go with what the service gives you.
AWS_URL is as it says, a standard URL, so it's https:// AWS_ENDPOINT / AWS_BUCKET. AWS_ENDPOINT is an important thing though - IDrive has the option of public and private endpoints with different hostnames. I'm not entirely clear on how a private endpoint works in this context - I would think it's a location that needs to be accessed with a shared key - but as you're publishing images online that's not going to be possible, and in testing I couldn't get Pixelfed to write to a private endpoint. In addition they're going to need to be public on an open server, so following the principle of least privilege, public and read-only works.
I had to comment AWS_USE_PATH_STYLE_ENDPOINT out as setting it to false didn't work for some reason. There's probably something in the code that assumes it's going to be an AWS URL or similar.

The Horizon dashboard was very useful for debugging. Again, this is a Laravel tool and part of the admin suite. I'm not that familiar with Laravel and but it basically appears to be the application manager. It writes to a log but that doesn't say much, and all the useful information is in the dashboard.

If you want to share images in the Fediverse, Pixelfed is the application you need. Its author, Daniel Supernault has been steadily improving it for years, and he's also currently working on a secure and federated messaging system intended as a drop-in replacement for direct messages. Cloud storage reduces your hosting costs as it's usually cheaper in bulk than VPS, and it's portable, so now you can replace Instagram with something under your control.

(Without disabling everything else)

My main laptop is a Lenovo X1 Yoga 2nd Gen running Manjaro KDE Plasma. Lovely machine and does what I want it to do. As a Yoga device, it has a touchscreen, which I don't use a lot and have often thought of disabling.

The other day, the laptop had the wrong kind of drop, which has cracked the touchscreen in the corner. This hasn't affected the display at all but has messed up the touchscreen input so that it keeps getting random signals that trigger events, which was sufficiently intrusive to need to turn off the touchscreen

The first thing I found was this from the Manjaro Forum. Tl;dr, disable the module that powers the touchscreen with sudo modprobe -r usbhid and make it permanent by creating a blacklist at /etc/modprobe.d/blacklist/wacom that contains the following:

blacklist wacom
blacklist usbhid

and restart.
This worked fine when just on the laptop, but I have a multi-monitor desktop setup that has a USB mouse and keyboard, and when I came to start work this morning, neither worked. Enabling usbhid in the blacklist just brought the spurious touches back.
There was going to be something that creates rules to selectively allow USB devices, and that something is USBGuard.
The Arch Wiki documents it well, but basically install with pacman -Sy usbguard (or your software manager of choice), and create your ruleset as root with usbguard generate-policy > /etc/usbguard/rules.conf.
This lists all your connected devices as allowed, including the touchscreen:

allow id 056a:50b6 serial "" name "Pen and multitouch sensor" hash "B1HYEaAtN9VpnKbIK5GQeZFfg3XN7EAAeQUvTx5zIhk=" parent-hash "jEP/6WzviqdJ5VSeTUY8PatCNBKeaREvo2OqdplND/o=" via-port "1-10" with-interface { 03:00:00 03:00:00 } with-connect-type "not used"

To disable it, change allow to block to stop it being processed, or reject to stop the device being loaded at all. At the moment I have it set to block.
Start USBGuard with systemctl start usbguard and enable it on boot with systemctl enable usbguard.
This stopped the touchscreen responding but kept the USB keyboard and mouse working. I haven't tested it across a reboot yet but I can't see why it won't continue to work.

I have a virtual OPNSense router as the gateway to a production network based on Proxmox servers (more about this another day). All VMs and containers get an unrouted IP address in the 10.x.x.x range and I have a couple of IP ranges for public access, generally but not always behind Haproxy. This doesn\'t seem to be documented properly elsewhere. ## A quick summary: 1. Assign IP range(s) as Virtual IPs 2. Create a One to One NAT between an external IP from a virtual IP range and an internal address 3. Create a WAN rule for the ports you want open to the internal address. ### 1. Assign IP ranges as Virtual IPs Our servers are with OVH and connected by their vRack service, which is remarkably flexible - connected servers can use an unrouted IP network, which is shared between them automatically, and for routed IP addresses, you rent a range (minimum is a /30, for reasons I\'ll explain shortly) and allocate it to the vRack, and in the simplest usage they are allocated to a physical interface on a server and routed to the ranges\' gateway, which is, somewhat counter-intuitively, the second to last address in the range, which is why the smallest range possible is a /30: | Range | CIDR | Gateway | Usable addresses | |-------|------|---------|------------------| | | /30 | | 1 | | | /29 | | 5 | | | /28 | | 12 | For the purposes of this article, I\'ll add a /29 as I have a routed one that\'s about to be reallocated from my account. a) Go to Interfaces > Virtual IPs > Settings b) Press \'+\' c) For the mode in this context, you will use Proxy ARP as IP Alias is for a single IP - the \'Single IP\' option is disabled. d) Select WAN for the interface e) Select \'Network\' for Type f) Enter the network range in the Address field without the CIDR range and select that from the dropdown. You don\'t define a gateway at this point, which also seems a bit counterintuitive but that comes at allocation time. g) Set a description and save. h) Apply changes on the main page. ### 2. Enable Reflection in the Firewall settings UPDATE 19/12/2022: I\'ve been trying to work out why I couldn\'t search other ActivityPub services from my Mastodon instance and found that on my local network at least, I couldn\'t find the address of my blog, so this is the fix for being able to access services internally. a) Go to Firewall > Settings > Advanced b) In the Network Address Translation section, check the Reflection options that you use. I went with all three just to be sure. c) Save. ### 2. Add a One to One NAT a) Go to Firewall > NAT > One-to-One b) Press \'+\' c) For \'Interface\' select \'WAN\' d) For Type selected \'BINAT\' so outbound traffic is rewritten as well e) For \'External network\' select an IP from your allocation and give it the CIDR range /32 f) For \'Source\' select \'Single host or Network\' and enter the IP address of the destination server/VM/container, again with a CIDR range of /32. This is also somewhat non-intuitive at first as the pfSense instructions say the CIDR range should be the same for both addresses and in this case we have a /29 for external traffic and a /22 for internal traffic. g) Set \'Destination\' to \'any\' h) Add a description i) Set NAT reflection to \'Use system default\' or as required. The default is set in Firewall:Settings:Advanced and is Disabled. j) Save k) Apply changes on the main page ### 3. Create firewall rules a) Go to Firewall > Rules > WAN b) Press \'+\' c) Action is \'Pass\' d) Interface is WAN e) Direction is in f) TCP/IP version is generally TCP g) Source is \'any\' h) Destination port range will usually a single port for a protocol such as HTTPS i) Destination is \'Single host or Network\' and the value is the IP address of the backend device with the correct CIDR range for your network, so in this case it\'s 10.10.x.x/22 j) Optionally set a description, but it\'s advisable as it\'s useful for documentation. k) Save l) Apply changes on the main page. Revision 2

This took a few days to work out and I finally found it buried in an Opnsense forum post, so here it is in a slightly easier to find way.


To forward HTTP(S) traffic to a virtual machine running Nginx (or any other HTTP proxy or load balancer) through a gateway running OPNsense.


1. Change the Web GUI port

Even if the Web GUI is inaccessible from the public interface of an Opnsense VM, it's still listening on it on both port 80 and port 443, so change the port.
In System > Settings > Administration > Web GUI, assuming you have set the protocol to HTTPS, change TCP Port to something other than 443:
Opnsense Web GUI TCP Port

Press Save and the configuration will reload. You may need to click on the link in the notification bar for it to complete.

2. Create aliases for the HTTP(S) service

This was the bit I didn't get. I was trying to define NAT ports and IPs manually. More about aliases in OPNSense
Assume your internal network is and your web server is at The WAN address is the address is the IP address of your gateway.
In Firewall > Aliases > View

  1. Click the plus button to add a new alias.
  2. Enter the following:
    • Enabled: check
    • Type: Hosts
    • Name: Reverse Proxy (or whatever, this is the identifier)
    • Content:
    • Statistics (as required)
    • Description: The reverse proxy host
  3. Click Save
  4. Click the plus button to add a new alias again.
  5. Enter the following:
    • Enabled: check
    • Type: Port(s)
    • Name: Reverse Proxy Ports
    • Content: 80, 443 (each port is a separate item)
    • Statistics: (as required)
    • Description: Reverse proxy ports
  6. Click Save and Apply Settings.

3. Create a NAT rule

In Firewall > NAT > Port Forward

  1. Click the Plus button to add a new Port Forward rule
  2. Enter the following:
    • Interface: WAN
    • TCP/IP version: IPv4
    • Protocol: TCP
    • Destination: WAN Address
    • Destination port range: from Reverse Proxy Ports to Reverse Proxy Ports (this will be in the dropdown under Aliases)
    • Redirect Target IP: Reverse Proxy (from the dropdown)
    • Redirect Target Ports: Reverse Proxy Ports (from the dropdown)
    • Pool Options: Default
    • NAT Reflection: Enable
    • Filter rule association: Rule
  3. Click Save and Apply settings.
    This also creates a rule in Filewall > Rules > WAN for the aliases.

If your web server/load balancer VM is up and you at least have a default configuration available, you should get a page.

H/T to huticip in the Opnsense forums.