Wave

Compose 5000 lines deep, or how to Containerize responsibly

Mia Rose Winter

If you are like me, and you have just learned how docker and docker compose worked, you will probably head out to rebuild your own little server, or start one anew, watch some tutorials, look for some tools, and end up with a little compose file to start your infrastructure.
It probably has a reverse proxy like nginx, traefik or Caddy, a little static website and maybe something for fun, a little self made project, a node app, a lil' blazor app, maybe just some open source link shortener you found (obligatory Just Short It! mention). A total of a hundred lines, not bad, manageable.

But it doesn't stay like that, does it?

Rise of the stacks

Now, you may get interested in some more advanced tech. Like, let's say, a blogging engine (like Wave), but that doesn't just take a container for a website, it also comes with a postgres database, a redis cache, maybe even more (at point of writing, Wave is still in alpha), so there goes another block in your compose, another 80 lines or so, now we got 200, not great, still okay I guess?

But now your thinking, you need some utilities to have a good look at everything, maybe add a dashboard, uptimekuma, maybe grafana? Three more containers can't hurt can they? 300 lines, should be fine, right?

But then you are me, create GeeksList, have a couple websites, a couple tools like JSI, FreshRSS, MastoGraph, your own docker repository with a web frontend to browse it, two matrix instances, a fedi instance, dpaste why not, a Minecraft Server, sure. And now we got to the 1000+ line docker compose file, and you realize you got a problem.

Sure it works, it's fine, but doesn't it feel icky? Surely there is a better way…

External Networks, Include and Extends

There sure is buddy.

For once, there is extend (docs.docker.com - extends). This allows you to centralize certain configuration, like when you got a couple static websites, you can put in your nginx or something. Next, there is include (docs.docker.com - include), which allows you to split up your compose into multiple files, and have a root file that combines them all. Personally, I've chosen a secret third option, and that is not having them work together at all. You see, when I separate, I want a clear separation, I have a folder /docker with folders for all my app stacks, completely isolated from each other, so if I want to move one, I just move that folder, and here I want to also have my compose, independent from everything else.
Docker does allow this, very easily even. The trick is, to have one central point of communication with the outside world, your reverse proxy. So I created a central container, in my case a Caddy server, that I hooked up to an external network I created previously, I called it Internet, easily created with docker add network Internet, if I recall correctly. Then in the compose, you just add the proxy to that network, and declare it as external like so:

networks:
  Internet:
    external: true

Now we have a network on our server, that we can include in any other compose or container whenever we want to be reachable by the outside world.
Next I want to set up a stack, I go into one of my folders, like /docker/Wave, and I create my compose (in this case, just copy it from the github repository and fill in the blanks). At the top level, I add name: wave, at the bottom, the external Internet network, and on the web container, I add that network.
Now when I run docker compose up -d in that network, it will create the container wave-web-1, wave-database-1, wave-redis-1. Nice names, easy to recall and predict, and wave-web-1 can communicate with my proxy, even tho they are in two completely unrelated compose projects, so now I can just add a little reverse_proxy instruction to my Caddyfile and everything works nicely. And this is basically what I have to do with all my projects, set up their individual compose file, update my Caddyfile, done. Neat right?

Now I just have to actually do that with anything other than Wave… (I get to it I swear)

About the Author

Mia Rose Winter

Software Developer / Project Manager. Full-time cat Woman and bisexual menace. Really not liking tech these days, I have more fun writing stories and books. Developer of GeeksList, Just Short It and Wave.

This might also interest you

A Mystery Involving Hardware Security Modules and Value Tokens

Forbidden Tempura 10/7/2025

Context Historical context In July, 2021, the phenomenon known as the “Gigaleak” continued. The Gigaleak was a drip-feed of part of the ill-gotten data from the 2018 Nintendo data breach. On July 20, 2021, the iqcvs.tar.xz file was uploaded to the now-defunct file sharing website anonfiles.com and thereby made available to the public by The Hacker Known as 4chan. This file contains a dump of CVS repositories. The repository sw contains the BroadOn network infrastructure around the middle of the year 2006. This is shortly before the Nintendo Wii launched. The network infrastructure was initially launched alongside the iQue Player, a variant of the Nintendo 64 featuring downloadable games and some anti-piracy measures of questionable quality (non-HTTPS link) intended for the Chinese market, which was and still is notorious for being particularly prone to piracy. It was developed by a company then called BroadOn Communications Corp., a California corporation. The iQue Player u

ITInfodump

A Brief Look at the 3DS Cartridge Protocol

Forbidden Tempura 6/2/2024

About a week ago, there has been a little addition to the 3dbrew wiki page about 3DS cartridges (carts) that outlines the technical details of how the 3DS cartridge controller and a 3DS cartridge talk to each other. I would like to take this opportunity to also include the 3DS itself in the conversation to illuminate which part of which device performs which step. I will then proceed to outline where I think the corresponding design decisions originate. Finally, I will conclude with some concrete ideas for improvement. But first, we need to talk about parallel universes This protocol makes no sense unless you have a basic overview of the 3DS AES engine. The 3DS AES engine can load 128-bit AES keys in two ways: Using key-derivation from a keyX and keyY (officially called KeyId and KeySeed, respectively). Directly specifying a full AES key. The key derivation from a keyX and keyY works as follows: AES key = (((keyX ROL 2) XOR keyY) + C1) ROR 41, where ROL is left rotation on a 128-bit

ITGamesInfodump

Reconstructing the 3DS Bootstrapping Process at the Factory

Forbidden Tempura 5/13/2024

Motivation The Nintendo 3DS was a fairly popular console. In spite of that, surprisingly little is known about how it is put together at the factory. Working with information that was uncovered during the so-called Gigaleak, I will try to recover as much information as I can about the manufacturing process up and until the point the 3DS is able to complete a normal boot sequence. One-Time Programmable (OTP) region Every 3DS ships with 0x100 of one-time programmable persistent memory at 0x10012000-0x10012100, containing console-unique keys and information. This obviously has to occur before any normal firmware runs on the system because significant amounts of all data written would fail to account for console-unique information and thus the encrypted values would be all encrypted for the wrong keys. An interesting observations: ctr.7z (SHA-256: 8b05072361254437277576d53c08b95e5f076c6b33a2871fad74eaa5561d1d38) ctr/sources/bootrom/CTR/private/build/bootrom/ctr_bootrom/ARM9/main.c has a pr

ITGamesInfodump
Powered by Wave