feat: entire blog now looks good :thumbs_up:
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
This commit is contained in:
parent
014a99d7e2
commit
f76196b017
18 changed files with 2584 additions and 3 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build
|
||||
node_modules
|
||||
_site
|
17
.woodpecker.yaml
Normal file
17
.woodpecker.yaml
Normal file
|
@ -0,0 +1,17 @@
|
|||
when:
|
||||
branch: ["main"]
|
||||
event: ["push", "manual"]
|
||||
steps:
|
||||
- name: build
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
repo: git.iwakura.rip/iwakura/blog
|
||||
platforms: linux/amd64
|
||||
dockerfile: Dockerfile
|
||||
tags:
|
||||
["${CI_COMMIT_BRANCH}-latest", "${CI_COMMIT_BRANCH}-${CI_COMMIT_SHA}"]
|
||||
username: hex
|
||||
registry:
|
||||
git.iwakura.rip
|
||||
password:
|
||||
from_secret: gitpat
|
25
Dockerfile
Normal file
25
Dockerfile
Normal file
|
@ -0,0 +1,25 @@
|
|||
FROM docker.io/node:23-alpine3.20 as compiled
|
||||
|
||||
WORKDIR /tmp
|
||||
USER root
|
||||
|
||||
# Copy the source code into the temp folder.
|
||||
COPY . /tmp
|
||||
|
||||
# Installing the dependencies required for compiling.
|
||||
RUN npm install
|
||||
RUN npm install @11ty/eleventy -g
|
||||
|
||||
RUN npm run compile
|
||||
|
||||
FROM docker.io/jitesoft/lighttpd as main
|
||||
|
||||
ARG UID=82
|
||||
ARG GID=82
|
||||
|
||||
RUN mkdir -p /html /logs
|
||||
|
||||
COPY --chown=$UID:$GID --from=compiled /tmp/build/ /html
|
||||
RUN chown -R $UID:$GID /html
|
||||
RUN chown -R $UID:$GID /logs
|
||||
COPY --chown=$UID:$GID --from=compiled /tmp/config/lighttpd.conf /etc/lighttpd/lighttpd.conf
|
|
@ -1,3 +1,4 @@
|
|||
# blog
|
||||
|
||||
iwakura.rip blog
|
||||
# iwakura blog
|
||||
|
||||
This repository contains the blog we run under the iwakura.rip domain. It is made using [11ty](https://11ty.dev).
|
||||
The main branch contains the production version of our blog running [here](https://blog.iwakura.rip). The review branch contains blog posts that need to be reviewed.
|
||||
|
|
28
config/lighttpd.conf
Normal file
28
config/lighttpd.conf
Normal file
|
@ -0,0 +1,28 @@
|
|||
server.modules += ("mod_accesslog", "mod_rewrite", "mod_dirlisting", "mod_staticfile")
|
||||
|
||||
# General daemon settings
|
||||
server.username = "www-data"
|
||||
server.groupname = "www-data"
|
||||
server.port = 80
|
||||
server.max-fds = 600
|
||||
server.follow-symlink = "enable"
|
||||
|
||||
# Security
|
||||
static-file.exclude-extensions = (".php", ".pl", ".cgi", ".fcgi", "~")
|
||||
url.access-deny = ("~", ".inc")
|
||||
|
||||
# Content
|
||||
server.document-root = "/html"
|
||||
server.indexfiles = ("index.html", "index.htm")
|
||||
server.error-handler = "/error.html"
|
||||
|
||||
mimetype.assign = ( ".png" => "image/png",
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".html" => "text/html",
|
||||
".txt" => "text/plain;charset=utf-8",
|
||||
".css" => "text/css" )
|
||||
|
||||
server.errorlog = "/logs/error.log"
|
||||
accesslog.filename = "/logs/access.log"
|
||||
server.breakagelog = "/logs/breakage.log"
|
18
eleventy.config.js
Normal file
18
eleventy.config.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import markdownIt from "markdown-it";
|
||||
import mkgh from "markdown-it-github-alerts";
|
||||
|
||||
export default function(eleventyConfig) {
|
||||
const options = {
|
||||
html: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
};
|
||||
|
||||
const md = markdownIt(options);
|
||||
md.use(mkgh);
|
||||
eleventyConfig.setLibrary("md", md);
|
||||
|
||||
eleventyConfig.addPassthroughCopy("src/fonts/typewriter.ttf");
|
||||
eleventyConfig.addPassthroughCopy("src/post.css");
|
||||
};
|
||||
|
1953
package-lock.json
generated
Normal file
1953
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
22
package.json
Normal file
22
package.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "iwakura-blog",
|
||||
"version": "1.0.0",
|
||||
"description": "iwakura.rip blog",
|
||||
"scripts": {
|
||||
"t:compile": "npx @tailwindcss/cli -i ./src/global.css -o ./build/global.css",
|
||||
"t:watch": "npx @tailwindcss/cli -i ./src/global.css -o ./build/global.css --watch",
|
||||
"e:compile": "eleventy --input=src --output=build",
|
||||
"compile": "npm run e:compile && npm run t:compile",
|
||||
"e:watch": "eleventy --input=src --output=build --serve"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "iwakura.rip",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@tailwindcss/cli": "^4.0.6",
|
||||
"@tailwindcss/vite": "^4.0.6",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-github-alerts": "^0.3.0",
|
||||
"tailwindcss": "^4.0.6"
|
||||
}
|
||||
}
|
15
src/_includes/base.njk
Normal file
15
src/_includes/base.njk
Normal file
|
@ -0,0 +1,15 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="/global.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ title }}</title>
|
||||
</head>
|
||||
<body class="scheme-dark bg-gray-900 px-[25%] pt-10">
|
||||
<h3 id="title" class="text-3xl font-bold leading-none text-gray-200 font-[typewriter]">iwakura blog</h3>
|
||||
<a class="link pl-10 text-gray-600 text-xs" href="https://iwakura.rip">by the iwakura computer club</a>
|
||||
<hr class="m-3">
|
||||
<div class="">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
5
src/_includes/post.njk
Normal file
5
src/_includes/post.njk
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
layout: base.njk
|
||||
---
|
||||
<link rel="stylesheet" href="/post.css">
|
||||
{{ content | safe }}
|
BIN
src/fonts/typewriter.ttf
Normal file
BIN
src/fonts/typewriter.ttf
Normal file
Binary file not shown.
45
src/global.css
Normal file
45
src/global.css
Normal file
|
@ -0,0 +1,45 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
@font-face {
|
||||
font-family: 'typewriter';
|
||||
src: url('/fonts/typewriter.ttf') format('truetype');
|
||||
}
|
||||
|
||||
body {
|
||||
/* background-color: #0E0E0E;*/
|
||||
color: white;
|
||||
}
|
||||
a {
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
a:hover:not(.postbtn) {
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
|
||||
hr {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.blogbox {
|
||||
border: 1px solid var(--color-gray-500);
|
||||
background-color: var(--color-gray-800);
|
||||
border-radius: 5px;
|
||||
padding: 0.6vw;
|
||||
transition: 0.2s;
|
||||
line-height: 1.3vw;
|
||||
}
|
||||
|
||||
.blogbox:hover {
|
||||
border-color: var(--color-gray-300);
|
||||
scale: 1.05;
|
||||
}
|
||||
|
||||
/*
|
||||
#header h3, #links a {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#page {
|
||||
padding: 10px 15%;
|
||||
}*/
|
23
src/index.html
Normal file
23
src/index.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
layout: base.njk
|
||||
title: Blog Posts
|
||||
---
|
||||
|
||||
<div id="content">
|
||||
<h1 class="text-3xl font-bold">Posts</h1>
|
||||
<ul class="px-1 py-2">
|
||||
{%- for post in collections.post -%}
|
||||
<li class="py-2">
|
||||
<a href="{{ post.url | url }}" class="postbtn">
|
||||
<div class="blogbox">
|
||||
<h2 class="text-gray-200">{{ post.data.title }}</h2>
|
||||
<p class="text-gray-500 text-xs">{{ post.date }}</p>
|
||||
<p id="preview" class="text-gray-400">{{ post.data.desc }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
<p>Want to help out reviewing (upcoming) blog posts? See the "review" branch at the <a
|
||||
href="https://git.iwakura.rip/iwakura/blog">git repository</a> for this blog!</p>
|
||||
</div>
|
52
src/post.css
Normal file
52
src/post.css
Normal file
|
@ -0,0 +1,52 @@
|
|||
code {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: var(--color-gray-800);
|
||||
overflow: auto;
|
||||
padding: 0.5vw;
|
||||
margin: 0.5vw 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
box-sizing: revert;
|
||||
margin: revert;
|
||||
padding: revert;
|
||||
border: revert;
|
||||
}
|
||||
|
||||
.markdown-alert-title {
|
||||
font-family: 'typewriter';
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.markdown-alert-warning .markdown-alert-title {
|
||||
fill: var(--color-red-400);
|
||||
color: var(--color-red-400);
|
||||
}
|
||||
|
||||
.markdown-alert {
|
||||
padding: 1vw;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h1, h2, h3:not(#title), h4, h5 {
|
||||
font-weight: revert;
|
||||
font-size: revert;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-size: var(--text-lg);
|
||||
}
|
33
src/posts/classicube1.md
Normal file
33
src/posts/classicube1.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: "ClassiCube: Minecraft Classic, reimagined!"
|
||||
desc: ""
|
||||
tags: post
|
||||
date: 2024-08-17
|
||||
---
|
||||
|
||||
# ClassiCube: Minecraft Classic, reimagined!
|
||||
|
||||
I had recently taken an interest again in the Minecraft Classic community, seeing as how this part of the Minecraft community is very different from your average Minecraft player.
|
||||
This part of the Minecraft community is much more focussed on the building & modding aspect of Minecraft, rather than Minecraft's (mostly competitive) gamemodes, making it an excellent platform to let your creativity free.
|
||||
|
||||

|
||||

|
||||
|
||||
## ClassiCube? That doesn't sound like Minecraft Classic?
|
||||
|
||||
You'd be right. ClassiCube is (atleast nowadays) much more focussed on **continuing** from Minecraft Classic, rather than **being** Minecraft Classic, although this used to be their main focus, from what i can find.
|
||||
ClassiCube is basically what the team at CC imagines Minecraft Classic (and onwards) should have been, although some features are pretty weird and/or quality-of-life (think about, built-in "hacks" to navigate around), i would personally consider this an entire game in itself.
|
||||
|
||||
ClassiCube also features its own client built entirely from scratch in C (wen rust rewrite???), mimicing the look and feel of the Minecraft Classic client, while being much more performant and moddable.
|
||||
|
||||
## Alright, sign me up!
|
||||
|
||||
You can [register here](https://classicube.net) & download their client.
|
||||
My in-game name is ``hexlocation``, say hi if you see me :)
|
||||
### More screenshots :)
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
-- hex
|
224
src/posts/init.md
Normal file
224
src/posts/init.md
Normal file
|
@ -0,0 +1,224 @@
|
|||
---
|
||||
title: "Hijacking your init system for fun and profit!"
|
||||
desc: "Click here for some hackery."
|
||||
tags: post
|
||||
date: 2024-11-20
|
||||
---
|
||||
|
||||
# Hijacking your init system for fun and profit!
|
||||
|
||||
## Prologue
|
||||
|
||||
Recently, I have begun messing with the Linux kernel, modifying some code, printing out some ascii art and making a very tiny initramfs without busybox for fun. This has made me aware of the fact that your init system resides in (or is bootstrapped from) a **single** binary! So, as one typically does, I decided to mess around with the things you can do when running as the init system.
|
||||
|
||||
## Replacing your init system
|
||||
|
||||
Ah yes, irresponsibly modifying your system files, the killer of immutable distros...
|
||||
So... how would one replace their init system? Well, to test this, I wrote a simple C program to print out hello world...
|
||||
|
||||
```
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello world! This is init speaking to you from the linux kernel.\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
I compiled it with ``gcc test.c``, ran it by adding init=\<path to binary\> to my kernel parameters, and... it failed?
|
||||
|
||||
```
|
||||
[ 1.547957] Failed to execute /test (error -2)
|
||||
[ 1.549016] Default init /sbin/init failed (error -2)
|
||||
[ 1.550202] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance.
|
||||
[ 1.550792] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.6.62_1 #1
|
||||
[ 1.551034] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
|
||||
[ 1.551468] Call Trace:
|
||||
[ 1.551602] <TASK>
|
||||
[ 1.551921] dump_stack_lvl+0x47/0x60
|
||||
[ 1.552280] panic+0x180/0x340
|
||||
[ 1.552392] ? __pfx_kernel_init+0x10/0x10
|
||||
[ 1.552509] kernel_init+0x18d/0x1f0
|
||||
[ 1.552611] ret_from_fork+0x34/0x50
|
||||
[ 1.552719] ? __pfx_kernel_init+0x10/0x10
|
||||
[ 1.552834] ret_from_fork_asm+0x1b/0x30
|
||||
[ 1.552978] </TASK>
|
||||
[ 1.553421] Kernel Offset: 0x1d000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
|
||||
[ 1.553901] ---[ end Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance. ]---
|
||||
```
|
||||
|
||||
Oh, right... my test environment doesn't include any libraries, it's just a cpio image with the binary at /test! Oh well, we can fix that! I added ``-static`` to the GCC flags to include the libraries with the binary, and...
|
||||
|
||||
```
|
||||
Hello world! This is init speaking to you from the linux kernel.
|
||||
[ 1.615461] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
|
||||
[ 1.616336] CPU: 0 PID: 1 Comm: init Not tainted 6.6.62_1 #1
|
||||
[ 1.616712] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
|
||||
[ 1.617199] Call Trace:
|
||||
[ 1.617343] <TASK>
|
||||
[ 1.617494] dump_stack_lvl+0x47/0x60
|
||||
[ 1.617882] panic+0x180/0x340
|
||||
[ 1.617987] do_exit+0x9c1/0xb40
|
||||
[ 1.618097] do_group_exit+0x31/0x80
|
||||
[ 1.618205] __x64_sys_exit_group+0x18/0x20
|
||||
[ 1.618326] do_syscall_64+0x5a/0x80
|
||||
[ 1.618457] ? __count_memcg_events+0x73/0xc0
|
||||
[ 1.618595] ? count_memcg_events.constprop.0+0x1a/0x30
|
||||
[ 1.618749] ? handle_mm_fault+0xa2/0x360
|
||||
[ 1.618865] ? preempt_count_add+0x4b/0xa0
|
||||
[ 1.618978] ? up_read+0x3b/0x80
|
||||
[ 1.619087] ? do_user_addr_fault+0x30b/0x620
|
||||
[ 1.619211] ? fpregs_assert_state_consistent+0x26/0x50
|
||||
[ 1.619353] ? exit_to_user_mode_prepare+0x40/0x1b0
|
||||
[ 1.619489] entry_SYSCALL_64_after_hwframe+0x78/0xe2
|
||||
[ 1.619785] RIP: 0033:0x4172b5
|
||||
[ 1.620186] Code: ff ff ff c3 48 c7 c0 c0 ff ff ff 64 c7 00 26 00 00 00 eb ea 90 48 c7 c6 c0 ff ff ff ba e7 00 00 00 eb 03 66 90 f4 89 d0 0f 05 <48> 3d 00 f0 ff ff 76 f3 f7 d8 64 89 06 eb0
|
||||
[ 1.620764] RSP: 002b:00007fffe87e5058 EFLAGS: 00000206 ORIG_RAX: 00000000000000e7
|
||||
[ 1.621005] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00000000004172b5
|
||||
[ 1.621210] RDX: 00000000000000e7 RSI: ffffffffffffffc0 RDI: 0000000000000000
|
||||
[ 1.621407] RBP: 0000000000000000 R08: 00007fffe87e4f58 R09: 000000000000001c
|
||||
[ 1.621627] R10: 0000000000000007 R11: 0000000000000206 R12: 0000000000000001
|
||||
[ 1.621830] R13: 0000000000000000 R14: 000000000049d100 R15: 000000000049f3e0
|
||||
[ 1.622077] </TASK>
|
||||
[ 1.622537] Kernel Offset: 0x22000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
|
||||
[ 1.623075] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000 ]---
|
||||
```
|
||||
|
||||
**It worked!** We have successfully created our own init system, if you will.
|
||||
|
||||
## Replacing your init system on a real system.
|
||||
|
||||
Right, so now we have our own, working "init system", but **what if we want to do this on a real system, while still being able to boot**?
|
||||
It's simple, really! Make your init system redirect execution to the "real" init system. We can do this by executing the execve syscall at the end of our C program, passing /sbin/init as the argument.
|
||||
|
||||
From the execve man page:
|
||||
> **execve**() executes the program referred to by _pathname_. This
|
||||
causes the program that is currently being run by the calling
|
||||
process to be replaced with a new program, with newly initialized
|
||||
stack, heap, and (initialized and uninitialized) data segments.
|
||||
|
||||
My simple C program now looks like this:
|
||||
|
||||
```
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello world! This is init speaking to you from the linux kernel.\n");
|
||||
execve("/sbin/init", NULL, NULL); // redirect execution to the real init system
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
And... it now boots!
|
||||
## What do we do now?
|
||||
|
||||
> [!WARNING]
|
||||
> This section *should* be safe to follow on a production system, but could still brick it. I am not responsible for any damage you cause to your system.
|
||||
|
||||
What everyone wants of course! Some ascii art! For this, I have made a simple C program that slowly reads out a file on the root filesystem and centers it.
|
||||
|
||||
I have gone through many revisions, but here is the final (janky) program I came up with.
|
||||
|
||||
```
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <unistd.h>
|
||||
#include <asm/termbits.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
FILE *fptr;
|
||||
char c;
|
||||
struct winsize ws;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) {
|
||||
printf("fuck the terminal size");
|
||||
}
|
||||
|
||||
fptr = fopen("/sequence", "r");
|
||||
|
||||
if (fptr == NULL) {
|
||||
printf("Couldn't find file!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
|
||||
memset(line, 0, sizeof(line)); // clear line string
|
||||
|
||||
while ((c = fgetc(fptr)) != EOF) {
|
||||
int len = strlen(line);
|
||||
line[len] = c; // append char to string
|
||||
|
||||
if (c == '\n') {
|
||||
int width = round(
|
||||
len +
|
||||
(ws.ws_col - len) /
|
||||
2); // calculate appropriate width to add to start of line
|
||||
|
||||
char line_no_padding[sizeof(
|
||||
line)]; // copy line without the padding for use in formatting
|
||||
memcpy(line_no_padding, line,
|
||||
sizeof(line_no_padding)); // copy old line var to line_no_padding
|
||||
|
||||
sprintf(line, "%*s", width,
|
||||
line_no_padding); // recycle old line var for new line with padding
|
||||
|
||||
// slowly print out each char
|
||||
for (int i = 0; i < strlen(line) + 1; i++) {
|
||||
printf("%c", line[i]); // print char
|
||||
|
||||
if (line[i] != ' ')
|
||||
usleep(25 *
|
||||
1000); // sleep if char is not a space
|
||||
|
||||
fflush(stdout); // flush tty
|
||||
}
|
||||
|
||||
memset(line, 0,
|
||||
sizeof(line)); // clear the line to make room for the next line
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fptr);
|
||||
|
||||
execve("/sbin/init", NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compile with ``gcc -static main.c`` and move the resulting binary to /splash, and then put your ascii art into ``/sequence``. Here's mine:
|
||||
|
||||
```
|
||||
#######################################################################################
|
||||
# #
|
||||
# ..####....####...######...####............####....####.. |\---/| #
|
||||
# .##......##..##....##....##..##..........##..##..##..... | ,_, | #
|
||||
# .##.###..######....##....##..##..........##..##...####.. \_`_/-..----. #
|
||||
# .##..##..##..##....##....##..##..........##..##......##. ___/ ` ' ,""+ \ meow #
|
||||
# ..####...##..##....##.....####............####....####.. (__...' __\ |`.___.'; #
|
||||
# ........................................................ (_,...'(_,.`__)/'.....+ #
|
||||
# #
|
||||
#######################################################################################
|
||||
doing some tomfoolery...
|
||||
|
||||
```
|
||||
|
||||
Now the last thing you need to do is modify your bootloader to use /splash, this can be done by changing the init parameter to /splash. If you use grub, append ``init=/splash`` to GRUB_CMDLINE_LINUX_DEFAULT, and run ``update-grub``.
|
||||
|
||||
Tada! You now have some fancy ascii art at boot.
|
||||
|
||||
-- hex
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
114
src/posts/micros.md
Normal file
114
src/posts/micros.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
title: "Migrating all of my servers over to OpenSUSE MicroOS - and discovering Podman Quadlet."
|
||||
desc: "Wake up, it is 2025. Stop using Debian."
|
||||
tags: post
|
||||
date: 2024-12-18
|
||||
---
|
||||
|
||||
# Migrating all of my servers over to OpenSUSE MicroOS.
|
||||
|
||||
## Why?
|
||||
TL;DR: Grew tired of Debian, wanted something immutable and low-maintenance.
|
||||
|
||||
Every single server I have ever touched has always turned into a mess, because random packages with no use to me that held back updates and/or bloated my system (For context, my main server, which hosts my arr stack and some other services, has ~1700 packages installed, which is a lot, as I mainly only use Docker to deploy services), or even packages that have completely broken all kinds of libraries and required me to spend a Saturday reinstalling.
|
||||
|
||||
Furthermore, I do not have a lot of time anymore to maintain everything, as my real life is starting to take up more and more space. The fact that I use most of the things I host on a daily basis ment that I had to start finding alternatives.
|
||||
|
||||
And find an alternative I did. It's called OpenSUSE MicroOS.
|
||||
It has been developed by a reputable company called OpenSUSE, it targets container workloads, it is easy to deploy en masse using something like Combustion (although I won't be taking full advantage of this, I only have 2 nodes as of writing this) & **minimal maintenance**, as Micro OS auto-updates and can rollback automatically in the event of a failed update. This right here is the most crucial part.
|
||||
|
||||
The only downside I have found so far is... well... it uses systemd.
|
||||
However, even systemd haters like myself have to admit - it has the (financial) support of multiple big companies, it is the most widely used init system today, and the most secure. OpenRC or runit are not really viable alternatives on servers, as they just aren't popular enough. I will **never** use systemd on any of my desktop machines though - don't worry!
|
||||
|
||||
All of this combined makes MicroOS the perfect choice. So... how do we get started?
|
||||
|
||||
## Installing MicroOS
|
||||
|
||||
Installing it is actually extremely simple. [Download](https://download.opensuse.org/tumbleweed/iso/openSUSE-MicroOS-DVD-x86_64-Current.iso) the iso pre-packaged with Podman (note: combustion and ignition are not enabled on the iso image provided by OpenSUSE), flash it to a usb stick and you're good to go.
|
||||
|
||||
You'll notice that MicroOS boots up pretty fast for a systemd distro. Took around 5-6 seconds to boot on my Dell Optiplex 3050 Micro. Once it has finished booting, it will ask you some simple questions and now you're done!
|
||||
|
||||
Once you have booted into the system, make sure you add your SSH key(s) and change the hostname, as is standard practice.
|
||||
|
||||
## Deploying services using Podman
|
||||
|
||||
Something I found out later while trying to install MicroOS in a VM for the first time is that there was no option to pre-install Docker, only Podman was available!
|
||||
I thought this was a good excuse for me to try Podman as I had heard of it before but didn't exactly know why I should be using it.
|
||||
|
||||
Initially I started by installing Podman Compose, but quickly realized something while looking at blog posts others had made on deploying using Podman - they were all using [Podman Quadlet](https://www.redhat.com/en/blog/quadlet-podman). This looked pretty cool to me, so I decided to delve a little deeper.
|
||||
|
||||
Quadlet is, in short, a way to easily declare and deploy containers, like docker/podman compose. But instead of using docker compose, you let systemd do all the hard work for you.
|
||||
|
||||
Here's what a container deployment looks like using Quadlet:
|
||||
|
||||
```
|
||||
# /etc/containers/systemd/caddy.container
|
||||
[Unit]
|
||||
Description=Caddy reverse proxy
|
||||
After=local-fs.target
|
||||
|
||||
[Container]
|
||||
Image=caddy:latest
|
||||
|
||||
PublishPort=80:80
|
||||
PublishPort=443:443
|
||||
|
||||
Volume=/var/caddy:/etc/caddy
|
||||
Volume=caddydata.volume:/data
|
||||
Volume=caddyconfig.volume:/config
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
...looks pretty similar to a systemd service right?
|
||||
|
||||
To get systemd to recognize these files, Podman uses a so called "systemd generator", called [podman-systemd.unit](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html). This generator dynamically translates those aforementioned .container files into fully working systemd services. Awesome!
|
||||
|
||||
So... how do we deploy this?
|
||||
|
||||
It's simple, really:
|
||||
1. Put the given container file into /etc/containers/systemd/caddy.container
|
||||
2. Create two files named caddydata.volume and caddyconfig.volume. You can compare these to named volumes in Docker.
|
||||
3. Reload systemd using ``systemd daemon-reload``
|
||||
4. Start the container using ``systemctl start caddy``
|
||||
|
||||
And now we have caddy up and running... right?
|
||||
|
||||
> WARNING: Do not use this on special system directories like /home or /bin. It WILL break your system (according to the docker manual).
|
||||
|
||||
Well, It's not that simple. You see, MicroOS uses SELinux. In short, SELinux defines policies for every application, file, directory etc, and it doesn't play well with container volumes by default. Using this in its current state, caddy wouldn't be able to read or write anything. Fortunately, this is just a simple fix. Add a single z to any lines that define a volume, like so:
|
||||
|
||||
```
|
||||
# /etc/containers/systemd/caddy.container
|
||||
[Unit]
|
||||
Description=Caddy reverse proxy
|
||||
After=local-fs.target
|
||||
|
||||
[Container]
|
||||
Image=caddy:latest
|
||||
|
||||
PublishPort=80:80
|
||||
PublishPort=443:443
|
||||
|
||||
Volume=/var/caddy:/etc/caddy:z
|
||||
Volume=caddydata.volume:/data:z
|
||||
Volume=caddyconfig.volume:/config:z
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
And now we have a working container! It's as simple as that.
|
||||
|
||||
## Note on Libreboot
|
||||
|
||||
Something I've had to deal with is that Libreboot does not want to boot MicroOS. I have yet to find out why, but I found a simple workaround; just use SeaBIOS instead by pressing esc at boot, and select your boot medium.
|
||||
|
||||
-- hex⏎
|
3
src/posts/posts.json
Normal file
3
src/posts/posts.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"layout": "post.njk"
|
||||
}
|
Loading…
Reference in a new issue