Skip to main content

Ralsina.Me — Roberto Alsina's website

30-minute project: caddy-static

I host a num­ber of stat­ic web­sites on my per­son­al serv­er. Over the years, they have been served by a va­ri­ety of web server­s, but I re­cent­ly de­cid­ed I want­ed to make it easy.

So, I looked for a mod­ern and min­i­mal­is­tic web serv­er that sup­port­ed a fea­ture of the ven­er­a­ble thttpd

That fea­ture is au­to­mat­ic vir­tu­al hosts. The main idea is that you have a fold­er and in there a bunch of sub­fold­er­s, each one is a site. And the name of the fold­er is the name of the site.

So, if I have /srv/ralsina.me then when a user asks for http://ralsina.me they get that. And if I have /srv/whatever.com and the user asks for whatever.com they get that.

Al­so, if a site is reach­able with more than one name, then just add sym­links and it should just work.

I found a way to do it us­ing Ng­inX but that's far from min­i­mal­is­tic.

So, I looked around and found that Cad­dy was pret­ty close ex­cept it did­n't do the au­to­mat­ic stuff.

So, I wrote the miss­ing bit, threw ev­ery­thing in a dock­er con­tain­er and now I have a 30-minute project that serves all my stat­ic sites.

Here's the dock­er com­pose I am us­ing:

version: "3.8"
services:
  web:
    logging:
      driver: journald
      options:
        tag: web
    container_name: web
    stdin_open: true
    tty: true
    ports:
      - 8080:8888
    volumes:
      - /data/websites/:/srv/
    image: ghcr.io/ralsina/caddy-static-arm64:latest
    restart: always
networks: {}

And here's the pro­jec­t: cad­dy-stat­ic

It probably needs some tweaking for anyone else specially in the Caddyserver config and maybe in the template it uses to generate sites which is hardcoded.

If any­one ac­tu­al­ly us­es this I can make those things con­fig­urable.

The Beauty and Horror of Crystal Shards

I have been us­ing a lot of Crys­tal for per­son­al projects for about a year. Think of it like "na­tive Ru­by with type in­fer­ence" or some­thing like that.

But this post is not about the lan­guage it­self, it's about one part of its ecosys­tem: the shard­s.

The Nice

Shards are like Ru­by gem­s, or like what­ev­er go calls them nowa­days, or rust crates, just "li­braries" that are writ­ten most­ly in crys­tal.

The thing is ... they are awe­some!

Suppose you want to use markdown in your app. You go to shards.info which crawls GitHub and finds things written in Crystal. You search for markdown and you find a few that look good. Suppose you want to use my cr-discount shard.

You just add the shard to your shard.yml and use it, like this:

dependencies:
  cr-discount:
    github: ralsina/cr-discount

Then in your code:

require "cr-discount"

markdown = "This *is* **markdown**"
html = Discount.compile(markdown)

And that's it, you just in­te­grat­ed it in­to your build, your code is us­ing it, and that's all there is to it.

But not on­ly that, sup­pose you are us­ing a shard like docr but you find a tiny bug or two. You fork it, fix the bugs and cre­ate a PR. If the au­thor is ac­tive, they will merge it, and you can go back to us­ing the shard, but even if they aren't ... you can just use your fork in the mean­time.

Just use ralsina/docr instead of marghidanu/docr in your shard.yml and you are using my fix.

And there's more! Sup­pose you find some code in your projects that you keep re­peat­ing. For ex­am­ple, I al­ways use the same log­ging set­up in CLI app­s:

  • Col­or­ful if it makes sense
  • Con­fig­urable ver­bosi­ty
  • Er­rors and worse in stderr
  • In­fo and bet­ter in std­out

So, why copy that ev­ery­where? Just make it a tiny shard.

There is no overhead in your code, you don't have to ask users to install anything, you just add it to your shard.yml and it's there for everyone that cares.

The Not So Nice

Of course noth­ing is free of cost.

  • Be­cause it's easy to cre­ate shard­s, it's easy to aban­don shard­s.
  • Be­cause it's easy to fork shard­s, it's easy to at­om­ize the ecosys­tem.
  • Be­cause it's easy to find shards and it's de­cen­tral­ized, it's triv­ial to poi­son the sup­ply chain (although TBH it seems to be easy enough in any lan­guage).

So, you have to be care­ful. You have to check if the shard is main­tained, if it's the best one for the job, if you fork it you need to com­mit to keep­ing your fork work­ing, you al­ways need to push the PR even if the au­thor does­n't pick it up be­cause it's there for oth­er user­s.

So, con­clu­sion­s... they are what they are. For me they are the most prac­ti­cal thing ev­er and I of­ten wish Python had some­thing like them, but they are al­so quite ... scary? And see­ing the aban­doned shards makes me sad for a lan­guage that should be much more pop­u­lar than it is.

Schizo Desktop IV: Audio

I have an of­­fice. It's like a home of­­fice but it's in an­oth­er place. It's just mine, so I get the peace and qui­et of a home of­­fice but al­­so get to go out­­­side to get there. It's a good set­up.

BUT I have two com­put­ers there. Well, ac­­tu­al­­ly I have like 10, but I in­­ter­act with two. One is my per­­son­al desk­­top com­put­er, the oth­­er is my work lap­­top. and I want to use the same pe­­riph­er­als in the same way with both of them. That's why I have the world's most com­­pli­­cat­ed schizo desk­­top set­up.

This se­ries of posts will doc­u­­ment it, the why and how of it, and the var­i­ous things I've learned along the way, along with mak­ing you want to buy weird chi­­nese gad­get­s.

Today: Audio

As in the rest of this se­ries, some­thing that usu­al­ly is very sim­ple be­comes a bit com­pli­cat­ed be­cause I want to use the same pe­riph­er­als with two com­put­er­s.

In the case of au­dio it's even worse be­cause I want to use dif­fer­ent de­vices de­pend­ing on con­tex­t.

The Requirements

  • I want to list­ed to both com­put­ers with­out head­set­s, be­cause I don't like wear­ing head­sets for long.
  • I want to be able to lis­ten us­ing head­sets if I want to, to take ad­van­tage of noise can­celling and to be qui­eter.
  • I have a good mi­cro­phone, I want to use. I don't want to use the bad ones, like my we­b­cam's, or my note­book's.

The Hardware

  • Speak­er: a lar­gish speak­er with a 3.5mm jack, hang­ing from the bot­tom of my desk, in­vis­i­ble.
  • Mi­cro­phone: a XLR con­denser mi­cro­phone (means it needs 48v phan­tom pow­er!)
  • Head­set: Blue­dio Hur­ri­cane H2 (with ca­ble!)

The head­set and mi­cro­phone switch com­put­ers as de­scribed in a pre­vi­ous post BUT how does a XLR mi­cro­phone con­nect to a com­put­er?

You need an au­dio in­ter­face. I have a su­per cheap chi­nese one:

The v8 live sound card

This plugs to a com­put­er via USB and works as a sound card, with in­put and out­put.

BUT it's not just a sound card, it's a mix­er. It has con­nec­tors for:

  • 2 Con­denser mi­cro­phones (yes, with phan­tom pow­er)
  • 2 "Ac­com­pa­ny" in­put­s, which are stereo line in­puts
  • Blue­tooth in­put
  • Mon­i­tor: this is a stereo out­put that is a mix of all in­put­s, so you can lis­ten to ev­ery­thing that's go­ing on.

It has vol­ume con­trols for "ac­com­pa­ny" / "mic" / "mon­i­tor" and a cou­ple nice LED feed­back light­s.

It al­so has a bunch of ef­fect­s, like re­ver­b, echo, sil­ly sound­s, etc. which I don't use.

That au­dio in­ter­face is the hub of my au­dio set­up. Usu­al­ly it's con­nect­ed to my work com­put­er with the mi­cro­phone, but I can switch it over to my per­son­al PC.

My per­son­al PC is con­nect­ed to it via BT, and the mon­i­tor out­put is con­nect­ed to the speak­er.

The head­set is a sep­a­rate usb de­vice for per­son­al pref­er­ence.

The Software

Not much need to do any­thing spe­cial with two ex­cep­tion­s:

  1. Dis­able all the au­dio in­ter­faces I don't want to ev­er use.
    • HD­­MI au­­dio out­­puts
    • We­b­­cam's mi­cro­­phone
    • Head­­set's mi­cro­­phone
  2. Use rofi-­sound-pick­er to choose where the sound goes. I use it most­ly to switch from speak­er to head­phones.

Rofi Sound Picker

The Routing

In work mod­e:

  • Both PCs sound via the au­dio in­ter­face and the speak­er con­nect­ed to its mon­i­tor out­put:
    • Per­­son­al PC via BT
    • Work PC via USB
  • Mi­cro­phone is con­nect­ed to the au­dio in­ter­face and is used by the work PC (and se­lect­ed in team­s/­zoom/etc as in­put)
  • Head­set is con­nect­ed to the work PC and I can change to it us­ing the rofi-­sound-pick­er

In Per­son­al mod­e:

The same as work mod­e, un­less I want to record some­thing, in which case I switch all the au­dio to the per­son­al PC and just pick and choose.

Conclusion

This is worth it even if all I got was both PCs com­ing out of the speak­er. The rest is good and a bonus.

Schizo Desktop III: Monitors

I have an of­fice. It's like a home of­fice but it's in an­oth­er place. It's just mine, so I get the peace and qui­et of a home of­fice but al­so get to go out­side to get there. It's a good set­up.

BUT I have two com­put­ers there. Well, ac­tu­al­ly I have like 10, but I in­ter­act with two. One is my per­son­al desk­top com­put­er, the oth­er is my work lap­top. and I want to use the same pe­riph­er­als in the same way with both of them. That's why I have the world's most com­pli­cat­ed schizo desk­top set­up.

This se­ries of posts will doc­u­ment it, the why and how of it, and the var­i­ous things I've learned along the way, along with mak­ing you want to buy weird chi­nese gad­get­s.

Today: Monitors

I have at least three mon­i­tors for my two com­put­er­s. It can get more com­pli­cat­ed than that, but let's just lim­it this to the "ba­sic­s".

Be­cause one of the com­put­ers (my work one) is a note­book, it has its own mon­i­tor. Then I have two reg­u­lar mon­i­tors, both 1080p, one of them land­scape and the oth­er por­trait.

This is how that look­s.

The three monitors described above

This would nor­mal­ly be just a mat­ter of plug­ging them in the right com­put­er, but ... in my case there is no right com­put­er!

When I am work­ing, I want the mid­dle mon­i­tor to be con­nect­ed to my work lap­top, and when I am not, I want it con­nect­ed to my desk­top.

The right­most mon­i­tor I al­ways want for my desk­top (usu­al­ly play­ing mu­sic or videos while I work) and of course the lap­top keeps con­trol of its own screen.

Ad­di­tion­al­ly I want to be able to spo­rad­i­cal­ly con­nect ran­dom com­put­ers (like rasp­ber­ry pis) and have them show up on a mon­i­tor.

Now it's not so ob­vi­ous, right?

Enter The HDMI Matrix

This is a 4x2 HD­MI ma­trix. It has 4 in­puts and 2 out­put­s. That means it can get 4 dif­fer­ent video sig­nals and will route them to 2 dif­fer­ent mon­i­tors in a com­plete­ly ar­bi­trary man­ner.

  • Want in­put 1 in both out­put­s? Sure.
  • Want in­put 1 in mon­i­tor 1 and in­put 2 in mon­i­tor 2? Sure.
  • Want it the oth­er way around? Sure.

It's to­tal­ly over­pow­ered for what I need, which could be done with a sim­pler 4x1 switch, but hey, it's nice.

So, I have 4 in­puts con­nect­ed:

  1. My desk­top com­put­er
  2. My desk­top com­put­er
  3. My work lap­top
  4. A ca­ble that I can reach un­der the desk­top

The out­puts are con­nect­ed to the mid­dle and right­most mon­i­tors in the desk re­spec­tive­ly.

When I work, the con­fig­u­ra­tion is in­put 3 in the mid­dle mon­i­tor, in­put 1 in the right­most mon­i­tor.

When I am not work­ing, it's in­put 2 in the mid­dle mon­i­tor, in­put 1 in the right­most mon­i­tor.

When I have a rasp­ber­ry I want to look at for a mo­men­t, that's in­put 4 to the mid­dle mon­i­tor.

Of course there is an­oth­er prob­lem:

The por­trait mon­i­tor does­n't know it's on its side. So ev­ery­thing is ro­tat­ed 90 de­grees when shown there.

Enter AutoRandr

Au­toRan­dr is one of those tools once you have it and use it you can't live with­out it.

It saves the cur­rent mon­i­tor con­fig­u­ra­tion and can re­store it when­ev­er it sees the same mon­i­tors plugged in­to the same out­put­s.

So, just make it look nicein "work mode", and configure all the monitor rotations and so on, then autorandr --save work.

Then, when you are not working, make it look nice again, and autorandr --save home.

Have to do that in both com­put­er­s, of course.

From then on, when­ev­er the switch changes things around, au­toran­dr au­to­mat­i­cal­ly re­con­fig­ures the mon­i­tors the right way on both com­put­er­s.

The on­ly prob­lem is that to switch from home con­fig to work I would have to do things like "click on the B but­ton of the ma­trix thing un­til is says "3", then click on the A but­ton un­til it says "1" and it's bor­ing.

Enter the Remote

As you can see in the pre­vi­ous pic­ture, the ma­trix has a re­mote. It's a sim­ple re­mote, with 8 but­ton­s, one for each in­put/out­put com­bi­na­tion.

I could just use the re­mote to switch be­tween work and home con­fig­u­ra­tions, but that's bor­ing too.

So, I use soft­ware to drive an in­frared emit­ter that switch­es things around when I click a but­ton in the macro key­board or flip a switch on a web­page.

But that's for an­oth­er post.

Schizo Desktop II: Keyboard and Mouse

I have an of­fice. It's like a home of­fice but it's in an­oth­er place. It's just mine, so I get the peace and qui­et of a home of­fice but al­so get to go out­side to get there. It's a good set­up.

BUT I have two com­put­ers there. Well, ac­tu­al­ly I have like 10, but I in­ter­act with two. One is my per­son­al desk­top com­put­er, the oth­er is my work lap­top. and I want to use the same pe­riph­er­als in the same way with both of them. That's why I have the world's most com­pli­cat­ed schizo desk­top set­up.

This se­ries of posts will doc­u­ment it, the why and how of it, and the var­i­ous things I've learned along the way, along with mak­ing you want to buy weird chi­nese gad­get­s.

Today: Keyboard and Mouse

I have 2 key­boards and no mouse. In­stead of a mouse I have a track­ball but for all prac­ti­cal pur­pos­es ... 1 mouse.

A keyboard, a mouse and a tiny keyboard

How do I use them with two computers?

The an­swer is Bar­ri­er which runs a serv­er in my per­son­al ma­chine and a client in my work lap­top.

With it run­ning, I can just slide my mouse to the edge of the screen of one com­put­er and it will ap­pear in the screen of the oth­er com­put­er. It's like mag­ic.

I can even copy­/­paste be­tween them trans­par­ent­ly, I just can't move win­dows across the fron­tier for ob­vi­ous rea­son­s.

How do I use them with random computers?

My key­board has 3 mod­es:

  • Wired (al­ways con­nect­ed to my per­son­al com­put­er)
  • Blue­tooth for up to 3 de­vices (not con­nect­ed to any­thing)
  • 2.4Ghz don­gle (not con­nect­ed to any­thing)

So, if I have a ran­dom com­put­er (say, a rasp­ber­ry pi I need to de­bug) I can just switch the key­board to use the 2.4Ghz don­gle, plug it in­to the com­put­er and use it that way.

What about the tiny keyboard?

That's macros. The wheel is vol­ume, and al­so con­trols my lights and oth­er things. The but­tons do things like con­trol my air con­di­tion­er.

It's a su­per cheap chi­nese one, and they have re­cent­ly be­come con­fig­urable in Lin­ux, which is al­ways nice.

Why a trackball?

Why not a track­bal­l?

Any special keyboard configuration?

Oh yes. because it's a 65% keyboard I have to choose between having an escape key or a ~ key.

So I chose both, and mapped escape to the caps lock key.

So when I start my ses­sion I run this:

# Map caps lock and esc to proper keys
xkeysnail --watch --devices "ROYUAN GamaKay 68" .config/xkeysnail/config.py &
sleep 1

setxkbmap -model pc104 -layout us -variant altgr-intl -option

The xkeysnail tool configures this keyboard (and only this keyboard) using this file:

from xkeysnail.transform import *

# define timeout for multipurpose_modmap
define_timeout(1)


# [Global modemap] Change modifier keys as in xmodmap
define_modmap({
    Key.CAPSLOCK: Key.ESC,
    Key.ESC: Key.GRAVE
})

So I get escape in the caps lock key, and ~ in the esc key.

Then setxkbmap configures a us international keyboard layout with the altgr-intl variant, which is the one I like.

Conclusions

This one is not very weird, oth­er than the re­liance in a sin­gle key­board and a track­bal­l. If you use mul­ti­ple com­put­ers in your set­up I rec­om­mend Bar­ri­er, it's a great tool.


Contents © 2000-2024 Roberto Alsina