<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>fmac's blog</title>
    <link>https://fmac.xyz</link>
    <description>Recent content in Posts on fmac&#39;s site</description>
    <generator>Phoenix, Earmark</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 11 Oct 2025 00:00:00 +0000</lastBuildDate>

	<atom:link href="https://fmac.xyz/posts/index.xml" rel="self" type="application/rss+xml" />

  
    <item>
      <title>Connect FWA modem to Mikrotik router</title>
      <link>https://fmac.xyz/posts/2025/10/11/connect-fwa-modem-to-mikrotik-router/</link>
      <pubDate>Sat, 11 Oct 2025 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2025/10/11/connect-fwa-modem-to-mikrotik-router/</guid>
      <description>&lt;h1&gt;
Connect FWA modem to Mikrotik router&lt;/h1&gt;
&lt;p&gt;
Due to issues outside of my control (probably the issue is Italy) I can’t get
FTTH Internet connection.  &lt;br&gt;
The best I can have for now is FWA (Fixed Wireless Access). 300 Mbps. Nowhere
close to fiber speed, but I’m not complaining.&lt;/p&gt;
&lt;p&gt;
For FWA plans, the ISP usually sells you (there’s no choice because fuck you)
their shitty router and the “5G antenna” which is a PoE modem plus the antenna.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/zyxel1.jpg&quot; alt=&quot;zyxel1&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/modem.jpg&quot; alt=&quot;modem&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
I’m fine with using their modem but using their WiFi router is just stupid. I
want to get rid of it and connect the modem directly to my Mikrotik router.&lt;/p&gt;
&lt;h2&gt;
Info gathering&lt;/h2&gt;
&lt;p&gt;
In my case the router is a Zyxel device, so not the worst shit you might get
from an ISP.  &lt;br&gt;
It exposes a web UI that offers a decent level of customization. At least
enough for me to understand what’s going on between the two devices.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/zyxel2.jpg&quot; alt=&quot;zyxel2&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
It has a bunch of interfaces already configured, most of them are useless.
“FWA_data” is obviously the one I need to replicate on my Mikrotik. Let’s have a
look at its details.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/zyxel3.jpg&quot; alt=&quot;zyxel3&quot;&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
“Encapsulation” is set to IPoE. So it expects common IP packets, nothing more
complicated such as PPPoE with credentials. Makes sense, auth should be
handled by the 5G modem, where you install the SIM card.  &lt;/li&gt;
  &lt;li&gt;
“Obtain an IP Address Automatically”. OK, it clearly has a DHCP client on
this interface.  &lt;/li&gt;
  &lt;li&gt;
VLAN 802.1q is enabled, and it says “10”. Clearly this interface expects
tagged frames with VLAN ID 10.  &lt;/li&gt;
  &lt;li&gt;
“NAT” is enabled. OK, I guess we’ll add a masquerade rule.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
These are the interesting parts of config I have to port to the Mikrotik.&lt;/p&gt;
&lt;h2&gt;
Mikrotik setup&lt;/h2&gt;
&lt;p&gt;
I have a hAP ax³. &lt;a href=&quot;https://mikrotik.com/product/hap_ax3&quot;&gt;Info&lt;/a&gt;.  &lt;br&gt;
I’ll connect the modem to &lt;code class=&quot;inline&quot;&gt;ether1&lt;/code&gt;.  &lt;br&gt;
Well, there is a PoE injection in the middle, but nothing to worry about.  By
the way, &lt;code class=&quot;inline&quot;&gt;ether1&lt;/code&gt; offers PoE out, so I tried to power the modem without the
injector, but it wasn’t enough. Enough what? I don’t know, I didn’t
investigate. I guess voltage too low. The hAP didn’t even detected the modem as
a PoE device.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/mikrotik1.jpg&quot; alt=&quot;mikrotik1&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
I’m on RouterOS 7.20.1.&lt;/p&gt;
&lt;p&gt;
First I attached a DHCP client to &lt;code class=&quot;inline&quot;&gt;ether1&lt;/code&gt;, just to see if I get an IP.  &lt;br&gt;
Make sure to remove &lt;code class=&quot;inline&quot;&gt;ether1&lt;/code&gt; from bridges before attaching a DHCP client to it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ip dhcp-client
add add-default-route=no default-route-tables=main interface=ether1 use-peer-dns=no use-peer-ntp=no&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
And the modem really gave me an IP. I’m not sure it’s useful for anything,
since the modem won’t work as gateway on this network. Maybe it’s exposing some
management interface here though. But I didn’t look for it yet.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[fmac@MikroTik_hAP_ax3] &amp;gt; /ip/dhcp-client/print where interface=ether1
Columns: INTERFACE, USE-PEER-DNS, ADD-DEFAULT-ROUTE, STATUS, ADDRESS
# INTERFACE  USE-PEER-DNS  ADD-DEFAULT-ROUTE  STATUS  ADDRESS           
0 ether1     no            no                 bound   192.168.252.150/24&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Now I know for sure that VLAN 10 is required. So let’s create &lt;code class=&quot;inline&quot;&gt;VLAN10&lt;/code&gt; on
&lt;code class=&quot;inline&quot;&gt;ether1&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/interface vlan
add comment=&amp;quot;windtre FWA&amp;quot; interface=ether1 name=VLAN10 vlan-id=10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Then another DHCP client to beg for an address on VLAN 10.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ip dhcp-client
add add-default-route=yes allow-reconfigure=no check-gateway=none comment=&amp;quot;windtre FWA&amp;quot; \
    default-route-distance=1 default-route-tables=main dhcp-options=hostname,clientid disabled=no \
    interface=VLAN10 use-broadcast=both use-peer-dns=no use-peer-ntp=no&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Good, we got an IP.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[fmac@MikroTik_hAP_ax3] &amp;gt; /ip/address/print where interface=VLAN10
Flags: D - DYNAMIC
Columns: ADDRESS, NETWORK, INTERFACE
 #   ADDRESS            NETWORK         INTERFACE
10 D 100.RE.DAC.TED/29  100.RE.DAC.TED  VLAN10   &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Finally add a NAT rule to masquerade.  &lt;br&gt;
In my case I have to make sure &lt;code class=&quot;inline&quot;&gt;VLAN10&lt;/code&gt; is in the &lt;code class=&quot;inline&quot;&gt;WAN&lt;/code&gt; list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ip firewall nat
add action=masquerade chain=srcnat comment=&amp;quot;WAN masquerade&amp;quot; out-interface-list=WAN&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;
Test&lt;/h2&gt;
&lt;p&gt;
And it works!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[fmac@MikroTik_hAP_ax3] &amp;gt; /tool/ping address=9.9.9.9
  SEQ HOST                                     SIZE TTL TIME       STATUS                                
    0 9.9.9.9                                    56  53 32ms468us &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/connect-fwa-modem-to-mikrotik/fast.jpg&quot; alt=&quot;fast&quot;&gt;
&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Deploying Anubis in front of my pastebin</title>
      <link>https://fmac.xyz/posts/2025/04/18/deploying-anubis-in-front-of-my-pastebin/</link>
      <pubDate>Fri, 18 Apr 2025 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2025/04/18/deploying-anubis-in-front-of-my-pastebin/</guid>
      <description>&lt;h1&gt;
Deploying Anubis in front of my pastebin&lt;/h1&gt;
&lt;p&gt;
&lt;a href=&quot;https://anubis.techaro.lol/&quot;&gt;Anubis&lt;/a&gt; is getting a lot of attention recently.
Since I love trying out new interesting projects, here I am deploying it to
protect my pastebin. Not that &lt;a href=&quot;https://p.fmac.xyz/&quot;&gt;Pasticcio&lt;/a&gt; really needs it,
but f*ck AI bots, so…&lt;/p&gt;
&lt;p&gt;
The pastebin is a K8s Deployment. I don’t have an Ingress. HAProxy is the SSL
termination, and forwards to the NodePort of the Service.  &lt;br&gt;
Of course Anubis must go between them.  &lt;br&gt;
I have to decide how to deploy Anubis: as a system service or in Kubernetes?&lt;/p&gt;
&lt;p&gt;
I could not find an official Helm chart, but they already provide the Docker
image.  &lt;br&gt;
I’ll put down a chart. It should be pretty easy.  &lt;br&gt;
Spoiler: &lt;a href=&quot;https://git.sr.ht/~fmac/charts/tree/7b8cc98eff11a40e610b2af48d5cb442400ee2a4/item/anubis&quot;&gt;the chart&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Helm chart&lt;/h2&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;helm create anubis&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
At the moment of writing 1.16 is the latest, so let’s put it in the values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;yaml&quot;&gt;image:
  repository: ghcr.io/techarohq/anubis
  tag: &amp;quot;v1.16.0&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Then a section for the custom environment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;yaml&quot;&gt;env:
  DIFFICULTY: 4
  SERVE_ROBOTS_TXT: &amp;quot;true&amp;quot;
  TARGET: &amp;quot;http://pasticcio:4000&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
The probes required adding a header for the client (the probe) IP. The check
won’t pass without it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;yaml&quot;&gt;livenessProbe:
  httpGet:
    path: /
    port: 8923
    httpHeaders:
      - name: x-real-ip
        value: 127.0.0.1
readinessProbe:
  httpGet:
    path: /
    port: 8923
    httpHeaders:
      - name: x-real-ip
        value: 127.0.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
And this is basically it.  &lt;br&gt;
Deployed with:
&lt;code class=&quot;inline&quot;&gt;helm upgrade -n pasticcio --cleanup-on-fail --install -f custom-values.yaml anubis .&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
Edited the HAProxy config to forward to the Anubis NodePort. Done.&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Why stream error stream ID 1; CANCEL; received from peer?</title>
      <link>https://fmac.xyz/posts/2025/03/31/why-stream-error-stream-id-1-cancel-received-from-peer/</link>
      <pubDate>Mon, 31 Mar 2025 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2025/03/31/why-stream-error-stream-id-1-cancel-received-from-peer/</guid>
      <description>&lt;h1&gt;
Why &lt;code class=&quot;inline&quot;&gt;stream error: stream ID 1; CANCEL; received from peer&lt;/code&gt;?&lt;/h1&gt;
&lt;p&gt;
Few days ago my &lt;a href=&quot;https://gmcmap-proxy.fmac.xyz/&quot;&gt;GMC Map proxy&lt;/a&gt; stopped
working.  &lt;br&gt;
This is the service I made few years ago to fasten the data loading of my
&lt;a href=&quot;https://sr.ht/~fmac/gmcmap-app/&quot;&gt;app&lt;/a&gt;.  &lt;br&gt;
The gmcparse program sends an HTTP GET request and matches a bunch of regexes on
the response to extract useful data for the app.  &lt;br&gt;
All I know from the pod log is that the server is resetting connections from my
client.  &lt;/p&gt;
&lt;p&gt;
From gmcparse:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ $ gmcparse 
main.go:48: INFO: Fetching https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0
main.go:52: Get &amp;quot;https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0&amp;quot;: stream error: stream ID 1; CANCEL; received from peer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Request to the same URL from the same IP: no problems.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[fmac@kube1 ~]$ curl -I &amp;#39;https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0&amp;#39;
HTTP/2 200 
cache-control: private
content-length: 575571
content-type: text/html
server: Microsoft-IIS/10.0
set-cookie: ASPSESSIONIDQGTTSSRD=JKEEPBDBOEIKLDFLAIPPNJAC; secure; path=/
x-powered-by: ASP.NET
x-powered-by-plesk: PleskWin
date: Mon, 31 Mar 2025 21:36:24 GMT&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
OK, they’re not blocking my IP.&lt;/p&gt;
&lt;p&gt;
Let me try locally with the same image.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull camuffo/gmcmap-parser:latest
[I] fmac@absinthe ~ (main) [1]&amp;gt; docker run --rm -it camuffo/gmcmap-parser:latest gmcparse
main.go:48: INFO: Fetching https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0
main.go:52: Get &amp;quot;https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0&amp;quot;: stream error: stream ID 1; CANCEL; received from peer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Same issue.&lt;/p&gt;
&lt;p&gt;
Does rebuilding the program with the latest Go fix it?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[I] fmac@absinthe ~/s/gqelectronics-gmcmap-parser (main)&amp;gt; go build main.go
[I] fmac@absinthe ~/s/gqelectronics-gmcmap-parser (main)&amp;gt; ./main
main.go:48: INFO: Fetching https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0
main.go:52: Get &amp;quot;https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0&amp;quot;: stream error: stream ID 1; CANCEL; received from peer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
No.&lt;/p&gt;
&lt;p&gt;
I wanna see what’s going on.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[I] fmac@absinthe ~ (main) [1]&amp;gt; yay -S zaproxy
[I] fmac@absinthe ~ (main)&amp;gt; export _JAVA_OPTIONS=&amp;#39;-Dsun.java2d.uiScale=2.5&amp;#39; # (java lol)
[I] fmac@absinthe ~ (main)&amp;gt; zaproxy &lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;doas mv zap_root_ca.cer /usr/share/ca-certificates/trust-source/anchors/
doas update-ca-trust&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[I] fmac@absinthe ~/s/gqelectronics-gmcmap-parser (main)&amp;gt; export http_proxy=127.0.0.1:8080
[I] fmac@absinthe ~/s/gqelectronics-gmcmap-parser (main)&amp;gt; export https_proxy=127.0.0.1:8080
[I] fmac@absinthe ~/s/gqelectronics-gmcmap-parser (main)&amp;gt; ./main
main.go:48: INFO: Fetching https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0
main.go:68: INFO: Deduplicated 0 lines
main.go:70: INFO: Parsing 5102 bytes, 0 lines (\r)
main.go:172: INFO: Parsed 0 mearuments
[]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
On ZAP:&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/stream-error-stream-id-1-cancel-received-from-peer/zap1.jpg&quot; alt=&quot;zap1&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
Nothing unexpected here. The Java client is getting a reset as well. Not a
problem with the Go client.&lt;/p&gt;
&lt;p&gt;
This is when my fear of GQ Electronics having done something sad started to
grow over the expectations.&lt;/p&gt;
&lt;p&gt;
Please, don’t tell me you banned the Go user agent string.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/stream-error-stream-id-1-cancel-received-from-peer/zap2.jpg&quot; alt=&quot;zap2&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
And apparently, yes, they did.  &lt;br&gt;
This is very sad.  &lt;br&gt;
I don’t wanna think they banned this UA string because of my service. Probably
they were bothered by other bots. I might end up asking them the reason behind
this in the forum. In any case, since they were not so nice to whitelist my IP, 
from now on I’ll present myself with the motherfucking Chrome user agent string.&lt;/p&gt;
&lt;p&gt;
Let me patch the program to support customizing the UA string.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--- a/main.go
+++ b/main.go
@@ -30,14 +30,15 @@ type Measurement struct {
 }
 
 var url string
+var uaString string
 
 func init() {
        const (
                defaultUrl = &amp;quot;https://gmcmap.com/ajaxm.asp?OffSet=0&amp;amp;Limit=1000000&amp;amp;dataRange=1&amp;amp;timeZone=0&amp;quot;
-               usage      = &amp;quot;URL&amp;quot;
        )
-       flag.StringVar(&amp;amp;url, &amp;quot;url&amp;quot;, defaultUrl, usage)
-       flag.StringVar(&amp;amp;url, &amp;quot;u&amp;quot;, defaultUrl, usage+&amp;quot; (shorthand)&amp;quot;)
+       flag.StringVar(&amp;amp;uaString, &amp;quot;useragent&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;User-agent string&amp;quot;)
+       flag.StringVar(&amp;amp;url, &amp;quot;url&amp;quot;, defaultUrl, &amp;quot;URL&amp;quot;)
+       flag.StringVar(&amp;amp;url, &amp;quot;u&amp;quot;, defaultUrl, &amp;quot;URL (shorthand)&amp;quot;)
 }
 
 func main() {
@@ -47,7 +48,22 @@ func main() {
 
        errLog.Printf(&amp;quot;INFO: Fetching %v&amp;quot;, url)
 
-       resp, err := http.Get(url)
+       client := &amp;amp;http.Client{
+               Transport: &amp;amp;http.Transport{
+                       Proxy: http.ProxyFromEnvironment,
+               },
+       }
+
+       req, err := http.NewRequest(&amp;quot;GET&amp;quot;, url, nil)
+       if err != nil {
+               errLog.Fatalf(&amp;quot;ERROR: creating HTTP request: %v&amp;quot;, err)
+       }
+
+       if uaString != &amp;quot;&amp;quot; {
+               req.Header.Set(&amp;quot;User-Agent&amp;quot;, uaString)
+       }
+
+       resp, err := client.Do(req)
        if err != nil {
                errLog.Fatal(err)
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;a href=&quot;https://git.sr.ht/~fmac/gqelectronics-gmcmap-parser/commit/9a7ef0948718a691632fc2b5a493801038a6f1a1&quot;&gt;commit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
Let’s try this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./main -useragent &amp;#39;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/stream-error-stream-id-1-cancel-received-from-peer/zap3.jpg&quot; alt=&quot;zap3&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
OK. I’ll fix the Dockerfile to support this and roll out.&lt;/p&gt;
&lt;p&gt;
This was really a bad surprise from GQ Electronics, since they manufactured two
of my beloved dosimeters.&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>My first desktop PC</title>
      <link>https://fmac.xyz/posts/2025/03/29/my-first-desktop-pc/</link>
      <pubDate>Sat, 29 Mar 2025 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2025/03/29/my-first-desktop-pc/</guid>
      <description>&lt;h1&gt;
My first desktop PC&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2025-03-29&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
I’ve only owned laptops all my life. Recently I felt the desire for a powerful
desktop PC.&lt;/p&gt;
&lt;p&gt;
I decided to assemble it myself to save some money.  &lt;br&gt;
I planned to spend ~1500 euros. At the end the total spent was ~1700 euros.&lt;/p&gt;
&lt;h2&gt;
Motherboard&lt;/h2&gt;
&lt;p&gt;
I wanted a small board, but big enough to fit two NVMes and a decent graphic
card. The Micro-ATX is best compromise for me.  &lt;br&gt;
Turns out my favourite form factor is the cheapest one. Happy about it.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;GIGABYTE B850M AORUS ELITE WIFI6E ICE&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/mb.jpg&quot; alt=&quot;mb&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€284,88&lt;/p&gt;
&lt;h2&gt;
CPU&lt;/h2&gt;
&lt;p&gt;
Knowing nothing about the state of the art of CPUs, I started from the latest
and greatest Ryzen (which I believe is the 9950X3D). It costs a bit too much for
me. After a bit of specs/prices comparisons I decided for the 9900X, which again
is a good compromise for me.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;AMD Ryzen 9900X&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
AM5. 12 cores up to 5.6 GHz. 120W TDP. 76MB cache. &lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/cpu1.jpg&quot; alt=&quot;cpu1&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/cpu2.jpg&quot; alt=&quot;cpu2&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/cpu3.jpg&quot; alt=&quot;cpu3&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€495,67&lt;/p&gt;
&lt;h3&gt;
Cooler&lt;/h3&gt;
&lt;p&gt;
I’m cooling it with some liquid.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;MSI MAG CORELIQUID E240&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/liquid.jpg&quot; alt=&quot;liquid&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€99&lt;/p&gt;
&lt;h2&gt;
RAM&lt;/h2&gt;
&lt;p&gt;
Hmm… Enough of it and fast enough sounds good.&lt;/p&gt;
&lt;p&gt;
2 x 16 GB. 6000MHz DDR5.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/ram.jpg&quot; alt=&quot;ram&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€89,8&lt;/p&gt;
&lt;h2&gt;
Storage&lt;/h2&gt;
&lt;p&gt;
I bought a new NVMe. Never had problems with Crucial.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Crucial P3 Plus&lt;/strong&gt;
1 TB. M2 2280.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/nvme.jpg&quot; alt=&quot;nvme&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€77,99&lt;/p&gt;
&lt;h2&gt;
Power supply&lt;/h2&gt;
&lt;p&gt;
I don’t know exactly how much power I’ll need but 850 W will be enough.&lt;/p&gt;
&lt;p&gt;
I got one that should be good in terms of power efficiency.  &lt;br&gt;
Something with PLATINUM written on it should be OK.
See &lt;a href=&quot;https://www.clearesult.com/80plus/&quot;&gt;80 Plus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Corsair SF850&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/power.jpg&quot; alt=&quot;power&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€199,9&lt;/p&gt;
&lt;h2&gt;
Case&lt;/h2&gt;
&lt;p&gt;
I like seeing what’s inside. It needs glass. Also want it to be small.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Mars Gaming MC-SE&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/case.jpg&quot; alt=&quot;case&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
Cons: it lacks a USB C port.&lt;/p&gt;
&lt;p&gt;
€45,5&lt;/p&gt;
&lt;h2&gt;
GPU&lt;/h2&gt;
&lt;p&gt;
Fuck Nvidia.&lt;/p&gt;
&lt;p&gt;
The best from AMD costs too much. I got something that’s just OK. Hopefully I’ll
upgrade in the future. The PCIe 5 slot on the MB is quite future proof.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Radeon RX 7600 XT&lt;/strong&gt; (GIGABYTE board)&lt;/p&gt;
&lt;p&gt;
16 GB RAM&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/gpu1.jpg&quot; alt=&quot;gpu1&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/gpu2.jpg&quot; alt=&quot;gpu2&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€357,12&lt;/p&gt;
&lt;h2&gt;
Build&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build1.jpg&quot; alt=&quot;build1&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build2.jpg&quot; alt=&quot;build2&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build3.jpg&quot; alt=&quot;build3&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build4.jpg&quot; alt=&quot;build4&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build5.jpg&quot; alt=&quot;build5&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build6.jpg&quot; alt=&quot;build6&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build7.jpg&quot; alt=&quot;build7&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/build8.jpg&quot; alt=&quot;build8&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
Looks good :D&lt;/p&gt;
&lt;hr class=&quot;thin&quot;&gt;
&lt;h2&gt;
Notes&lt;/h2&gt;
&lt;p&gt;
The ATX cable and the CPU cable provided with the PSU were too short.  &lt;br&gt;
I had to buy two extensions.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/my_first_desktop_pc/cables.jpg&quot; alt=&quot;cables&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
€12,8&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Moving searx from Hetzner to 1984</title>
      <link>https://fmac.xyz/posts/2023/07/25/moving-searx-from-hetzner-to-1984/</link>
      <pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2023/07/25/moving-searx-from-hetzner-to-1984/</guid>
      <description>&lt;h1&gt;
Moving searx from Hetzner to 1984&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2023-07-25&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
My &lt;a href=&quot;https://searx.fmac.xyz&quot;&gt;Searx instance&lt;/a&gt; started one day at
&lt;a href=&quot;https://exoscale.com&quot;&gt;Exoscale&lt;/a&gt;. It’s a great VPS provider, but at some point 9
€/month felt too much.&lt;/p&gt;
&lt;p&gt;
For the last few months Hetzner hosted my instance smoothly. Sadly, I recentry
received this abuse report.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dear Sir or Madam,

Thank you for your statement.

-----
I&amp;#39;m hosting a metasearch engine.
What is happening is supposed to happen.
-----

Then please stop hosting that service and move it to another provider.

We can give you 48 hours to confirm that, otherwise we will lock the IP.

Important: Please leave [AbuseID:&amp;lt;redacted&amp;gt;] unchanged in the subject line when replying directly to this report.

Kind regards

Abuse Team

[...]

&amp;gt; Dear Mr Francesco Camuffo,
&amp;gt;
&amp;gt; We have received an abuse report from anti-abuse-external@google.com.
&amp;gt;
&amp;gt; Please check the report for details and fix any (potential) problems:
&amp;gt;
&amp;gt; -----
&amp;gt; +-------------------------+--------------------------+----------+---------------------+
&amp;gt; | Source                  | Destination              | DestPort | Time_UTC            |
&amp;gt; +-------------------------+--------------------------+----------+---------------------+
&amp;gt;
&amp;gt;  2a01:4f8:1c17:7a52::1, 2a00:1450:4001:829::2004 ,443, 2023-07-17 22:09:54 
&amp;gt;
&amp;gt; -----
&amp;gt;
&amp;gt; We will need a reply from you within the next *24 hours*.
&amp;gt;
&amp;gt; Once you have resolved any problems or if you think there is no problem, please send us a statement. This statement should let us know what the problem was, how you resolved it and what steps you have taken to prevent it from happening again. Otherwise it should let us know why exactly you think the report is not valid.
&amp;gt;
&amp;gt; Please send us the statement via the following link: https://abuse.hetzner.com/statements/?token=&amp;lt;redacted&amp;gt;
&amp;gt;
&amp;gt; If you fail to comply within the stated deadline, the IP may be locked according to 8.4. of our Terms and Conditions (https://www.hetzner.com/legal/terms-and-conditions).
&amp;gt;
&amp;gt; Important: Please leave [AbuseID:&amp;lt;redacted&amp;gt;] unchanged in the subject line when replying directly to this report.
&amp;gt;
&amp;gt; Kind regards
&amp;gt;
&amp;gt; Abuse Team
&amp;gt;
&amp;gt; Hetzner Online GmbH
&amp;gt; Industriestr. 25
&amp;gt; 91710 Gunzenhausen / Germany
&amp;gt; Tel: +49 9831 505-0
&amp;gt; Fax: +49 9831 505-3
&amp;gt; abuse@hetzner.com
&amp;gt; www.hetzner.com
&amp;gt;
&amp;gt; Register Court: Registergericht Ansbach, HRB 6089
&amp;gt; CEO: Martin Hetzner, Stephan Konvickova, Günther Müller&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
First of all: fu*k google.  &lt;br&gt;
Second: I have to find a new home for my instance.&lt;/p&gt;
&lt;p&gt;
I want to stay in a nice country, so there are few options.  &lt;br&gt;
&lt;a href=&quot;https://1984.hosting&quot;&gt;1984.is&lt;/a&gt; is definitely worth a try.  &lt;br&gt;
I went with the cheapest VPS they offer. 4.5 €/month is acceptable. Sadly,
prices scale bad.&lt;/p&gt;
&lt;p&gt;
First thing I loved after buying: this nice plain-text email.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dear Customer,

Your vps is now ready for install. As requested we didn&amp;#39;t install a operating system on your vps.  You have access to the following images. If you feel your favorite image is missing let us know.  No, Windows will never be available. 🙂

Available images:
AlmaLinux-8.8
Debian GNU/Linux Bookworm 12.0
mikrotik-7.10beta8
Ubuntu 22.10-live-server
Calculate Linux Scratch 23
Android 9.0-r2
AlmaLinux-9.2
9front-9442
Kodachi 8.26
Tails 5.5
Mikrotik 7.6
Hyperbola v0.4.1[0]
hrmpf 20211227
Fedora Server 37-1.7
ClearOS 7, Community Edition
Ubuntu-22.04.1
openSUSE-Leap-15.3
Rocky-9.0-20220805.0
Trisquel 10.0.1 GNU/Linux
NetBSD-9.2
Trisquel 9.0.1 GNU/Linux
Devuan Chimaera 4.0
OpenBSD install 7.3
Parrot-security-4.11.2
OPNsense-21.7.1
Trisquel GNU/Linux
pfSense-CE-2.5.1
3CX Debian
OpenBSD install 6.9
Ubuntu-21.04
Ubuntu Server 20.10
Debian Bullseye 11.1.0
CentOS-9
Fedora Server 35-1.2
Rancher 1.0
proxmox-mailgateway_6.3-1
hyperbola-milky-way-v0.3.1
Devuian ascii 2.1
Ubuntu Server 18.04 LTS
OpenBSD install 6.6
void-live-x86_64-20191109
grml64-small_2021.07
Debian 9.3 Stretch 64bit
Alpine Linux 3.17.0
FreePBX-64bit-10.13.66
Fedora Server 23
Parabola GNU/Linux-libre 2020.08.03
Ubuntu Server 16.04 LTS
archlinux-2022.06.01
Gentoo 20220102
FreeBSD-13.2
CentOS-7-x86_64-NetInstall-2009
HardenedBSD-13-stable-bootonly
ubuntu-18.04.4
artix-base-s6-20201109
UCS 4.4
manjaro-architect-20.0.3-200607
NixOS minimal 22.05
turnkey-mattermost-16.0-buster
Ubuntu Server 20.04
CentOS-8.1.1911-x86_64
CentOS-8-x86_64-1905
Slackware 15.0
Kha-OS-Stable-Pentest-Edition.082022.Oficial
LibertBSD6.1
Ubuntu Server 19.04
Debian 10.0 Buster 64bit
guix-system-install-1.4.0
DragonFlyBSD-5.4.1
System Rescue CD 8.04-amd64

Regards, 1984 Hosting.
1984 ehf. | P.O. Box 126, 121 Reykjavik ICELAND | Sími: 00354 546 1984 | 1984@1984.is&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Such a juicy selection of ISOs intrigued me. c:  &lt;br&gt;
Of course I went with Alpine.  &lt;br&gt;
By the way, &lt;a href=&quot;https://fmac.xyz/posts/2023/07/25/hosting-searx-on-alpine/&quot;&gt;here&lt;/a&gt;
is how you could host &lt;a href=&quot;https://searxng.org&quot;&gt;Searxng&lt;/a&gt; on Alpine.&lt;/p&gt;
&lt;p&gt;
I’m currently waiting for the next report…&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Hostign Searxng on Alpine</title>
      <link>https://fmac.xyz/posts/2023/07/25/hostign-searxng-on-alpine/</link>
      <pubDate>Tue, 25 Jul 2023 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2023/07/25/hostign-searxng-on-alpine/</guid>
      <description>&lt;h1&gt;
Hosting Searxng on Alpine&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2023-07-25&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
Here’s how you could host &lt;a href=&quot;https://searxng.org&quot;&gt;Searxng&lt;/a&gt; on Alpine Linux.&lt;/p&gt;
&lt;p&gt;
Note that I don’t wish to create a venv.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;[ $(id -u) -eq 0 ] || exit 1

apk add git python3 py3-gunicorn py3-pip py3-yaml

mkdir /usr/local/searx
addgroup -S searx
adduser -S -D -h /usr/local/searx -s /sbin/nologin -G searx searx
chown -R searx:searx /usr/local/searx
doas -u searx git clone https://github.com/searxng/searxng.git /usr/local/searx/searx-src
doas -u searx pip install -r /usr/local/searx/searx-src/requirements.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Follow the official guide for the &lt;code class=&quot;inline&quot;&gt;/etc/searxng/settings.yml&lt;/code&gt; stuff and then try to run.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;cd /usr/local/searx/
doas -u searx gunicorn -b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src searx.webapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Hope to see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;txt&quot;&gt;/usr/local/searx # doas -u searx gunicorn -b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src searx.webapp
[2023-07-25 21:40:38 +0000] [2837] [INFO] Starting gunicorn 20.1.0
[2023-07-25 21:40:38 +0000] [2837] [INFO] Listening at: http://127.0.0.1:8001 (2837)
[2023-07-25 21:40:38 +0000] [2837] [INFO] Using worker: sync
[2023-07-25 21:40:38 +0000] [2838] [INFO] Booting worker with pid: 2838&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Now you got searxng running but if you want it public we should prepare filtron
and morty, and make them services. 🥵&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;doas apk add go
go install github.com/asciimoo/filtron@latest
go install github.com/asciimoo/morty@latest
doas mv ~/go/bin/filtron ~/go/bin/morty /usr/local/bin

doas addgroup -S filtron
doas adduser -S -D -H -s /sbin/nologin -G filtron filtron
doas addgroup -S morty
doas adduser -S -D -H -s /sbin/nologin -G morty morty&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Now, let me omit obvious explainations. The point is you should get to have something
like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;searx:~$ cat /etc/init.d/filtron
#!/sbin/openrc-run

supervisor=supervise-daemon
name=filtron
command=&amp;quot;/usr/local/bin/filtron&amp;quot;
command_args=&amp;quot;-api &amp;#39;127.0.0.1:4005&amp;#39; -listen &amp;#39;127.0.0.1:4004&amp;#39; -rules &amp;#39;/etc/filtron/rules.json&amp;#39; -target &amp;#39;127.0.0.1:8001&amp;#39;&amp;quot;
command_user=&amp;quot;${FILTRON_USER:-filtron}&amp;quot;
pidfile=&amp;quot;/run/filtron.pid&amp;quot;

depend() {
  need net
  after firewall
}
searx:~$ doas rc-service filtron start
 * Starting filtron ...                                                    [ ok ]
searx:~$ doas rc-update add filtron
 * service filtron added to runlevel default&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;searx:~$ cat /etc/init.d/morty
#!/sbin/openrc-run

supervisor=supervise-daemon
name=morty
command=&amp;quot;/usr/local/bin/morty&amp;quot;
command_user=&amp;quot;${FILTRON_USER:-morty}&amp;quot;
supervise_daemon_args=&amp;quot;--env DEBUG=false --env MORTY_ADDRESS=127.0.0.1:3000 --env MORTY_KEY=&amp;lt;your secret key generated with `openssl rand -base64 33`&amp;gt;&amp;quot;
pidfile=&amp;quot;/run/morty.pid&amp;quot;

depend() {
  need net
  after firewall
}
searx:~$ doas rc-service morty start
 * Starting morty ...                                                      [ ok ]
searx:~$ doas rc-update add morty
 * service morty added to runlevel default&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;searx:~$ cat /etc/init.d/searx
#!/sbin/openrc-run

supervisor=supervise-daemon
name=searx
command=&amp;quot;/usr/bin/gunicorn&amp;quot;
command_args=&amp;quot;-b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src searx.webapp&amp;quot;
command_user=&amp;quot;${SEARX_USER:-searx}&amp;quot;
pidfile=&amp;quot;/run/searx.pid&amp;quot;

depend() {
  need net
  after firewall
}
searx:~$ doas rc-service searx start
 * Caching service dependencies ...                                                                        [ ok ]
 * Starting searx ...                                                                                      [ ok ]
searx:~$ doas rc-update add searx
 * service searx added to runlevel default&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Got it?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;txt&quot;&gt;searx:~$ doas netstat -ltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 searx.searx.fmac.xyz:8001 0.0.0.0:*               LISTEN      4526/gunicorn: mast
tcp        0      0 searx.searx.fmac.xyz:4005 0.0.0.0:*               LISTEN      4337/filtron
tcp        0      0 searx.searx.fmac.xyz:4004 0.0.0.0:*               LISTEN      4337/filtron
tcp        0      0 searx.searx.fmac.xyz:3000 0.0.0.0:*               LISTEN      4367/morty&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Cool. We can now serve this through a nice reverse proxy.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;doas apk add caddy&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;txt&quot;&gt;searx:~$ cat /etc/caddy/Caddyfile
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile

searx.fmac.xyz {
    tls {
        protocols tls1.2 tls1.3
        ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    }

    root * /usr/local/searx/searx-src/searx

    @static {
        method GET
        path /static/*
    }
    file_server @static

    @searx {
        not path /static/*
        not path /morty/*
    }
    reverse_proxy @searx 127.0.0.1:4004 {
        header_up X-Real-IP {http.request.remote.host}
    }

    reverse_proxy /morty/* 127.0.0.1:3000 {
        header_up Host {http.reverse_proxy.upstream.hostport}
        header_up X-Real-IP {http.request.remote.host}
    }

    header * Strict-Transport-Security &amp;quot;max-age=63072000&amp;quot;
    header * Feature-Policy &amp;quot;accelerometer &amp;#39;none&amp;#39;;ambient-light-sensor &amp;#39;none&amp;#39;; autoplay &amp;#39;none&amp;#39;;camera &amp;#39;none&amp;#39;;encrypted-media &amp;#39;none&amp;#39;;focus-without-user-activation &amp;#39;none&amp;#39;; geolocation &amp;#39;none&amp;#39;;gyroscope &amp;#39;none&amp;#39;;magnetometer &amp;#39;none&amp;#39;;microphone &amp;#39;none&amp;#39;;midi &amp;#39;none&amp;#39;;payment &amp;#39;none&amp;#39;;picture-in-picture &amp;#39;none&amp;#39;; speaker &amp;#39;none&amp;#39;;sync-xhr &amp;#39;none&amp;#39;;usb &amp;#39;none&amp;#39;;vr &amp;#39;none&amp;#39;&amp;quot;
    header * Content-Security-Policy &amp;quot;upgrade-insecure-requests; default-src &amp;#39;none&amp;#39;; script-src &amp;#39;self&amp;#39;; style-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39;; form-action &amp;#39;self&amp;#39;; font-src &amp;#39;self&amp;#39;; frame-ancestors &amp;#39;self&amp;#39;; base-uri &amp;#39;self&amp;#39;; connect-src &amp;#39;self&amp;#39; https://overpass-api.de; img-src * data: https://*.tile.openstreetmap.org; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com&amp;quot;
    header * X-Frame-Options &amp;quot;SAMEORIGIN&amp;quot;
    header * -Server

    encode zstd gzip

    log {
        output file /var/log/caddy/searx.fmac.xyz.access.log {
            roll_size 1gb
            roll_keep 12
            roll_keep_for 48h
        }
        level error
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;searx:~$ doas rc-service caddy start
searx:~$ doas rc-update add caddy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Enjoy c:&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Fuck you, Discord</title>
      <link>https://fmac.xyz/posts/2022/11/01/fuck-you-discord/</link>
      <pubDate>Tue, 1 Nov 2022 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2022/11/01/fuck-you-discord/</guid>
      <description>&lt;h1&gt;
Fuck you, Discord&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2022-11-01&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
I already knew Discord is a piece of malware masked as messaging app.  &lt;br&gt;
I tought it was also simple to join and use, to attract joyous soydevs.&lt;/p&gt;
&lt;p&gt;
Today I couldn’t try the piece of garbage.  &lt;br&gt;
The reason is explained in this short timeline. T in minutes.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;code class=&quot;inline&quot;&gt;T+0&lt;/code&gt; I create an account, process that requires my email and phone number.
Sad but acceptable.  &lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;inline&quot;&gt;T+2&lt;/code&gt; My account gets disabled for «Violation of TOS/Community
Guidelines».  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Not that I give a shit about Discord. My problem is that I wasn’t able to
interact with the &lt;a href=&quot;https://atlasgo.io/&quot; title=&quot;&quot;&gt;atlasgo&lt;/a&gt; community!&lt;/p&gt;
&lt;p&gt;
Nevertheless, I let someone at Discord know that I’m gravely disappointed.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/Screenshot_2022-11-01_20-12-12_1667329932.png&quot; alt=&quot;mail&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
Fuck you, Discord!  &lt;br&gt;
Fuck you, projects choosing discord!&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;https://social.tchncs.de/@fmac/109270081923319472&quot; title=&quot;&quot;&gt;mastorant&lt;/a&gt;&lt;/p&gt;
&lt;hr class=&quot;thin&quot;&gt;
&lt;p&gt;
&lt;strong&gt;UPDATE @ 2022.11.02&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
Nelly kindly gave me my account back.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/Screenshot_2022-11-02_22-39-15_1667425155.png&quot; alt=&quot;nelly-mail&quot;&gt;
&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Yggdrasil my computers</title>
      <link>https://fmac.xyz/posts/2022/08/09/yggdrasil-my-computers/</link>
      <pubDate>Tue, 9 Aug 2022 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2022/08/09/yggdrasil-my-computers/</guid>
      <description>&lt;h1&gt;
Yggdrasil my computers&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2022-08-09&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;https://yggdrasil-network.github.io/&quot; title=&quot;&quot;&gt;Yggdrasil&lt;/a&gt; is a thing of beauty. A smart and easy-to-use
implementation of an overlay network.  &lt;br&gt;
I’ve equipped most of my servers, my PCs and my phone with this daemon, building
a mesh network over all my beloved computers.&lt;/p&gt;
&lt;p&gt;
I’ll keep updated this list of my nice use cases.&lt;/p&gt;
&lt;h2&gt;
Workaround the lack of IPv6&lt;/h2&gt;
&lt;p&gt;
I don’t have IPv6 connectivity at home. Accessing my IPv6-only VPS would not be
immediate. But with yggdrasil I just need to have a route to it, via another
IPv4 VPS I can peer to.  &lt;br&gt;
Now I can psql into my backend (which doesn’t need IPv4 at all) across a
securely encrypted tunnel, provided the middle peer stays up.  &lt;br&gt;
It also saves me the money needed to reserve a precious IPv4 address. \o/&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Naransa overview</title>
      <link>https://fmac.xyz/posts/2022/05/16/naransa-overview/</link>
      <pubDate>Mon, 16 May 2022 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2022/05/16/naransa-overview/</guid>
      <description>&lt;h1&gt;
Naransa overview&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2022-05-16&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
Overview of my handmade Orange Dark Terror clone, the &lt;strong&gt;Naransa Dark Checco&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_1.jpg&quot; alt=&quot;naransa_1&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_2.jpg&quot; alt=&quot;naransa_2&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_3.jpg&quot; alt=&quot;naransa_3&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_4.jpg&quot; alt=&quot;naransa_4&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_5.jpg&quot; alt=&quot;naransa_5&quot;&gt;

  &lt;img src=&quot;https://pb.fmac.xyz/p/naransa/naransa_6.jpg&quot; alt=&quot;naransa_6&quot;&gt;
&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Unleash Linux process</title>
      <link>https://fmac.xyz/posts/2022/01/30/unleash-linux-process/</link>
      <pubDate>Sun, 30 Jan 2022 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2022/01/30/unleash-linux-process/</guid>
      <description>&lt;h1&gt;
Unleash Linux process&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2022-01-30&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
If you execute &lt;code class=&quot;inline&quot;&gt;ulimit -a&lt;/code&gt; in a shell&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-m: resident set size (kbytes)      unlimited
-u: processes                       95020
-n: file descriptors                1024
-l: locked-in-memory size (kbytes)  64
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 95020
-q: bytes in POSIX msg queues       819200
-e: max nice                        0
-r: max rt priority                 0
-N 15:                              unlimited&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
it shows various resource limits imposed to the process. Same limits will
eventually be inherited by the shell children.&lt;/p&gt;
&lt;p&gt;
In this case, you can observe Alpine Linux being quite restrictive on the
maximum locked-in-memory size (64KB). This is usually not a problem, but
particular programs might have a difficult time in such restricted environment.
An example is &lt;a href=&quot;https://ardour.org/&quot; title=&quot;&quot;&gt;Ardour&lt;/a&gt;, at the time of writing, my &lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_audio_workstation&quot; title=&quot;&quot;&gt;DAW&lt;/a&gt; of choice.
If I just run it, the first thing it does is complaining. It wants the
opportunity to lock more memory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ardour6
WARNING: Your system has a limit for maximum amount of locked memory!
         This might cause Ardour to run out of memory before your system runs
         out of memory. You can view the memory limit with &amp;#39;ulimit -l&amp;#39;, and it
         is normally controlled by /etc/security/limits.conf
Ardour6.9.0 (built using 6.9 and GCC version 10.3.1 20210625)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Looking for help, I couldn’t find a solution that applied to my case. Most
suggestions were about editing &lt;code class=&quot;inline&quot;&gt;/etc/security/limits.conf&lt;/code&gt;. Here you can
customize global limits for the user session. A comment in the same file reads:
&lt;code class=&quot;inline&quot;&gt;#This file sets the resource limits for the users logged in via PAM.&lt;/code&gt;. If I
logged in via a display manager such as LightDM, that would probably work, as
&lt;a href=&quot;https://wiki.archlinux.org/title/PAM&quot; title=&quot;&quot;&gt;PAM&lt;/a&gt; would happily set my custom limits. The problem is I don’t use a DM.
I use a simple login shell, which doesn’t go through PAM.&lt;/p&gt;
&lt;p&gt;
I believe &lt;a href=&quot;https://man7.org/linux/man-pages/man1/prlimit.1.html&quot; title=&quot;&quot;&gt;PRLIMIT(1)&lt;/a&gt; could be a workaround. This tool allows to set
limits of a running process. So I prepared 2 sh lines that do the trick.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;#!/bin/sh -eux
doas /usr/bin/prlimit --pid $$ --memlock=unlimited
exec &amp;quot;$@&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
This script:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
unlimits the maximum locked memory for itself (&lt;code class=&quot;inline&quot;&gt;$$&lt;/code&gt;);  &lt;/li&gt;
  &lt;li&gt;
replaces itself (&lt;code class=&quot;inline&quot;&gt;exec&lt;/code&gt;) with whatever is passed inside &lt;code class=&quot;inline&quot;&gt;$@&lt;/code&gt;.  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Because it needs root to increase a hard limit, I’ve told doas not to bother me
asking for my password.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;permit nopass fmac as root cmd /usr/bin/prlimit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Not ideal, but keeps it simple.&lt;/p&gt;
&lt;p&gt;
Now I just have to run Ardour with &lt;a href=&quot;https://git.sr.ht/~fmac/mydotfiles/tree/17024aa258745f9bf3c608037d5b34adb755fe70/item/.local/bin/unlea.sh&quot; title=&quot;&quot;&gt;&lt;code class=&quot;inline&quot;&gt;unlea.sh&lt;/code&gt;&lt;/a&gt;, and it won’t
complain anymore.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ unlea.sh ardour6
+ doas /usr/bin/prlimit --pid 7711 &amp;#39;--memlock=unlimited&amp;#39;
+ exec ardour6
Ardour6.9.0 (built using 6.9 and GCC version 10.3.1 20210625)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
I can also confirm the new limits.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat /proc/`pidof ardour-6.9.0`/limits
Limit                     Soft Limit           Hard Limit           Units
...
Max locked memory         unlimited            unlimited            bytes
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Last touch, since I like to start applications with Rofi, is to edit
&lt;code class=&quot;inline&quot;&gt;~/.local/share/applications/ardour6.desktop&lt;/code&gt; so that it will use unlea.sh.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat .local/share/applications/ardour6.desktop
[Desktop Entry]
...
Exec=unlea.sh ardour6
...&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
  
    <item>
      <title>Nested WireGuard tunnels to my home</title>
      <link>https://fmac.xyz/posts/2021/12/07/nested-wireguard-tunnels-to-my-home/</link>
      <pubDate>Tue, 7 Dec 2021 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2021/12/07/nested-wireguard-tunnels-to-my-home/</guid>
      <description>&lt;h1&gt;
Nested WireGuard tunnels to my home&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2021.12.07&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
My setup to safely (I hope) access my home network via WireGuard VPN.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; WG from my home to a VPS, to expose another WG endpoint bypassing
CGNAT.&lt;/p&gt;
&lt;p&gt;
I love the simplicity of WireGuard. It feels to me like fresh air when compared
to the disorienting huge amount of &lt;a href=&quot;https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/&quot; title=&quot;&quot;&gt;OpenVPN options&lt;/a&gt;, or to the
weapons-grade accuracy needed to set up an IKE2/IPsec tunnel. Maybe one day I’ll
try &lt;a href=&quot;http://www.openiked.org/&quot; title=&quot;&quot;&gt;iked(8)&lt;/a&gt; and I’ll love it, but for now I think setting up IPsec for a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Road_warrior_(computing)&quot; title=&quot;&quot;&gt;road warrior&lt;/a&gt; device is a nighmare. I’d still like to know why a W1nd0w$ PC
wasn’t liking the IKE chiper suites I was offering him a couple years ago.&lt;/p&gt;
&lt;p&gt;
I simply want a tunnel between my PC and my home network, using modern
cryptography. The problem is my ISP hiding my home behind &lt;a href=&quot;https://en.wikipedia.org/wiki/Carrier-grade_NAT&quot; title=&quot;&quot;&gt;CGNAT&lt;/a&gt;. For my
road warrior PC to be able to create the tunnel, the other WG peer must be
reacheable.&lt;/p&gt;
&lt;p&gt;
First of all, since I had a nice MikroTik RB750Gr3 doing nothing, it was chosen
to serve my home. RouterOS 6 doesn’t support WG. At the time of writing, ROS
7.1 beta with WG support is in testing and not very stable, but I have no choice
so that’s what I’m using.&lt;/p&gt;
&lt;p&gt;
Since this MT is not directly facing WAN, it acts as a router-on-a-stick.
Routing and firewall rules set on my main firewall that make all this work are
beyond the scope of this post, and more related to my LAN.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://pb.fmac.xyz/p/RB750Gr3-on-a-stick.jpg&quot; alt=&quot;MikroTik RB750Gr3&quot; title=&quot;&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
Now I need a VPS to bypass CGNAT. The first way I considered was this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    +--------+       +--------+       +--------+
    |        |       |        |       |        |
    |       ===========      ===========       |
    |       ====wg0====      ====wg1====       |
    |        |       |        |       |        |
    +--------+       +--------+       +--------+
        PC              VPS               MT&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
PC creates a tunnel to VPS. VPS routes packets destinated to MT into tunnel wg1.
This should work, but packets are not encrypted when they are routed between wg0
and wg1.&lt;/p&gt;
&lt;p&gt;
What if I don’t trust the VPS? The next diagram shows what I ended up with.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    +--------+       +--------+       +--------+
    |        |       ===================       |
    |       ============================       |
    |       ====wg0=====================       |
    |        |       ============wg1====       |
    +--------+       +--------+       +--------+
        PC              VPS               MT&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Here wg1 is used to expose another WG endpoint (on another port) of MT. When PC
creates wg0, VPS doesn’t get to see the end of the tunnel, it can only see
encrypted WG traffic.&lt;/p&gt;
&lt;p&gt;
To implement this, starting from MT, we have to declare:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
two WG interfaces;  &lt;/li&gt;
  &lt;li&gt;
one peer for wg1;  &lt;/li&gt;
  &lt;li&gt;
one peer for each road warrior device, for wg0.  &lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;[admin@MikroTik_hEX] &amp;gt; /interface/wireguard/print
Flags: X - disabled; R - running
 0  R name=&amp;quot;wg0&amp;quot; mtu=1420 listen-port=60000 private-key=&amp;quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&amp;quot;
      public-key=&amp;quot;njg+gAB5Zt/NJl2U8HUA6+vTJvjOIdSLhpbw7SxpADA=&amp;quot;

 1  R name=&amp;quot;wg1&amp;quot; mtu=1420 listen-port=60001 private-key=&amp;quot;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY&amp;quot;
      public-key=&amp;quot;XKm72iBBljwo3l2YAIvzO4RnbR5HitAh9UoelWjBQ3U=&amp;quot;

[admin@MikroTik_hEX] &amp;gt; /interface/wireguard/peers/print
Columns: INTERFACE, PUBLIC-KEY, ENDPOINT-ADDRESS, ENDPOINT-PORT, ALLOWED-ADDRESS, PERSISTENT-KEEPALIVE
# INTERFACE  PUBLIC-KEY                                    ENDPOINT-ADDRESS  ENDPOINT-PORT  ALLOWED-ADDRESS  PERSISTENT-KEEPALIVE
0 wg1        q9ii3/DoyZgqYkzEiTdPM9FfraDtUJdKP1KItmh6c1U=  X.X.X.X                   60100  172.16.1.0/24    25s
;;; RW1
1 wg0        TvfgJvb9Zn37tJNxWU9Lyf+/TWQQy3rFZq4xBILCRwI=                                0  172.16.0.1/32
;;; RW2
2 wg0        AFSycdpkMPYm9Fj32MB4fjiOpP306omN06WMtzo0s3g=                                0  172.16.0.2/32

[admin@MikroTik_hEX] &amp;gt; /ip/address/print where interface=wg1
Columns: ADDRESS, NETWORK, INTERFACE
# ADDRESS          NETWORK     INTERFACE
1 172.16.1.254/24  172.16.1.0  wg1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
I redacted portions of the config, but it’s quite clear. &lt;code class=&quot;inline&quot;&gt;X.X.X.X&lt;/code&gt; is the public
IP of VPS. MT initiates the tunnel to &lt;code class=&quot;inline&quot;&gt;X.X.X.X:60100&lt;/code&gt;. Note that
&lt;code class=&quot;inline&quot;&gt;persistent-keepalive=25s&lt;/code&gt; is useful to persist the state that lets us traverse
CGNAT. Otherwise, after some time of inactivity, firewalls on the path would
drop the state, and the tunnel could not be recreated trying to send a packet
from VPS to MT.&lt;/p&gt;
&lt;p&gt;
On the VPS: Alpine Linux, wireguard-tools, ifupdown-ng-wireguard.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# cat /etc/wireguard/wg1.conf
[Interface]
ListenPort = 60100
PrivateKey = ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

# MT

[Peer]
PublicKey = XKm72iBBljwo3l2YAIvzO4RnbR5HitAh9UoelWjBQ3U=
AllowedIPs = 172.16.1.254/32&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Note that there’s no &lt;code class=&quot;inline&quot;&gt;wg0.conf&lt;/code&gt; since VPS is not aware of wg0.&lt;/p&gt;
&lt;p&gt;
With this config in place and the interface activated, MT should initiate the
tunnel almost instantly, but for road warriors to be able to reach wg0 we have
to forward packets into wg1.&lt;/p&gt;
&lt;p&gt;
On VPS, right after interface &lt;code class=&quot;inline&quot;&gt;wg1&lt;/code&gt; goes up, we tell Linux to forward packets.
We also define a few &lt;a href=&quot;https://www.man7.org/linux/man-pages/man8/iptables.8.html&quot; title=&quot;&quot;&gt;iptables(8)&lt;/a&gt; dstnat rules to let the world
access wg0 port.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# cat /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
    hostname &amp;lt;redacted&amp;gt;

iface eth0 inet6 static
    address &amp;lt;redacted&amp;gt;
    gateway fe80::1
    pre-up echo 0 &amp;gt; /proc/sys/net/ipv6/conf/eth0/accept_ra

auto wg1
iface wg1 inet static
    address 172.16.1.100/24
    requires eth0
    use wireguard

    post-up echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
    post-up echo 1 &amp;gt; /proc/sys/net/ipv4/conf/all/proxy_arp
    post-up iptables -t nat -A PREROUTING -p udp -i eth0 --dport 60000 -j DNAT --to-destination 172.16.1.254
    post-up iptables -t nat -A POSTROUTING -p udp -d 172.16.1.254 --dport 60000 -j MASQUERADE

    post-down iptables -t nat -D PREROUTING -p udp -i eth0 --dport 60000 -j DNAT --to-destination 1172.16.1.254
    post-down iptables -t nat -D POSTROUTING -p udp -d 172.16.1.254 --dport 60000 -j MASQUERADE
    post-down echo 0 &amp;gt; /proc/sys/net/ipv4/ip_forward
    post-down echo 0 &amp;gt; /proc/sys/net/ipv4/conf/all/proxy_arp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Now from PC our favourite WG client might be able to complete the tunnel wg0.&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Resize an image to fit size</title>
      <link>https://fmac.xyz/posts/2021/05/05/resize-an-image-to-fit-size/</link>
      <pubDate>Wed, 5 May 2021 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2021/05/05/resize-an-image-to-fit-size/</guid>
      <description>&lt;h1&gt;
Resize an image to fit size&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2021.5.5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
It is the case that I often need to resize a bunch of PNGs of random sizes to
a maximum height of 350px, preserving ratio.&lt;/p&gt;
&lt;p&gt;
Many people would use some many-MB-weighted GUI bloatware and multiple
mouse clicks to achieve that (expecially on w1nd0w5).
Computer users who love computers choose the CLI way.&lt;/p&gt;
&lt;hr class=&quot;thin&quot;&gt;
&lt;p&gt;
&lt;a href=&quot;https://www.imagemagick.org&quot;&gt;ImageMagick&lt;/a&gt; is the solution, and is likely to be
packaged for your OS.  &lt;br&gt;
Once installed, you can run &lt;code class=&quot;inline&quot;&gt;convert&lt;/code&gt; from the shell.&lt;/p&gt;
&lt;p&gt;
Now to resize &lt;code class=&quot;inline&quot;&gt;1.png&lt;/code&gt; to fit the desired size you can do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ file 1.png         
1.png: PNG image data, 2119 x 1056, 8-bit/color RGB, non-interlaced
$ convert 1.png -resize 350x350 1-350.png        
$ file 1-350.png                         
1-350.png: PNG image data, 350 x 174, 8-bit/color RGB, non-interlaced&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
This is already amazing, but I need the image height to be 350px.  &lt;br&gt;
To do that, you specify only the height.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ convert 1.png -resize x350 1-350.png 
$ file 1-350.png                      
1-350.png: PNG image data, 702 x 350, 8-bit/color RGB, non-interlaced&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Great! Now I need to do the same thing for every image in this directory.
Let’s &lt;code class=&quot;inline&quot;&gt;find&lt;/code&gt; them.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls   
1.png  2.png  3.png  4.png
$ mkdir ../out      
$ find . -type f -exec convert {} -resize x350 ../out/{} \;
$ file ../out/*                                            
../out/1.png: PNG image data, 239 x 350, 8-bit/color RGB, non-interlaced
../out/2.png: PNG image data, 178 x 350, 8-bit/color RGB, non-interlaced
../out/3.png: PNG image data, 632 x 350, 8-bit/color RGB, non-interlaced
../out/4.png: PNG image data, 204 x 350, 8-bit/color RGB, non-interlaced&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Nice.&lt;/p&gt;
</description>
    </item>
  
    <item>
      <title>Hosting a Searx instance on OpenBSD</title>
      <link>https://fmac.xyz/posts/2021/02/06/hosting-a-searx-instance-on-openbsd/</link>
      <pubDate>Sat, 6 Feb 2021 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2021/02/06/hosting-a-searx-instance-on-openbsd/</guid>
      <description>&lt;h1&gt;
Hosting a Searx instance on OpenBSD&lt;/h1&gt;
&lt;p&gt;
&lt;strong&gt;2021.2.4-2021.2.6&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;!!!:&lt;/code&gt; This post comes from my personal notes archive, so it may be confusional and/or not structured as a lesson.&lt;/p&gt;
&lt;h5&gt;
Env&lt;/h5&gt;
&lt;ul&gt;
  &lt;li&gt;
&lt;a href=&quot;https://www.openbsd.org&quot;&gt;OpenBSD&lt;/a&gt; 6.8 GENERIC#4 amd64  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
🐡 Installation went smooth as always…&lt;/p&gt;
&lt;p&gt;
I’ve edited the default disk layout like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a      565M   85.0M    452M    16%    /
/dev/sd0k      986M    2.0K    937M     0%    /home
/dev/sd0d      782M   10.0K    743M     0%    /tmp
/dev/sd0f      2.9G    1.0G    1.7G    38%    /usr
/dev/sd0g      619M    234M    354M    40%    /usr/X11R6
/dev/sd0h      6.9G    218K    6.5G     0%    /usr/local
/dev/sd0e      4.8G    6.9M    4.6G     0%    /var&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
It’s considered bad to delete some of the proposed partitions but this is an experimental install.&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;NOTE:&lt;/code&gt; I’m following &lt;a href=&quot;https://searx.github.io/searx/admin/installation-searx.html&quot;&gt;https://searx.github.io/searx/admin/installation-searx.html&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Searx &amp;amp; gunicorn&lt;/h2&gt;
&lt;p&gt;
The &lt;a href=&quot;https://searx.me&quot;&gt;Searx&lt;/a&gt; installation guide employs
&lt;a href=&quot;https://uwsgi-docs.readthedocs.io&quot;&gt;uWSGI&lt;/a&gt;. I don’t wanna compile uWSGI plugins for OpenBSD at the moment, so to avoid errors like
&lt;code class=&quot;inline&quot;&gt;!!! UNABLE to load uWSGI plugin: File not found !!!&lt;/code&gt;
I’ll install &lt;a href=&quot;https://gunicorn.org&quot;&gt;gunicorn&lt;/a&gt; instead and improvise.&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;pkg_add python py3-pip git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;ln -s /usr/local/bin/python3.8 /usr/local/bin/python&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;ln -s /usr/local/bin/pip3.8 /usr/local/bin/pip&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;pip install gunicorn&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
Create user _searx that is going to own the gunicorn process.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir /usr/local/searx
useradd -d /usr/local/searx/ -s /sbin/nologin -u 10000 _searx
chown -R _searx:_searx /usr/local/searx/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;NOTE:&lt;/code&gt; I don’t want to use a Python virtual env for now.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /etc/doas.conf
permit setenv { -ENV PS1=$DOAS_PS1 SSH_AUTH_SOCK } :wheel&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;doas -u _searx git clone &amp;quot;https://github.com/searx/searx.git&amp;quot; \
&amp;quot;/usr/local/searx/searx-src&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;pip install -r /usr/local/searx/searx-src/requirements.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;if&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;Error: Please make sure the libxml2 and libxslt development packages are installed.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;then&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;pkg_add py3-lxml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;fi&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Follow the guide for the &lt;code class=&quot;inline&quot;&gt;/etc/searx/settings.yml&lt;/code&gt; stuff.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
Ok. Try.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /usr/local/searx/
doas -u _searx gunicorn -b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src searx.webapp&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[INFO] Listening at: http://127.0.0.1:8001 (93345)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Nice. Daemonize gunicorn. Create &lt;code class=&quot;inline&quot;&gt;/etc/rc.d/gunisearx&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/ksh

RUN_DIR=&amp;quot;/var/run/gunisearx&amp;quot;
daemon=&amp;quot;/usr/local/bin/gunicorn&amp;quot;
gunisearx_flags=&amp;quot;-b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src -p /var/run/gunisearx/gunisearx.pid -D searx.webapp&amp;quot;
gunisearx_user=&amp;quot;_searx&amp;quot;

. /etc/rc.d/rc.subr

pexp=&amp;quot;/usr/local/bin/python.*${pexp}&amp;quot;

# For the PID file.
rc_pre() {
    if [[ ! -d /var/run/gunisearx ]]; then
        mkdir $RUN_DIR
        chown -R _searx:_searx $RUN_DIR
    fi
}

rc_stop() {
    if [[ -f $RUN_DIR/gunisearx.pid ]]; then
        kill $(cat $RUN_DIR/gunisearx.pid)
        rm $RUN_DIR/gunisearx.pid
    fi
}

rc_cmd $1&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;
Filtron&lt;/h2&gt;
&lt;p&gt;
Compiled &lt;a href=&quot;https://github.com/asciimoo/filtron&quot;&gt;filtron&lt;/a&gt; on a build VM and copied to the server.&lt;/p&gt;
&lt;p&gt;
Create user _filtron that is going to own the filtron process.
&lt;code class=&quot;inline&quot;&gt;useradd -s /sbin/nologin -u 10001 _filtron&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
Daemonize filtron. Create &lt;code class=&quot;inline&quot;&gt;/etc/rc.d/filtron&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/ksh

daemon=&amp;quot;/usr/local/bin/filtron&amp;quot;
filtron_flags=&amp;quot;-api &amp;#39;127.0.0.1:4005&amp;#39; -listen &amp;#39;127.0.0.1:4004&amp;#39; -rules &amp;#39;/etc/filtron/rules.json&amp;#39; -target &amp;#39;127.0.0.1:8001&amp;#39;&amp;quot;
filtron_user=&amp;quot;_filtron&amp;quot;

rc_bg=YES

. /etc/rc.d/rc.subr

rc_cmd $1&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;
morty&lt;/h2&gt;
&lt;p&gt;
Compiled &lt;a href=&quot;https://github.com/asciimoo/morty&quot;&gt;morty&lt;/a&gt; on a build VM and copied to the server.&lt;/p&gt;
&lt;p&gt;
Create user _morty that is going to own the morty process.
&lt;code class=&quot;inline&quot;&gt;useradd -s /sbin/nologin -u 10002 _morty&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
Daemonize morty. Create &lt;code class=&quot;inline&quot;&gt;/etc/rc.d/morty&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/ksh

daemon=&amp;quot;/usr/local/bin/morty&amp;quot;
morty_user=&amp;quot;_morty&amp;quot;

rc_bg=YES

. /etc/rc.d/rc.subr

rc_cmd $1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Create a login class in &lt;code class=&quot;inline&quot;&gt;/etc/login.conf&lt;/code&gt; to set some environment variables:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...other things...

morty:\
    :setenv=DEBUG=false,MORTY_ADDRESS=127.0.0.1\c3000,MORTY_KEY=&amp;lt;key generated with `openssl rand -base64 33`&amp;gt;:\
    :tc=daemon:&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;
Bonus - nginx config&lt;/h2&gt;
&lt;p&gt;
Nginx as reverse proxy and scores A+ at SSL Labs and observatory.mozilla.org.
&lt;code class=&quot;inline&quot;&gt;/etc/nginx/nginx.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http {

...lots of things...

server {
        listen      443 ssl;
        listen      [::]:443 ssl;
        server_name searx.fmac.xyz;

        ssl_protocols   TLSv1.2 TLSv1.3;
        ssl_ciphers     ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers   on;

        ssl_certificate     /etc/ssl/searx.fmac.xyz.fullchain.pem;
        ssl_certificate_key /etc/ssl/private/searx.fmac.xyz.key;

        ssl_session_timeout 1d;
        ssl_session_cache   shared:MozSSL:10m;
        ssl_session_tickets off;

        location / {
            proxy_pass http://127.0.0.1:4004/;

            include /etc/nginx/searx-proxy-headers.conf;
            include /etc/nginx/searx-default-headers.conf;
            add_header Content-Security-Policy &amp;quot;upgrade-insecure-requests; default-src &amp;#39;none&amp;#39;; script-src &amp;#39;self&amp;#39;; style-src &amp;#39;self&amp;#39; &amp;#39;unsafe-inline&amp;#39;; form-action &amp;#39;self&amp;#39;; font-src &amp;#39;self&amp;#39;; frame-ancestors &amp;#39;self&amp;#39;; base-uri &amp;#39;self&amp;#39;; connect-src &amp;#39;self&amp;#39; https://overpass-api.de; img-src &amp;#39;self&amp;#39; data: https://*.tile.openstreetmap.org; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com&amp;quot; always;
        }

        location /static/ {
            root /var/www/htdocs/searx/;

            include /etc/nginx/searx-default-headers.conf;
            add_header Cache-Control &amp;quot;public, max-age=31536000&amp;quot; always;
        }

        location /morty {
            proxy_pass http://127.0.0.1:3000/;

            include /etc/nginx/searx-proxy-headers.conf;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr class=&quot;thin&quot;&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;/etc/nginx/searx-default-headers.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_header Feature-Policy &amp;quot;accelerometer &amp;#39;none&amp;#39;;ambient-light-sensor &amp;#39;none&amp;#39;; autoplay &amp;#39;none&amp;#39;;camera &amp;#39;none&amp;#39;;encrypted-media &amp;#39;none&amp;#39;;focus-without-user-activation &amp;#39;none&amp;#39;; geolocation &amp;#39;none&amp;#39;;gyroscope &amp;#39;none&amp;#39;;magnetometer &amp;#39;none&amp;#39;;microphone &amp;#39;none&amp;#39;;midi &amp;#39;none&amp;#39;;payment &amp;#39;none&amp;#39;;picture-in-picture &amp;#39;none&amp;#39;; speaker &amp;#39;none&amp;#39;;sync-xhr &amp;#39;none&amp;#39;;usb &amp;#39;none&amp;#39;;vr &amp;#39;none&amp;#39;&amp;quot; always;
add_header Referrer-Policy &amp;quot;no-referrer&amp;quot; always;
add_header Strict-Transport-Security &amp;quot;max-age=31536000; includeSubDomains; preload&amp;quot; always;
add_header X-Content-Type-Options &amp;quot;nosniff&amp;quot; always;
add_header X-Frame-Options &amp;quot;SAMEORIGIN&amp;quot; always;
add_header X-Robots-Tag &amp;quot;noindex, noarchive, nofollow&amp;quot; always;
add_header X-XSS-Protection &amp;quot;1&amp;quot; always;&lt;/code&gt;&lt;/pre&gt;
&lt;hr class=&quot;thin&quot;&gt;
&lt;p&gt;
&lt;code class=&quot;inline&quot;&gt;/etc/nginx/searx-proxy-headers.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;proxy_hide_header   Referrer-Policy;
proxy_hide_header   X-Content-Type-Options;
proxy_hide_header   X-Robots-Tag;
proxy_hide_header   X-Xss-Protection;
proxy_set_header    Host $host;
proxy_set_header    Connection $http_connection;
proxy_set_header    X-Real-IP $remote_addr;
proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header    X-Scheme $scheme;&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
  
    <item>
      <title>Hello world</title>
      <link>https://fmac.xyz/posts/2020/12/14/hello-world/</link>
      <pubDate>Mon, 14 Dec 2020 00:00:00 +0000</pubDate>

      <guid>https://fmac.xyz/posts/2020/12/14/hello-world/</guid>
      <description>&lt;h1&gt;
Hello world&lt;/h1&gt;
&lt;p&gt;
Please, ignore this post for now.
I’m just giving a try to &lt;a href=&quot;https://gohugo.io&quot;&gt;Hugo&lt;/a&gt;. Feels nice so far…&lt;/p&gt;
</description>
    </item>
  
  </channel>
</rss>
