Added page about my homelab
This commit is contained in:
parent
588660ac62
commit
e85e882f48
23 changed files with 522 additions and 31 deletions
|
@ -5,7 +5,7 @@ import '../styles/global.css';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description?: string;
|
||||||
image?: string;
|
image?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ const today = new Date();
|
||||||
<span class="sr-only">My Github?</span>
|
<span class="sr-only">My Github?</span>
|
||||||
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github"
|
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github"
|
||||||
><path
|
><path
|
||||||
fill="currentColor"
|
fill="white"
|
||||||
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
|
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
|
||||||
></path></svg
|
></path></svg
|
||||||
>
|
>
|
||||||
|
@ -21,17 +21,21 @@ const today = new Date();
|
||||||
footer {
|
footer {
|
||||||
padding: 2em 1em 6em 1em;
|
padding: 2em 1em 6em 1em;
|
||||||
/* background: linear-gradient(var(--gray-gradient)) no-repeat;'*/
|
/* background: linear-gradient(var(--gray-gradient)) no-repeat;'*/
|
||||||
color: rgb(var(--gray));
|
color: white;
|
||||||
|
background-color: rgb(198, 60, 81);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 80%;
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 100%;
|
||||||
|
height: 0em;
|
||||||
}
|
}
|
||||||
.social-links {
|
.social-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
.social-links a {
|
.social-links a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { SITE_TITLE } from '../consts';
|
||||||
<HeaderLink href="/">Home</HeaderLink>
|
<HeaderLink href="/">Home</HeaderLink>
|
||||||
<HeaderLink href="/blog">Blog</HeaderLink>
|
<HeaderLink href="/blog">Blog</HeaderLink>
|
||||||
<HeaderLink href="/about">About</HeaderLink>
|
<HeaderLink href="/about">About</HeaderLink>
|
||||||
|
<HeaderLink href="/homelab">Homelab</HeaderLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="social-links">
|
<div class="social-links">
|
||||||
<a href="https://github.com/polsevev" target="_blank">
|
<a href="https://github.com/polsevev" target="_blank">
|
||||||
|
@ -28,12 +29,17 @@ import { SITE_TITLE } from '../consts';
|
||||||
header {
|
header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
background: white;
|
background-color: rgb(198, 60, 81);
|
||||||
box-shadow: 0 2px 8px rgba(var(--black), 5%);
|
box-shadow: 0 2px 8px rgba(var(--black), 5%);
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
color: white;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 a,
|
h2 a,
|
||||||
|
|
|
@ -1,5 +1,24 @@
|
||||||
import { defineCollection, z } from 'astro:content';
|
import { defineCollection, z } from 'astro:content';
|
||||||
|
|
||||||
|
const homelab = defineCollection({
|
||||||
|
type: 'content',
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
// Transform string to Date object
|
||||||
|
pubDate: z.coerce.date(),
|
||||||
|
updatedDate: z.coerce.date().optional(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const servers = defineCollection({
|
||||||
|
type: 'content',
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
lastUpdated: z.coerce.date()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const blog = defineCollection({
|
const blog = defineCollection({
|
||||||
type: 'content',
|
type: 'content',
|
||||||
// Type-check frontmatter using a schema
|
// Type-check frontmatter using a schema
|
||||||
|
@ -9,8 +28,7 @@ const blog = defineCollection({
|
||||||
// Transform string to Date object
|
// Transform string to Date object
|
||||||
pubDate: z.coerce.date(),
|
pubDate: z.coerce.date(),
|
||||||
updatedDate: z.coerce.date().optional(),
|
updatedDate: z.coerce.date().optional(),
|
||||||
heroImage: z.string().optional(),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collections = { blog };
|
export const collections = { blog, homelab, servers };
|
||||||
|
|
7
src/content/homelab/woodpecker.md
Normal file
7
src/content/homelab/woodpecker.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title: Woodpecker as CI
|
||||||
|
description: Setting up my own CI with Woodpecker!
|
||||||
|
pubDate: 08.03.2024
|
||||||
|
---
|
||||||
|
|
||||||
|
I am currently working on setting opp Woodpecker as my CI. Will write a post about this here :)
|
34
src/content/servers/Oceanus.md
Normal file
34
src/content/servers/Oceanus.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
title: 'Oceanus'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is it?
|
||||||
|
|
||||||
|
Oceanus is my main VM server. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
|
||||||
|
## Specs
|
||||||
|
|
||||||
|
- MODEL: HP Elitedesk 600 G3
|
||||||
|
- CPU: i7 6700
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage:
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
Currently this server has quite a bit of purpose, but i will probably move most of the stateless applications from this into my K3S cluster.
|
||||||
|
|
||||||
|
- lb-1
|
||||||
|
- HAproxy load-balancer
|
||||||
|
- nginx-public
|
||||||
|
- Temporary NGINX until i get K3S up and running
|
||||||
|
- wireguard
|
||||||
|
- Hosts a wireguard instance i use for VPN
|
||||||
|
- grafana
|
||||||
|
- ALL THE DASHBOARDS!
|
||||||
|
- woodpecker_worker
|
||||||
|
- This is a WIP of setting up my own CI
|
||||||
|
|
||||||
|

|
27
src/content/servers/ares.md
Normal file
27
src/content/servers/ares.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
title: 'Ares'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
## What is it?
|
||||||
|
|
||||||
|
Ares is a node in my cluster of 5 mini PCs. It follows the exact same configuration as the other nodes for consistency. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
|
||||||
|
## Specs
|
||||||
|
|
||||||
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
|
- CPU: AMD A10-8770E
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running proxmox at the moment, to allow for virtualization of all my services. Currently this server has 2 VMS.
|
||||||
|
|
||||||
|
- k3s_master
|
||||||
|
- Master in my K3s cluster
|
||||||
|
- k3s_worker
|
||||||
|
- Worker in my K3S cluster
|
||||||
|
|
||||||
|

|
25
src/content/servers/cronus.md
Normal file
25
src/content/servers/cronus.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: 'Cronus'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is it?
|
||||||
|
|
||||||
|
Cronus was my first server, and i built it myself. This was my entry into homelabing and i am so thankful i spent the money on it, even though i was a struggling student.
|
||||||
|
|
||||||
|
## Specs
|
||||||
|
|
||||||
|
- CPU: 1x Xeon E5 2678 V3 12 core
|
||||||
|
- RAM: 24 GB DDR4
|
||||||
|
- MOTHERBOARD: MSI X99S SLI-PLUS
|
||||||
|
- Storage
|
||||||
|
- 7x 4 TB Ironwolf HDD
|
||||||
|
- 1x 1 TB NVME SSD
|
||||||
|
- GPU: Nvidia GTX 1050 ti
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running [Unraid](https://unraid.net). I made this choice because i was new to servers when i built it, and wanted a simple entry. Turns out that was quite a wise choice, as it allowed me to build my skills over time without making it super difficult in the beginning.
|
||||||
|
|
||||||
|
Currently this server mostly only contains files and serves its purpose as a NAS. I do some video transcoding with ffmpeg on it as well to minimize the space my videos take. This is actually a breeze because of the GPU
|
||||||
|
|
||||||
|

|
24
src/content/servers/hades.md
Normal file
24
src/content/servers/hades.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
title: 'Hades'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
Hades is a node in my cluster of 5 mini PCs. It follows the exact same configuration as the other nodes for consistency. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
|
||||||
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
|
- CPU: AMD A10-8770E
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running proxmox at the moment, to allow for virtualization of all my services. Currently this server has 2 VMS.
|
||||||
|
|
||||||
|
- k3s_master
|
||||||
|
- Master in my K3s cluster
|
||||||
|
- k3s_worker
|
||||||
|
- Worker in my K3S cluster
|
||||||
|
|
||||||
|

|
24
src/content/servers/hermes.md
Normal file
24
src/content/servers/hermes.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
title: 'Hermes'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
Hermes is a node in my cluster of 5 mini PCs. It follows the exact same configuration as the other nodes for consistency. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
|
||||||
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
|
- CPU: AMD A10-8770E
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running proxmox at the moment, to allow for virtualization of all my services. Currently this server has 2 VMS.
|
||||||
|
|
||||||
|
- k3s_master
|
||||||
|
- Master in my K3s cluster
|
||||||
|
- k3s_worker
|
||||||
|
- Worker in my K3S cluster
|
||||||
|
|
||||||
|

|
BIN
src/content/servers/images/cluster.png
Normal file
BIN
src/content/servers/images/cluster.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 717 KiB |
BIN
src/content/servers/images/cronus.png
Normal file
BIN
src/content/servers/images/cronus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 936 KiB |
BIN
src/content/servers/images/oceanus.png
Normal file
BIN
src/content/servers/images/oceanus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 542 KiB |
24
src/content/servers/poseidon.md
Normal file
24
src/content/servers/poseidon.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
title: 'Poseidon'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
Poseidon is a node in my cluster of 5 mini PCs. It follows the exact same configuration as the other nodes for consistency. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
|
||||||
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
|
- CPU: AMD A10-8770E
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running proxmox at the moment, to allow for virtualization of all my services. Currently this server has 2 VMS.
|
||||||
|
|
||||||
|
- k3s_master
|
||||||
|
- Master in my K3s cluster
|
||||||
|
- k3s_worker
|
||||||
|
- Worker in my K3S cluster
|
||||||
|
|
||||||
|

|
25
src/content/servers/zeus.md
Normal file
25
src/content/servers/zeus.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: 'Zeus'
|
||||||
|
lastUpdated: '03.08.2024'
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is it?
|
||||||
|
Zeus is a node in my cluster of 5 mini PCs. It follows the exact same configuration as the other nodes for consistency. It used to be an office PC, but has since been re-purposed as a tiny home server.
|
||||||
|
## Specs
|
||||||
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
|
- CPU: AMD A10-8770E
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This server is running proxmox at the moment, to allow for virtualization of all my services. Currently this server has 2 VMS.
|
||||||
|
|
||||||
|
- k3s_master
|
||||||
|
- Master in my K3s cluster
|
||||||
|
- k3s_worker
|
||||||
|
- Worker in my K3S cluster
|
||||||
|
|
||||||
|

|
|
@ -7,7 +7,7 @@ import FormattedDate from '../components/FormattedDate.astro';
|
||||||
|
|
||||||
type Props = CollectionEntry<'blog'>['data'];
|
type Props = CollectionEntry<'blog'>['data'];
|
||||||
|
|
||||||
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
const { title, description, pubDate, updatedDate} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
@ -19,21 +19,12 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.hero-image {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.hero-image img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: var(--box-shadow);
|
|
||||||
}
|
|
||||||
.prose {
|
.prose {
|
||||||
width: 720px;
|
width: 720px;
|
||||||
max-width: calc(100% - 2em);
|
max-width: calc(100% - 2em);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
color: rgb(var(--gray-dark));
|
color: cyan;
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
@ -58,9 +49,6 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||||
<Header />
|
<Header />
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<div class="hero-image">
|
|
||||||
{heroImage && <img width={1020} height={510} src={heroImage} alt="" />}
|
|
||||||
</div>
|
|
||||||
<div class="prose">
|
<div class="prose">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="date">
|
<div class="date">
|
||||||
|
|
67
src/layouts/ServerDescription.astro
Normal file
67
src/layouts/ServerDescription.astro
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
import type { CollectionEntry } from 'astro:content';
|
||||||
|
import BaseHead from '../components/BaseHead.astro';
|
||||||
|
import Header from '../components/Header.astro';
|
||||||
|
import Footer from '../components/Footer.astro';
|
||||||
|
import FormattedDate from '../components/FormattedDate.astro';
|
||||||
|
|
||||||
|
type Props = CollectionEntry<'servers'>['data'];
|
||||||
|
|
||||||
|
const { title, lastUpdated} = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<BaseHead title={title} />
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
width: calc(100% - 2em);
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.prose {
|
||||||
|
width: 720px;
|
||||||
|
max-width: calc(100% - 2em);
|
||||||
|
margin: auto;
|
||||||
|
padding: 1em;
|
||||||
|
color: cyan;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 1em 0;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.title h1 {
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
}
|
||||||
|
img{
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<div class="prose">
|
||||||
|
<div class="title">
|
||||||
|
<div class="date">
|
||||||
|
<FormattedDate date={lastUpdated} />
|
||||||
|
</div>
|
||||||
|
<h1>🖥️ {title}</h1>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -21,7 +21,4 @@ import Layout from "../layouts/BlogPost.astro";
|
||||||
<p>
|
<p>
|
||||||
I do love board games! Currently my favorite has to be Magic The Gathering, it eats up way too much of my time and salary, but i find the game so engaging and fun.
|
I do love board games! Currently my favorite has to be Magic The Gathering, it eats up way too much of my time and salary, but i find the game so engaging and fun.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
I mostly spend my time hanging out with friends, playing magic, or tinkering in my homelab.
|
|
||||||
</p>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -94,7 +94,6 @@ const posts = (await getCollection('blog')).sort(
|
||||||
posts.map((post) => (
|
posts.map((post) => (
|
||||||
<li>
|
<li>
|
||||||
<a href={`/blog/${post.slug}/`}>
|
<a href={`/blog/${post.slug}/`}>
|
||||||
<img width={720} height={360} src={post.data.heroImage} alt="" />
|
|
||||||
<h4 class="title">{post.data.title}</h4>
|
<h4 class="title">{post.data.title}</h4>
|
||||||
<p class="date">
|
<p class="date">
|
||||||
<FormattedDate date={post.data.pubDate} />
|
<FormattedDate date={post.data.pubDate} />
|
||||||
|
|
23
src/pages/homelab/[...slug].astro
Normal file
23
src/pages/homelab/[...slug].astro
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||||
|
import BlogPost from '../../layouts/BlogPost.astro';
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const posts = await getCollection('homelab');
|
||||||
|
|
||||||
|
return posts.map((post)=> ({
|
||||||
|
params: { slug: post.slug },
|
||||||
|
props: post,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = CollectionEntry<'homelab'>;
|
||||||
|
|
||||||
|
const post = Astro.props;
|
||||||
|
const { Content } = await post.render();
|
||||||
|
---
|
||||||
|
|
||||||
|
<BlogPost {...post.data}>
|
||||||
|
<Content />
|
||||||
|
</BlogPost>
|
165
src/pages/homelab/index.astro
Normal file
165
src/pages/homelab/index.astro
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
---
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
|
import BaseHead from "../../components/BaseHead.astro";
|
||||||
|
import Footer from "../../components/Footer.astro";
|
||||||
|
import FormattedDate from "../../components/FormattedDate.astro";
|
||||||
|
import Header from "../../components/Header.astro";
|
||||||
|
import { SITE_TITLE, SITE_DESCRIPTION } from "../../consts";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const posts = (await getCollection('homelab')).sort(
|
||||||
|
(a, b) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
|
||||||
|
);
|
||||||
|
const servers = (await getCollection('servers'));
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2rem;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
ul li * {
|
||||||
|
text-decoration: none;
|
||||||
|
transition: 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li img {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
ul li a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(0,255,159);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
}
|
||||||
|
ul li a:hover h4,
|
||||||
|
ul li a:hover .date {
|
||||||
|
color: rgb(var(--accent));
|
||||||
|
}
|
||||||
|
ul a:hover img {
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
ul {
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
site_header{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
left{
|
||||||
|
width: 75%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
right{
|
||||||
|
width: 25%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#column{
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
|
box{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
box left,right{
|
||||||
|
border-color: white;
|
||||||
|
border-width: 0.2em;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 1em;
|
||||||
|
margin: 0.2em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<site_header>
|
||||||
|
<h2>All bout the homelab!</h2>
|
||||||
|
</site_header>
|
||||||
|
<box>
|
||||||
|
<left class="column">
|
||||||
|
<h3>What is in my homelab now?</h3>
|
||||||
|
<p>
|
||||||
|
So my current homelab has gotten quite extensive, which honestly is a pain because electricity is expensive as hell.
|
||||||
|
</p>
|
||||||
|
<p>I have waaaaay too many servers, and they are not at all used to their full capabilites. But i am a tinkerer at heart.
|
||||||
|
Owning a proxmox cluster with 6 nodes, or a 5 node K3S cluster is just fun to me. It doesn't really matter that it costs money, it is a hobby. So without further ado,
|
||||||
|
let me explain each server, and what it is currently being used for.
|
||||||
|
</p>
|
||||||
|
<p>As you can probably tell, i use greek mythology for the naming scheme of physical machines :P</p>
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
servers.map((s) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/homelab/servers/${s.slug}/`}>
|
||||||
|
<h5 class="title">🖥️ {s.data.title}</h5>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</left>
|
||||||
|
<right class="column">
|
||||||
|
<h3>Homelab blog:</h3>
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
posts.length == 0 ? <p>Wow, such empty</p> :
|
||||||
|
posts.sort((a,b) => {
|
||||||
|
return b.data.pubDate.getTime() - a.data.pubDate.getTime()
|
||||||
|
}).map((post) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/homelab/${post.slug}/`}>
|
||||||
|
<h5 class="title">{post.data.title}</h4>
|
||||||
|
<p class="date">
|
||||||
|
<FormattedDate date={post.data.pubDate} />
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</right>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
25
src/pages/homelab/servers/[...slug].astro
Normal file
25
src/pages/homelab/servers/[...slug].astro
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||||
|
import BlogPost from '../../../layouts/BlogPost.astro';
|
||||||
|
import ServerDescription from '../../../layouts/ServerDescription.astro';
|
||||||
|
import type { ACTION_ERROR_CODES } from 'astro:actions';
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const servers = await getCollection('servers');
|
||||||
|
|
||||||
|
return servers.map((s)=> ({
|
||||||
|
params: { slug: s.slug },
|
||||||
|
props: s,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = CollectionEntry<'servers'>;
|
||||||
|
|
||||||
|
const servers = Astro.props;
|
||||||
|
const { Content } = await servers.render();
|
||||||
|
---
|
||||||
|
|
||||||
|
<ServerDescription {...servers.data}>
|
||||||
|
<Content />
|
||||||
|
</BlogPost>
|
|
@ -14,6 +14,7 @@
|
||||||
--gray-gradient: rgba(var(--gray-light), 50%), #fff;
|
--gray-gradient: rgba(var(--gray-light), 50%), #fff;
|
||||||
--box-shadow: 0 2px 6px rgba(var(--gray), 25%), 0 8px 24px rgba(var(--gray), 33%),
|
--box-shadow: 0 2px 6px rgba(var(--gray), 25%), 0 8px 24px rgba(var(--gray), 33%),
|
||||||
0 16px 32px rgba(var(--gray), 33%);
|
0 16px 32px rgba(var(--gray), 33%);
|
||||||
|
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Atkinson';
|
font-family: 'Atkinson';
|
||||||
|
@ -29,6 +30,12 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
}
|
}
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
footer{
|
||||||
|
height: 4em;
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
font-family: 'Atkinson', sans-serif;
|
font-family: 'Atkinson', sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -38,11 +45,11 @@ body {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: linear-gradient(var(--gray-gradient)) no-repeat;
|
background: repeating-linear-gradient(to bottom, #522258 0%, #8c3061, #522258 100%);
|
||||||
background-size: 100% 600px;
|
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
color: rgb(var(--gray-dark));
|
color: cyan;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +57,9 @@ main {
|
||||||
width: 720px;
|
width: 720px;
|
||||||
max-width: calc(100% - 2em);
|
max-width: calc(100% - 2em);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
min-height: 100%;
|
||||||
padding: 3em 1em;
|
padding: 3em 1em;
|
||||||
|
margin-bottom: -4em;
|
||||||
}
|
}
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
|
@ -59,7 +68,7 @@ h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
margin: 0 0 0.5rem 0;
|
margin: 0 0 0.5rem 0;
|
||||||
color: rgb(var(--black));
|
color: rgb(0,255,159);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
|
|
Loading…
Reference in a new issue