agnos.is

The agnos.is blog

Published: 2025-04-16T12:58:45+02:00

The Gentoo libre-kernel dist-kernel is now working again.

A few months ago, I updated my personal overlay with the latest stable version of the gentoo-kernel package (6.12.16 at the time). But the build would always fail with a warning-as-error regarding extra arguments to sprintf in one of the drm modules.

But finally, I have fixed this. There is a kernel setting called CONFIGDRMWERROR. Normally, this is set to 'n' (i.e. no, disabled). But somehow, this option has been defaulted to 'y' (i.e., enabled). I'm not sure where or how this was changed, but I assume it's something in the Gentoo kernel configs. It took me a long, long time to find this:

  • I don't have a huge amount of time for delving into build issues.
  • The kernel would compile for 40 minutes before failing.
  • It's not immediately obvious why the warning causes failure.

I finally sat down and started poking around, and in my grepping of the kernel sources, I found the CONFIGDRMWERROR setting. After checking the documentation, and found that it was supposed to be set to off by default, I updated the ebuild, and now it builds!

There is one problem: the verify-sig USE flag seems to be broken, despite the presence of the key and signing file. But that's for a later time...

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-06-14T14:02:19+02:00

The UrbMob Kick'n'Go is one of the few electric scooters allowed on public roads in the Netherlands.

The Netherlands is a strange place when it comes to micromobility. On one hand, they have encouraged a culture of biking and avoiding cars since the ~1920s. But on the other hand, they are one of the few countries in Europe that does not allow electric (kick) scooters on the road. In Dutch, they are known as “e-steps.” What makes the whole situation even stranger is that electric scooters are -NOT- illegal in the Netherlands. They are allowed to be sold. You can walk into MediaMarkt (electronics retailer) and buy one. You are allowed to own them. What is -NOT- allowed is using them on public roads. They are limited to use on private property, which essentially means they are useless. Most houses in the Netherlands don't have big yards. Certainly not big enough to make using an electric scooter any fun.

There are a few electric scooters allowed in the Netherlands!

I am not talking about “special mopeds.”

The only actual, regular electric scooters currently allowed on the open road in the Netherlands are ones that aren't fully motorized.

  • The scooter cannot have a functioning throttle.
  • The user is required to push the scooter.
  • The motor must go to max of 25 km/h, and be no more than 250w.

If the scooter meets these requirements, they are treated as electric bikes under the current legislation, and are allowed on the public road. This is because the scooter is considered a “pedal-assisted” device (pedelec). In this design, the electric motor only starts after the rider pushes the scooter forward. The motor will activate for about 8 seconds before cutting off again, and then the rider must push again.

The UrbMob Kick&Go

The UrbMob Kick&Go.

The Kick&Go is one of two or three scooters that meets the requirements to be allowed on Dutch roads.

The other main one is the StapStep.

Both the Kick&Go and StapStep are allowed on public roads because they are treated as “pedal-assisted” vehicles, like an electric bike. The idea is that the rider has to push the scooter forward every so often in order to benefit from the electric motor.

Features

The Kick&Go is a solidly-built electric scooter with an array of standard features. Built in is an automatic braking light, a headlight, reflective stickers, and integration with a simple app.

The scooter has a throttle, but it's not functional (except in gear 1). There are 5 “gears” or speed settings.

  • 0: No power to the motor. Perfect for walking.
  • 1: Holding the throttle moves you along at 6 km/h.
  • 2: Maximum of 12 km/h.
  • 3: Maximum of 20 km/h.
  • 4: Maximum of 25 km/h.

After 1st gear, pushing the scooter forward gives power to the electric motor for approximately 8 seconds. After that, the power is cut, and you have to push yourself again!

The app is basic, which I honestly consider a pro rather than a con. It allows you to adjust all the necessary settings of the scooter while remaining in legal limits. There is no account or ride tracking involved. The app can be used to turn the headlight on and off, change your speed setting (“gear”), and toggle the parking mode.

  • Parking mode does not lock the scooter.
  • It just beeps angrily if you try to move the device.

The Build

The Kick&Go is built to feel like a step above basic electric scooters available at every major electronics outlet. While it's not top of the line material and construction, it certainly doesn't feel cheap. The body appears to be made out of quality metal, and has the branding painted on to the handlebar stem. The platform features a non-slip mat, and the rear wheel is beautifully designed with a disc brake on its left side. A headlight and brake light are built in, and reflective stickers are placed at appropriate places for increased safety.

The scooter is IP54 rated. This means it is not waterproof, but can handle light rain. It does NOT mean you should drive it through puddles on wet roads. It's not something you should use in heavy rain. If you need a scooter that can handle wet conditions properly, look for something that is IP66 rated, like the Apollo City Pro 2022

Working on the scooter is relatively easy. a collection of standard Allen/hex wrenches are all that's needed. I've tightened up the rear brake by shortening the line and also adjusted the caliper position a bit. On some old bikes, trying to adjust the brake line wound up with me losing the brake wire completely, somewhere inside the brake line itself. No such problems with the Kick&Go.

Things like removing the wheels is a bit more involved. The screws for the wheels are under the reflective stickers, so those have to be removed before doing any maintenance that requires removal of a wheel.

The Ride

The ride is fairly smooth, given that the scooter has solid tires. It's pleasant on asphalt. Less so on older brick streets. Especially in and around older cities, one can find these roads. It gets VeRy BuMpY! But even with the solid tires, it's a good travel experience.

The main feature (or quirk, if you prefer) of the Kick&Go is the fact that it cuts the motor off approximately every 8 seconds in order to comply with Dutch legislation. The scooter has to detect forward movement (i.e. you pushing it with your foot) in order for the motor to engage again. This works well at lower speeds, but is difficult when traveling at 25 km/h. Luckily, there is a solution! The scooter will continue to move if you sort of shove it forward as it moves. It looks (and feels) a bit goofy, but it's enough to trigger the speed controller and make the motor turn back on. So the ride is often not very different from a regular, fully motorized electric scooter.

The speed controller is also prone to detecting forward motion when rolling down speed bumps or inclines, which is handy. In some situations, the motor continues uninterrupted for an extended period of time, depending on the terrain.

Braking is responsive. There is one brake lever, which engages the disc brake on the rear, and then the scooter triggers the front brake right after, in order to come to a stop.

Security

No scooter is safe from theft. Like many compact e-scooters, the Kick&Go does not have dedicated locking points. A strong “handcuff”-style chain lock that goes around the base of the stem is a must. I didn't even know these types of locks existed until after buying the Kick&Go. They're inspired by handcuffs: one cuff locks around the base of the scooter, and the other cuff is locked to a bike rack or a not-too-thick pole. The two cuffs are joined by a strong chain.

A folding lock as a secondary is recommended. It can be threaded through the back of the scooter, either just through the thin metal bar that connects to the rear wheel, or more preferably, through the rear wheel itself. It takes a bit of patience to get a folding lock through the rear wheel; space is tight due to the brake disc on the wheel's left side. Thick steel won't work here. Ideally, the folding lock should be long enough that you have enough room to lock it to the bike rack while the handcuff lock acts as the scooter's main anchor.

I have a small folding lock that can fit through the rear wheel, but I don't think it's long enough. If there's not a locking point right next to the rear wheel, the folding lock is only long enough to lock the wheel itself. While this isn't a bad thing, having the lock be long enough to always be able to secure the scooter at both points is better.

Quirks and Downsides

The biggest problems with the Kick&Go come from its intentionally limited design in order to comply with the Dutch laws that allow it to be used on public roads. The Kick&Go does not have a functioning throttle. It immediately starts accelerating when it detects enough forward motion. If you leave the scooter in gears 2 to 4, you might accidentally activate the scooter's motor by walking too fast. I've done this a few times. You CAN walk with the scooter while it's in higher gear, but it's best to put it down to gear 0 or 1.

Another thing to keep in mind are the solid tires. They are honeycombed inside, so they absorb some of the shock, but it's not enough. Solid tires mean you never have to worry about flats or inflating, but they'll never be to absorb as much shock as pneumatic tires. So you be in for a bumpy ride on older brick or cobblestone roads. It rides like a dream on asphalt or newer brick that's still flat, though!

Additionally, there is one small issue with the rear fender. Because of the strong vibrations from the solid tires, the screw that holds the fender to the rear wheel bar can come undone, and then you have an obnoxious rattling sound as you ride. This is easily fixed by putting some thread lock on the screw and tightening it again—but getting to that screw requires taking the rear wheel off (although I managed to tighten it with a pair of very tiny pliers)!

Finally, the lack of a dedicated lock point is a noticeable issue. Apollo scooters have dedicated lock points on the latch mechanism at the rear of the platform. Other brands have bars integrated into the stem near the front wheel that can be used to lock the scooter. The Kick&Go only has the thin metal bars that protect the rear tire as something one might call a “locking point.” The metal bars are not flimsy, but an angle grinder will cut through them in a few seconds. This lack of a dedicated locking point is easily overcome by having a proper handcuff chain lock that can go around the base of the stem.

Conclusion

The UrbMob Kick&Go is a fine, proper scooter. And most importantly, it can be used on public roads in the Netherlands! Despite its quirks, I would recommend it as an option for someone looking to use an electric scooter in the Netherlands. At least until the legislation changes in July 2025, and in theory the RDW (road authority) starts approving some fully motorized electric scooters.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-04-17T22:27:07+02:00

I have created a new filter that enhances LLM image understanding by looking up location names from image data, when available.

It is a simple filter that pre-processes user messages and looks up the address/location name of the most recent user-supplied image. By providing the LLM with the GPS coordinates embedded in an image, along with the address (including country), the LLM can answer questions like “where was this picture taken?” accurately, reason about things located nearby where a photo was taken, and more.

It reduces hallucinations by telling the LLM where photos were taken, or instructing it to inform the user that it's not possible to determine location when no EXIF GPS data can be found.

This filter is based on my work for the OSM tool.

For the next iteration of this filter, I want to do the following:

  • Configurable location granularity. Less granular = better caching, at the expense of location accuracy.
  • Read other EXIF data (altitude, etc).
  • Handle multiple images better.

Getting and Configuring the Filter

🗺️ You can read the instructions for the filter here.

You can install the tool from the Open WebUI website.

Or you can install it directly from my git repository.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-04-16T20:08:18+02:00

A small note: the verify-sig USE flag for the libre kernel has been restored. It was a typo. I accidentally deleted the letter V out of the ebuild on the line that sets the path to the GPG key used for verification...

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-05-10T10:12:27+02:00

It's been a while since I made a blog post. But now, I have a bit of free time, and an idea struck me. It's something that's been written about plenty of times in the past few years: the rise of generative AI and how it's changing the fabric of computing, and by extension society. Generative AI seems to be a topic that, for some reason, one is not allowed to have a middle ground position on.

You either:

  • Think generative AI is changing humanity and the path to sapient machines.
  • Think it's useless slop built on intellectual property stolen from the digital world at large.

The idea that generative AI will solve all problems, change the world, “democratize technology,” and alter human society for the better seems to be confined to certain enthusiastic “techbro” circles and the groups of people that exist on their periphery. This embrace of generative AI as a vehicle of change is similar to how services like Facebook presented themselves when they were first created. I am old enough to have been around when Facebook was founded and became popular. I remember when Google was seen as the “good guy” and how Chrome blew everything else out of the water.

Perspective: Generative AI, a Glorious Future

If you read OpenAI's blog, it sounds like they're building a technological utopia to share with humanity.

But of course, OpenAI is led by a charismatic CEO with a dubious and controversial history! Notably, he was fired by OpenAI's board of directors, offered a job at Microsoft, and then rehired by OpenAI, all in the span of a few days. The membership of the board was shaken up after that.

The way OpenAI, Anthropic, et al present their generative AI products to the world paints a picture of “disrupting the industry” and “democratizing” tech or art. They market themselves as equalizers that will help people solve every kind of problem, build social connections, get help with things, increase educational opportunities, and more!

Perspective: Generative AI, a Social Scourge

The opposite view of the glorious future above is that generative AI is useless, generates wrong information, and is built on climate-destroying amounts of energy and stolen intellectual property. People with this view have a strong reaction to anything in which AI was involved. From this base negative reaction, they often assert that the problems inherent to generative AI extend beyond the models themselves, and cause problems in society: making interactions shallow, perpetuating misinformation, and eroding trust in people, law and institutions.

The In-Between

I think reality is somewhere in-between. Large language models (LLMs) are a tool. And, whether we like it or not, they are not going to disappear. They HAVE created a paradigm shift. But it's not the paradigm shift promoted by companies like OpenAI, nor is it the shift decried by AI detractors. I think generative AI is an event that is similar (in very broad strokes) to when Wikipedia first came online. The current situation reminds me of sitting in high school classes listening to teachers say that Wikipedia is an untrustworthy source, because anyone can edit it to say anything.

And yet, today Wikipedia remains one of the most valuable repositories of human knowledge available. It's to the point that governments try to censor it, shut it down, or generally make its operations more difficult. It's not viewed as untrustworthy. But the “stigma” against it, if it could be called a stigma, still exists in academia. Rightly so. Wikipedia is valuable, but in serious research or education, it should only be used as a springboard to the actual sources of information. The criticism that anyone can edit Wikipedia isn't ENTIRELY unfounded (just mostly). By and large, Wikipedia has policies and a community that works towards a collective good, updating articles, trying to be neutral, reverting vandalism, etc. Like any project, it's not without problems. There have been issues with people using Wikipedia to advertise, hide information, push agendas, etc.

The Real Paradigm Shift of Generative AI

The paradigm shift from generative AI is similar to the beginnings of Wikipedia. It's presented as an authoritative tool, with demonstrable success, at least some of the time. Enough of the time that people are convinced they should use it.

What makes the paradigm shift of generative AI fundamentally different from Wikipedia is the sheer SCALE of it. Anyone can access it. Anyone can use it.

Generative AI models produce volumes and volumes of data quickly. They do it often sounding like they're confident in their knowledge, and present information as if it's correct. They respond in understandable language. Some generative AI models can pass the Turing Test. This doesn't mean that LLMs think or are sapient, but it is important for how people interact with them.

Because of the way LLMs work, and how they're presented to the world, the task of educating people on their benefits and limitations is much more difficult. The polarized discourse around generative AI also makes it hard to spread this information.

LLMs as Tools

Large language models are ultimately powerful statistical word association predictors. Given input (user query), they produce an answer that is statistically likely to make sense relative to the given input.

Text in, text out. They are based on complex pre-trained associations between words (or more accurately, tokens). Input is transformed into complex numerical vectors, run through the statistical model, and the numerical output is transformed back into readable text for the user.

This means:

  • LLMs do not think. They do not understand.
  • They are not a source of information.
  • They are not correct. They are not wrong.

But not being a source of information doesn't mean a language model cannot be used for information. The goal of the three bullet points above is to understand what a large language model is and how it works. Large language models are, ultimately, NOTHING more than mathematical text generation devices. Dissociating the WAY LLMs present their output from the process they use is very, very important for understanding what they are actually useful FOR. Because LLMs operate on text and produce text, they are good at understanding and manipulating text. They excel greatly at fuzzy searching, catching typos, grammatical mistakes, and more. They “understand” instructions given to them.

The usefulness of an LLM depends on its training data, and how many parameters it has. Smaller models are less likely to understand correctly, simply because they lack the parameter space.

The End Result

The biggest, most visible problem with LLMs is their tendency to “hallucinate” information that does not exist. It is a natural artifact of how they operate. If users do not train themselves to dissociate the tone of output from the usefulness of the output, hallucinations become an even bigger problem. People are trusting AI for everything. AI models generate volumes of confidently incorrect information that is slowly filling the internet.

The future with large language models in our society requires educating people what they're for and what they're good at, and how they work. They are kind of like Wikipedia, often useful as a springboard to authoritative information, or more in-depth reading. Users will have to train their minds to dissociate the tone of LLM responses from their capabilities. Often, one can find a nugget of truth in an otherwise hallucinatory LLM response.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-01-18T09:04:30Z

What is Home? Part II

Home is a place, a feeling. It's more than one place. It's where you live currently, but also where you come from. It's where your family is, or was. This is what I said in my blog post about this almost one year ago.

Two and a half years ago, in summer 2022, we moved to a new country. Two and a half years ago, we changed everything about our lives.

I am becoming more at peace with my new home. But it's not perfect. Nothing is. I spent much of the past 2.5 years fighting against this new place, that I now must call home. Coming here, staying here, was not by choice. It was a clouded decision, and I think it was ultimately the wrong decision. But it was still the decision that I agreed with and supported, and I have to live with the consequences of that decision, likely for the next decade or more.

For the past year, I turned inward from depression and being overwhelmed. Now, I am finally starting to come back out of that shell. I am coming to terms with my situation, and even learned to appreciate the country we live in, in a way. It's a nice country, a safe one.

But there is still much to be done. The hard work remains.

Making Peace

I am in the process of making peace with two things:

  • I will never truly consider the place I live now as home. It is a place I must endure.
  • I will endure this place, and even find beauty in it, for the sake of myself and my family.

This started about one year ago, at the end of 2023/beginning of 2024. I recognized that I needed to change my attitude towards where we now live. At the time, I simply couldn't do it. Even now, it's very difficult. This refusal, and the stress resulting from it, has almost destroyed my life on multiple occasions. But for the sake of my own sanity, and the sake of my family, I HAVE to get with the program.

The first breakthrough was when I decided that I would not and could not truly feel at peace where I live now. It was a way out, a way to focus the rage and betrayal that I felt in summer 2022. It's a way to give my feelings a name and make them into something coherent: “I did it. I tried to live here, and I decided it's not for me.” For many people, this would be the point where they returned from where they came. But I cannot do that: I am tied here by family. I am stuck.

Now, I am trying to reconcile my necessary present with that decision to survive, rather than thrive, in this place. There is not one thing I can point to that truly screams “progress in emotional processing!” But I do notice the little differences when I go back to the place I consider my true home. When I am there, I feel a little more detached, and a little bit more desire to return to where I currently live. it's probably the most tangible sign of progress that I've noticed, and it's also what inspired me to write this blog post.

Surviving vs Thriving

Ideally, a person would thrive in a new environment, not merely survive in it. But that's not happening for me. Not yet. Possibly not ever. I thrived in the place where I used to live, and I still thrive there when I return. When I'm there, in many ways it feels like I never left. I get to role-play living there for a week or so before returning to my life as it really is: a life of isolation (somewhat self-imposed) as a stranger in a strange land. I do not speak the language of the country where I live. I do not share the culture of the country where I live (and in fact find several parts of it quite hostile and odd).

I am recovering from culture shock, and still dealing with the aftershocks and tremors of the earthquake that uprooted our lives in mid-2022. I once read it took at least 6 months to feel at home in such a drastically new place, and for some people it might even take two years. For me, it's going to take longer.

Two years ago, this place was a prison that I was dragged into, kicking and screaming. A year ago, it was a prison where I could go to the beach sometimes. Today, everything feels a bit “less foreign.” It's hard to call it “familiar.” But I suppose that would be an easier way to phrase it: “everything feels a bit more familiar.” Today, I wouldn't describe my life as being in a prison. But nor would I classify it as living the dream.

Things aren't like they were where I used to live. There, I thrived! But I also failed. But I conveniently forget those problems most of the time. The human mind is impressive: it warps, distorts, suppresses, and changes. We focus on the good things of our past, and minimize the bad parts. I have romanticized my life in the country we previously lived.

I believe that EVERYTHING I feel and experience today ultimately stems from a breakdown I had 6 years ago, where some 25+ years of stress and trauma finally exploded and spilled out. Stress from my job at the time finally broke what coping mechanisms I had, and ground my psyche to dust.

I've been slowly rebuilding my sense of self and emotional state ever since. A growing family and the move added to this stress, and it felt like taking many steps backward, undoing all the progress I had made. Multiple times.

Progress is Not Linear

I've come to realize that progressing towards a healthier mental state is not a line. It's not a ladder one must climb, where “happiness” is at the top and “depression” is at the bottom. That is too simplistic of a model. It's more like a tree, with many branches. The mental breakdown was somebody chopping down the tree (and perhaps setting it on fire and then throwing it into a wood chipper). But in its place, a new sapling sprouts. A sapling that I have to nurture and regrow into a new Tree of Self.

  • With the new tree comes new branches.
  • Some branches grow faster than others, and they grow higher.
  • You begin your climb from the ground once more, and make your way up the branches.
  • But then you slip from a higher branch and fall to a lower one!

But instead of falling all the way back to the ground, you're still in the tree. You cautiously make your way back over to the branch you were on before you fell, and while you're not as high up in the tree as you were, you're still IN THE TREE.

The Tree of Self

To put things in more concrete terms, let's say one branch is Family. Another is Social Life. Yet another is Self-Worth. Another is Self-Identity. The list can go on, and is probably specific to each person and each situation.

For me, the branch of Family regrew very slowly in the beginning. My life was turned upside down by starting a family, even though I went into it knowing fully well what was going to happen. To quote a famous line:

You are NOT prepared.

Recently, my “Family branch” has started to grow rapidly. I am finding my place as a parent and member of a family. It feeds into my regrowing branch of Self-Identity, which was similarly crushed and ground into nothingness 6 years ago (and then again 2.5 years ago). The branch of Self-Identity seems to grow much more slowly, and perhaps has been sawed off a few times over the past year. Job changes, the move to a new country, moving between houses, and constantly having to re-“find myself” have made it difficult. It's a similar situation for my social life. THAT branch is the hardest to regrow.

Change in Self-Perception

What I have noticed, especially over 2024, is that my perception of self is changing. I am beginning the transition of seeing myself as a victim and prisoner to seeing myself as a survivor. Hopefully I will eventually leave the fog of irrationality and come to see myself as just a person who has made a series of interesting life decisions. On paper, my life looks well-lived: moved across the world, got a new citizenship, and now I'm doing it all again. I'm a citizen of the world! My children even more-so! A successful career (thus far) and family. On paper, everything looks almost perfect!

The worst part about being in this state of anxiety and depression is that you often KNOW it's all irrational and not (entirely) true. But you can't stop yourself from thinking it must be true. It goes in cycles of rationality and irrationality. But the depression and anxiety do come from somewhere. It's important to remember that not EVERYTHING is just in my head.

The journey back towards happiness is very long, and very difficult. But I'm slowly getting there. Hopefully, a year from now, my outlook is less bleak, or even actually positive!

Would I go back?

Would I leave the place I live now and return to where we lived before? Absolutely, without a doubt, 100%, yes. If the opportunity presented itself, in any shape or form that I could ethically justify, I would leave immediately. And some day, that opportunity WILL come. I will not retire nor die where I live now. That would be giving up. The fight is not dead; it is merely on hold.

Hopefully by the time comes to resume the “fight,” it won't be a fight. Hopefully, it will be a life decision that I can make peacefully: not as a reaction against what I've become, but rather because it's a place where I want to go.

The Final Goals

My goal for 2025 isn't to change my mindset. Directly attacking the problem head-on is tantamount to trying to run my head through a brick wall. I spent two years trying that. First by fighting against the situation itself, then by trying to force myself to change my opinion of the situation. It didn't work either time.

My goal is to be learn to be happy in the present, within the constraints that have been forced upon me. My goal is to synthesize a happy medium between my own opinion and the reality I must navigate. By doing this, I think that my mindset will slowly shift over time. I want to settle into a place where I can recognize the sacrifices I made, to be happy in the present, and to be hopeful for the future. I want to be engaged with life, not merely drifting through it.

Hopefully, it works this time.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-01-12T14:27:23+01:00

I have undertaken a journey to radically change, and in my opinion, simplify, my self-hosting setup. For the past 5+ years, I have been manually creating and maintaining nginx configs—one for each service.

But now I plan to gradually move everything to Coolify.

The Matrix server, which runs on the same VPS as most services, is deployed through its own Ansible playbook. This makes the current configuration very complicated: the playbook expects to own the webserver. Getting it to play nicely with other services is slightly challenging.

The VPS environment is quite old, and the Matrix Ansible playbook used to use nginx as a proxy. But they have since changed it to use Traefik. That is good, but all my configurations are still stuck on nginx! So right now, I have nginx fronting the Matrix server's traefik instance, along with all other services.

This means that nginx is the source of truth for everything like SSL certs, routing, service configuration, etc. It also means that I lose Coolify's more interesting features like automatic SSL certificate acquisition, automatically binding services to domains, etc.

Benefits of Coolify

Even though I have to solve the proxy problem, Coolify is still giving me benefits:

  • Centralization: all services will live in one place.
  • One-click deployments: no more git pull, push, and manual updates.
  • Automation

Centralization

My self-hosted services are strewn across several servers, both on VPSes and at home. I proxy the services running at my house through frp to the VPS, and expose them via separate nginx server blocks, sometimes with special configs for web sockets and the like. This is very annoying to manage by hand (though after 5 years, I've gotten it down to a science).

Services on the VPS are usually bash scripts. They either start a container, or run a program directly. Services at home are usually Docker Compose deployments that I have to manage directly, with a configuration separate from the docker-compose.yaml distributed from upstream. I maintain private forks of several services for both config and functionality changes.

In order to update a service, I have to do it completely manually. AND I have to remember where it's actually running. AND I have to make sure I don't break any configuration. This does not scale. I'm one person, and pretty much all of these are hobby projects. But my time is valuable, because I have a family to take care of, a job, and other hobbies. The less time I spend messing around with underlying stuff, the more time I have for the interesting parts: using my self-hosted services, building something new, etc.

One-Click Deployments

This is one of the biggest selling points of Coolify. There's a bunch of applications that you can install with one click. Notably, though, it doesn't allow you to override or map ports with these one-click installations. Given my proxy problem, I can't make much use of this feature yet. But even without it, I can still make use of the built-in docker compose deployments. Coolify allows a docker-compose.yaml file to be directly uploaded, and it then handles deployment of this to one or more servers.

Automation

Coolify aims to be an open source Vercel/Netlify replacement, and the integration with Git repositories is excellent. Coolify has direct integration with GitHub, but can pull from anything that it can access over SSH. It also supports webhook deployments from the common git forges, including self-hosted ones like Gitea/Forgejo. This allows me to completely replace the entire Drone pipeline, and I no longer need to rely on privileged directory mounts into the Drone runner.

New Deployment Process

Original deployment process, before Coolify: – A commit is pushed to the capsule's git repo. – Drone CI pipeline runs and builds the static site. – Drone CI pipeline copies the capsule files into a directory mount. – The directory mount is from the host VPS, where the server runs.

This has some obvious disadvantages: it's stuck on one server, it cannot scale, and it's also less secure. While a Gemini server will likely never need to scale, having to mount directories from the host VPS is not so great.

Here is the n ew deployment process, after Coolify: – A commit is pushed to the capsule's git repo. – A webhook call is made to Coolify. – Coolify uses the docker-compose file to build and deploy the site.

The Docker Compose build serves all content directly as a container, which allows the static site to be hosted anywhere (not just the VPS), AND it does not require the VPS directory to be mounted anywhere. This increases isolation and security of the server.

New docker-compose.yaml

The new Docker Compose file is radically small. The Gemini host is defined below, and the only volume mount is an existing mount that holds the TLS certificate for gemini://agnos.is.

docker-compose.yaml for capsule and kineto services: capsule: container_name: agnosis-capsule hostname: capsule build: context: . dockerfile: Dockerfile init: true volumes: - /path/to/.certificates:/app/.certificates environment: - GEMINI_HOST=${GEMINI_HOST} ports: - 1965:1965 http-proxy: container_name: agnosis-http-proxy build: context: . dockerfile: Dockerfile.kineto args: CSS_FILE: /files/agnosis.css environment: - GEMINI_HOST=${GEMINI_HOST} ports: - 9080:8080

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2025-01-02T22:09:05+01:00

A small update on the status of the filters and tools for Open WebUI. The 0.5 version of Open WebUI introduced major changes in the codebase, which has affected some of the extensions I have made:

  • Checkpoint Summarization Filter: will not load.
  • Thinking filters: may or may not work; depends on the inlet request parameter.
  • OSM tool: works.
  • Gemini tool: works.

I will update the broken filters soon, although I am considering redoing the checkpoint summarization filter from scratch, AGAIN. It has proven to be a decent baseline for how to handle stories, but it needs further work, especially around branching and regeneration of responses.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-12-13T22:40:53+01:00

As of this post, the capsule is now serving all content natively via the Gemini protocol. There is no longer a separate HTML copy of the site.

Today, I discovered Kineto, a Gemini –> Web proxy.

Kineto is very simple. You give it a stylesheet and a Gemini domain, and it proxies the entire capsule. In fact, it's so simple that it's composed of one source code file. I kept the CSS generated by gmi-web, so the HTTP version of the capsule looks the same. But instead of receiving the HTML content from static HTML files hosted on my web server, you are receiving HTML dynamically generated from Gemtext on the Gemini protocol!

While this fits in with the ethos of my site being Gemini-first, it has also allowed me to drastically simplify how the site is generated. I was able to nuke the entirety of the HTML build process from the Justfile, which has removed probably around 100 lines of hacky bash scripting.

Additionally, I can store the CSS in the site's git repository now, and tweak it as I feel like. The capsule serves the CSS, and Kineto proxies it too. This will give me many more opportunities to change how the site looks in web browsers, without having to hack gmi-web.

License: CC-BY-SA-4.0.

Written by: @[email protected]

Published: 2024-12-06T09:35:36+01:00

I have been working on reworking Gempost.

Gempost is a static site generator that was created by JustLark.

I forked it quite a long time ago to modify it for my needs, the biggest change of which was adding pages support to the application, instead of just handling Gemlogs. I have now made a pretty major update to this pages functionality by turning pages into fully templatable gemtext Tera layout templates, similar to how Jekyll handles content.

You can find it here. (pagetemplatedir branch)

How does it work?

  • You must specify a page_template_dir directory in config.
  • This directory can have any number of Tera templates.
  • There must at least be a base.tera template file.

New Features

Layout Templates

The base.tera template is a common template that all pages use as a layout, unless overridden by the new layout option in the sidecar YAML file. A layout Tera template has the following available to it:

  • {{ content }} variable. This is the content of the page itself.
  • {{ values }} variable, from the page's sidecar YAML file.
  • {{ entry }} variable, from the actual page entry itself.
  • {{ breadcrumb }} variable, from the page navigation hierarchy.

Page Templates

All pages (NOT posts! yet.) are themselves templatable, similar to how Jekyll handles HTML or Markdown content. They are handled as full Tera templates, which means all Tera features will work with them, including extends and includes.

The following variables are available to pages:

  • {{ values }} variable, from the page's sidecar YAML file.
  • {{ entry }} variable, from the actual page entry itself.
  • {{ breadcrumb }} variable, from the page navigation hierarchy.

There is a new layout option available in the sidecar YAML for pages. It is the layout template to use. By default, if it's not specified, this will be “base”, which means it will read the base.tera file from the pages template directory specified in the gempost config file.

Better Error Reporting

I have also updated the error reporting during templating for pages. The application will now output exactly why a templating operation failed, rather than just the top-level (and usually unhelpful) error.

Where to go from here

It seems like gempost is pretty much abandoned, especially because JustLark's Gemini capsule is now offline. I am thinking about taking Gempost in a new direction, and unifying the features of pages and posts together. This will simplify my own site configuration, and I think make the tool more useful to people who want a more generalized static site generation solution for Gemini capsules.

Things I'm thinking about:

  • Generating dynamic data (e.g. link menus) at site compile time.
  • Global site data, not just values per page.
  • Adding all the pages features to the gemlog post generation.

License: CC-BY-SA-4.0.

Written by: @[email protected]