Compare commits
47 commits
Author | SHA1 | Date | |
---|---|---|---|
63b4438463 | |||
7989f98776 | |||
2608fd281d | |||
19e2605b03 | |||
d12dfc6d91 | |||
5a74fb5ef5 | |||
10a550aea2 | |||
1d51866188 | |||
f969c3620d | |||
5057118cc3 | |||
66f85f80f2 | |||
76a9cbb157 | |||
12ae79ecd8 | |||
354c45a260 | |||
186ff13f6c | |||
84585ca242 | |||
ce129548d1 | |||
4f07ca6526 | |||
62166113fa | |||
82774c08f4 | |||
5c642d0626 | |||
6a8a1a5871 | |||
0e156d5f61 | |||
7c973ac48a | |||
0c245cb055 | |||
b5aabf34a3 | |||
d2bb4cf502 | |||
9e9aacfbcf | |||
af1cd7ed91 | |||
4566c85c44 | |||
bd785f0fc0 | |||
7d46ceeae7 | |||
c6891b9e1f | |||
1f342fb6fd | |||
6382e55f70 | |||
41f6a74b69 | |||
2b17edc92b | |||
92507301ac | |||
8b72fb085f | |||
4fbb7f0321 | |||
71dd878651 | |||
![]() |
8e245ce07b | ||
429e7ff3b0 | |||
2dc58f20ce | |||
90bab656bf | |||
614a021b1e | |||
88d816c144 |
14
.forgejo/workflows/deploy.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: npm i
|
||||||
|
- run: npm run build
|
||||||
|
- run: ssh-keyscan hephaestus >> ~/.ssh/known_hosts
|
||||||
|
- run: /bin/rsync -avzh ./dist ansible@hephaestus:/var/www/polsevev/
|
||||||
|
|
28
.github/workflows/main.yml
vendored
|
@ -1,28 +0,0 @@
|
||||||
name: Build on self hosted runner
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master2
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build Website
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- run: |
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
- name: Rsync to server
|
|
||||||
uses: burnett01/rsync-deployments@5.2
|
|
||||||
with:
|
|
||||||
switches: -avzr --delete
|
|
||||||
path: dist
|
|
||||||
remote_path: /var/www/polsevev
|
|
||||||
remote_host: ${{secrets.SERVER_IP}}
|
|
||||||
remote_user: ansible
|
|
||||||
remote_key: ${{secrets.SSH_PRIVATE_KEY}}
|
|
||||||
remote_port: 22
|
|
|
@ -1,17 +0,0 @@
|
||||||
when:
|
|
||||||
- event: push
|
|
||||||
branch: testing
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
image: local/builder
|
|
||||||
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
- mkdir /root/.ssh && chmod 0700 /root/.ssh
|
|
||||||
- echo $SSH_KEY | base64 --decode >> /root/.ssh/id_rsa
|
|
||||||
- chmod 0600 /root/.ssh/id_rsa
|
|
||||||
- ssh-keyscan $REMOTE_IP >> /root/.ssh/known_hosts
|
|
||||||
- /bin/rsync -avzh ./dist ansible@$REMOTE_IP:/var/www/polsevev/dist
|
|
||||||
secrets: [ SSH_KEY, remote_ip ]
|
|
24
LICENSE
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
|
@ -1,5 +1,5 @@
|
||||||
# Test 2
|
# Welcome!
|
||||||
|
|
||||||
I am evaluating if i want to use Astro to make this website :)
|
|
||||||
|
|
||||||
|
This is a repo for my website [polsevev.dev](polsevev.dev)
|
||||||
|
|
||||||
|
You are welcome to look at, and use, the code. If you want submit a PR you can, but i prolly won't accept it, as this is just a place for mye to publish things on the interwebs while avoiding using social media.
|
||||||
|
|
|
@ -5,6 +5,6 @@ import sitemap from '@astrojs/sitemap';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: 'https://example.com',
|
site: 'https://polsevev.dev',
|
||||||
integrations: [mdx(), sitemap()],
|
integrations: [mdx(), sitemap()],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
# Astro Starter Kit: Blog
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm create astro@latest -- --template blog
|
|
||||||
```
|
|
||||||
|
|
||||||
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/blog)
|
|
||||||
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/blog)
|
|
||||||
[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/blog/devcontainer.json)
|
|
||||||
|
|
||||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- ✅ Minimal styling (make it your own!)
|
|
||||||
- ✅ 100/100 Lighthouse performance
|
|
||||||
- ✅ SEO-friendly with canonical URLs and OpenGraph data
|
|
||||||
- ✅ Sitemap support
|
|
||||||
- ✅ RSS Feed support
|
|
||||||
- ✅ Markdown & MDX support
|
|
||||||
|
|
||||||
## 🚀 Project Structure
|
|
||||||
|
|
||||||
Inside of your Astro project, you'll see the following folders and files:
|
|
||||||
|
|
||||||
```text
|
|
||||||
├── public/
|
|
||||||
├── src/
|
|
||||||
│ ├── components/
|
|
||||||
│ ├── content/
|
|
||||||
│ ├── layouts/
|
|
||||||
│ └── pages/
|
|
||||||
├── astro.config.mjs
|
|
||||||
├── README.md
|
|
||||||
├── package.json
|
|
||||||
└── tsconfig.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
|
||||||
|
|
||||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
|
||||||
|
|
||||||
The `src/content/` directory contains "collections" of related Markdown and MDX documents. Use `getCollection()` to retrieve posts from `src/content/blog/`, and type-check your frontmatter using an optional schema. See [Astro's Content Collections docs](https://docs.astro.build/en/guides/content-collections/) to learn more.
|
|
||||||
|
|
||||||
Any static assets, like images, can be placed in the `public/` directory.
|
|
||||||
|
|
||||||
## 🧞 Commands
|
|
||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
|
||||||
|
|
||||||
| Command | Action |
|
|
||||||
| :------------------------ | :----------------------------------------------- |
|
|
||||||
| `npm install` | Installs dependencies |
|
|
||||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
|
||||||
| `npm run build` | Build your production site to `./dist/` |
|
|
||||||
| `npm run preview` | Preview your build locally, before deploying |
|
|
||||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
||||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
|
||||||
|
|
||||||
## 👀 Want to learn more?
|
|
||||||
|
|
||||||
Check out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
|
||||||
|
|
||||||
## Credit
|
|
||||||
|
|
||||||
This theme is based off of the lovely [Bear Blog](https://github.com/HermanMartinus/bearblog/).
|
|
2262
package-lock.json
generated
11
package.json
|
@ -10,11 +10,12 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^3.1.3",
|
"@astrojs/check": "^0.9.4",
|
||||||
"@astrojs/rss": "^4.0.7",
|
"@astrojs/mdx": "^3.1.8",
|
||||||
"@astrojs/sitemap": "^3.1.6",
|
"@astrojs/rss": "^4.0.9",
|
||||||
"astro": "^4.13.1",
|
"@astrojs/sitemap": "^3.2.1",
|
||||||
"@astrojs/check": "^0.9.1",
|
"astro": "^4.16.7",
|
||||||
|
"sharp": "^0.33.5",
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 21 KiB |
|
@ -1,9 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
|
||||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
|
||||||
<style>
|
|
||||||
path { fill: #000; }
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
path { fill: #FFF; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 749 B |
BIN
public/images/self.png
Normal file
After Width: | Height: | Size: 79 KiB |
40
public/svg/Forgejo_logo.svg
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<svg viewBox="0 0 212 212" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<metadata
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
>
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="https://codeberg.org/forgejo/meta/src/branch/readme/branding#logo">
|
||||||
|
<dc:title>Forgejo logo</dc:title>
|
||||||
|
<cc:creator rdf:resource="https://caesarschinas.com/"><cc:attributionName>Caesar Schinas</cc:attributionName></cc:creator>
|
||||||
|
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<style type="text/css">
|
||||||
|
circle {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 15;
|
||||||
|
}
|
||||||
|
path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 25;
|
||||||
|
}
|
||||||
|
.orange {
|
||||||
|
stroke:#ff6600;
|
||||||
|
}
|
||||||
|
.red {
|
||||||
|
stroke:#d40000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<g transform="translate(6,6)">
|
||||||
|
<path d="M58 168 v-98 a50 50 0 0 1 50-50 h20" class="orange" />
|
||||||
|
<path d="M58 168 v-30 a50 50 0 0 1 50-50 h20" class="red" />
|
||||||
|
<circle cx="142" cy="20" r="18" class="orange" />
|
||||||
|
<circle cx="142" cy="88" r="18" class="red" />
|
||||||
|
<circle cx="58" cy="180" r="18" class="red" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -11,13 +11,13 @@ interface Props {
|
||||||
|
|
||||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||||
|
|
||||||
const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props;
|
const { title, description, image = '/self.png' } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Global Metadata -->
|
<!-- Global Metadata -->
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/self.png" />
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
|
||||||
<!-- Font preloads -->
|
<!-- Font preloads -->
|
||||||
|
@ -45,3 +45,5 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props;
|
||||||
<meta property="twitter:title" content={title} />
|
<meta property="twitter:title" content={title} />
|
||||||
<meta property="twitter:description" content={description} />
|
<meta property="twitter:description" content={description} />
|
||||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||||
|
|
||||||
|
<script defer src="https://umami.polsevev.dev/script.js" data-website-id="84ead158-3295-4160-8b05-48d56cf7337b"></script>
|
|
@ -5,37 +5,33 @@ const today = new Date();
|
||||||
<footer>
|
<footer>
|
||||||
© {today.getFullYear()} Rolf Martin Glomsrud. All rights reserved.
|
© {today.getFullYear()} Rolf Martin Glomsrud. All rights reserved.
|
||||||
<div class="social-links">
|
<div class="social-links">
|
||||||
<a href="https://github.com/polsevev" target="_blank">
|
<a href="https://code.polsevev.dev" target="_blank" >
|
||||||
<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"
|
<img src="/svg/Forgejo_logo.svg"/>
|
||||||
><path
|
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github" ></svg>
|
||||||
fill="white"
|
</a>
|
||||||
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
|
|
||||||
>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
footer {
|
footer {
|
||||||
padding: 2em 1em 6em 1em;
|
padding: 1em 1em 1em 1em;
|
||||||
/* background: linear-gradient(var(--gray-gradient)) no-repeat;'*/
|
|
||||||
color: white;
|
color: white;
|
||||||
background-color: rgb(198, 60, 81);
|
background-color: rgb(198, 60, 81);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-top: 0.5rem;
|
margin-top: 2rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 2rem;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
width: 100%;
|
width: 90%;
|
||||||
height: 0em;
|
|
||||||
|
max-width: 1000px;
|
||||||
}
|
}
|
||||||
.social-links {
|
.social-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1em;
|
|
||||||
}
|
}
|
||||||
.social-links a {
|
.social-links a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -44,4 +40,8 @@ const today = new Date();
|
||||||
.social-links a:hover {
|
.social-links a:hover {
|
||||||
color: rgb(var(--gray-dark));
|
color: rgb(var(--gray-dark));
|
||||||
}
|
}
|
||||||
|
img{
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,34 +7,32 @@ import { SITE_TITLE } from '../consts';
|
||||||
<nav>
|
<nav>
|
||||||
<h2><a href="/">{SITE_TITLE}</a></h2>
|
<h2><a href="/">{SITE_TITLE}</a></h2>
|
||||||
<div class="internal-links">
|
<div class="internal-links">
|
||||||
<HeaderLink href="/">Home</HeaderLink>
|
<HeaderLink href="/">~/</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://code.polsevev.dev" target="_blank" >
|
||||||
<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"
|
<img src="/svg/Forgejo_logo.svg"/>
|
||||||
><path
|
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github" ></svg>
|
||||||
fill="currentColor"
|
|
||||||
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
|
|
||||||
>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<style>
|
<style>
|
||||||
header {
|
header {
|
||||||
margin: 0;
|
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||||
padding: 0 1em;
|
|
||||||
background-color: rgb(198, 60, 81);
|
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;
|
border-radius: 10px;
|
||||||
margin-top: 0.5rem;
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
color: white;
|
color: white;
|
||||||
width: 100%;
|
width: 90%;
|
||||||
|
max-width: 1000px;
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -52,14 +50,18 @@ import { SITE_TITLE } from '../consts';
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
nav a {
|
nav a {
|
||||||
padding: 1em 0.5em;
|
padding: 0.5em 0.5em;
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
border-bottom: 4px solid transparent;
|
border-bottom: 4px solid transparent;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
img{
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
nav a.active {
|
nav a.active {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-bottom-color: var(--accent);
|
border-bottom-color: cyan;
|
||||||
}
|
}
|
||||||
.social-links,
|
.social-links,
|
||||||
.social-links a {
|
.social-links a {
|
||||||
|
@ -69,5 +71,8 @@ import { SITE_TITLE } from '../consts';
|
||||||
.social-links {
|
.social-links {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
nav a {
|
||||||
|
padding: 0.2em 0.2em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -17,9 +17,10 @@ const isActive = href === pathname || href === '/' + subpath?.[0];
|
||||||
a {
|
a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
}
|
}
|
||||||
a.active {
|
a.active {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
text-decoration: underline;
|
text-decoreation: underline;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
BIN
src/content/blog/images/keyboard.jpg
Normal file
After Width: | Height: | Size: 2.6 MiB |
11
src/content/blog/split_keyboard.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
title: I got a split keyboard!
|
||||||
|
description: I am now a superior developer
|
||||||
|
pubDate: 1.30.2025
|
||||||
|
---
|
||||||
|
|
||||||
|
As can be read in the title, i finally caved and bought one. I am currently writing this post using it and it is better than i expected.
|
||||||
|
|
||||||
|
I will do a full writeup of my experience learning a split keyboard sometime in the future, just wanted to share the excitement!
|
||||||
|
|
||||||
|

|
28
src/content/homelab/homelab_oct_24.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
title: Homelab update
|
||||||
|
description: I did some major renovations to my homelab this week
|
||||||
|
pubDate: 10.19.2024
|
||||||
|
---
|
||||||
|
|
||||||
|
## My homelab used to be on the floor
|
||||||
|
|
||||||
|
Yeah, you read that right, no rack here. While i don't have any pictures, because i actually was ashamed of it, my homelab used to be on the floor under my desk. With a ratsnest of wires behind all the "servers", and the heat eminating from it mimicking the scorching Norwegian summer (so not that hot lol). On a random wednesday i decided to do something about this.
|
||||||
|
|
||||||
|
### Well, what?
|
||||||
|
|
||||||
|
As i have seen time and time again on [r/homelab](https://reddit.com/r/homelab), people use proper server racks. However, i live in a 32 m² appartment (more an overgrown hotel room), so finding a small but still usable rack turned out to be a challenge. I did some research and looked at the options availible to me. Turns out getting a proper rack would be quite expensive where i live. This is for several reasons, i don't have easy access to a large van, so it had to be shipped, meaning i can't go for something used, I don't have any proper rack mount servers and getting shelves for a rack is also not cheap. Therefore, after browsing reddit for a bit, i decided to go with a Ikea [Ekenabben](https://www.ikea.com/no/no/p/ekenabben-apen-hylle-asp-hvit-10487816/).
|
||||||
|
|
||||||
|
### The pain, but in the end, glory!
|
||||||
|
|
||||||
|
I fucking hate cable managing. There is no fun in it in my opinion, it takes ages and makes it difficult to make changes. But the end result is so satisfying. I think the picture speaks for itself, cables are routed behind the legs of the rack (where applicable) and the power adapters for the mini pcs are hidden below the bottom shelf. I love this.
|
||||||
|

|
||||||
|
|
||||||
|
To give a super quick rundown. At the top i have my 3d printer and free space for random things (see the raspberry pi). On the shelf below there is a wireless keyboard and mouse (for debugging broken machines), a label maker (god i love that thing), 5 mini pcs used as proxmox hosts, a 24 port unmanaged gigabit switch (behind the pcs) as well as a wifi access point. On the bottom shelf i have the two most powerful proxmox hosts, and free space for future servers (i have a problem).
|
||||||
|
|
||||||
|
If you wish to read in a bit more detail about my homelab, check out [/homelab](/homelab)
|
||||||
|
|
||||||
|
### Fin
|
||||||
|
|
||||||
|
I just wanted to share the excitement i have now, as my homelab always used to be a mess. So i hope i can finally maintain it this time (probably not xD). Thanks for reading!
|
||||||
|
|
||||||
|

|
BIN
src/content/homelab/images/borat-borat-very-nice.gif
Normal file
After Width: | Height: | Size: 7.9 MiB |
BIN
src/content/homelab/images/cable_management.jpg
Normal file
After Width: | Height: | Size: 226 KiB |
BIN
src/content/homelab/images/homelab_revamp.jpg
Normal file
After Width: | Height: | Size: 2.8 MiB |
BIN
src/content/homelab/images/i-have-homelab.webp
Normal file
After Width: | Height: | Size: 28 KiB |
140
src/content/homelab/terraform.md
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
---
|
||||||
|
title: Terraform + Proxmox = <3
|
||||||
|
description: Using Terraform to deploy Virtual Machines
|
||||||
|
pubDate: 09.29.2024
|
||||||
|
---
|
||||||
|
|
||||||
|
## I am tired of UIs
|
||||||
|
|
||||||
|
Up until now, every time i wanted to deploy a VM in my homelab i did it with the Proxmox GUI. Don't get me wrong, the GUI is nice, but i would like to not have to repeat the same mundane task every time i want a new VM.
|
||||||
|
There is an argument to be made that i probably shouldn't run that many VMs, and that for the number of VMs i need, this isn't worth it. However, being able to deploy a VM by just changing a few variables in a file and running `terraform apply` just tickles something in my nerd brain.
|
||||||
|
|
||||||
|
I also really like the repeatability of this, as i use these VM definitions to deploy K3S hosts, docker hosts and others where i want a "default" setup.
|
||||||
|
|
||||||
|
## Initial requirements
|
||||||
|
|
||||||
|
To use Terraform with Proxmox we use a privoder created by [Telmate](https://github.com/Telmate/terraform-provider-proxmox). We create the initial `provider.tf` file as so:
|
||||||
|
```json
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
proxmox = {
|
||||||
|
source = "telmate/proxmox"
|
||||||
|
version = "3.0.1-rc3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_api_url" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_user" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_password" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_public_key" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "proxmox"{
|
||||||
|
pm_api_url = var.proxmox_api_url
|
||||||
|
pm_user = var.proxmox_user
|
||||||
|
pm_password = var.proxmox_password
|
||||||
|
pm_tls_insecure = true
|
||||||
|
pm_otp = ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
I have stored all secrets to access the proxmox API in custom variables located in a `.auto.tfvars` file that i do not track in git. Those variables are defined in the provider such that if they are not present Terraform will complain.
|
||||||
|
|
||||||
|
In this step i had some trouble, as you can see i use a release candidate version. There seems to be a bug in version `2.9.3`, and instead of trying to track it down i just switched to release candidate.
|
||||||
|
|
||||||
|
## Defining the virtual machine
|
||||||
|
|
||||||
|
Now as i mentioned previously, i already have templates created in my proxmox cluster (i made these with Ansible). Therefore i can use these as a base for the provisioning of a new VM.
|
||||||
|
|
||||||
|
Here is an example definition of a VM
|
||||||
|
|
||||||
|
```terraform
|
||||||
|
resource "proxmox_vm_qemu" "havneboks" {
|
||||||
|
name = "havneboks"
|
||||||
|
desc = "Docker master"
|
||||||
|
target_node = "poseidon"
|
||||||
|
|
||||||
|
agent = 1
|
||||||
|
onboot = true
|
||||||
|
|
||||||
|
clone = "VM 9001"
|
||||||
|
cores = 4
|
||||||
|
sockets = 1
|
||||||
|
cpu = "host"
|
||||||
|
memory = 3096
|
||||||
|
|
||||||
|
# Setup the disk
|
||||||
|
disks {
|
||||||
|
ide {
|
||||||
|
ide2 {
|
||||||
|
cloudinit {
|
||||||
|
storage = "basseng"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scsi {
|
||||||
|
scsi0 {
|
||||||
|
disk {
|
||||||
|
size = "10G"
|
||||||
|
storage = "basseng"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
network {
|
||||||
|
bridge = "vmbr0"
|
||||||
|
model = "virtio"
|
||||||
|
}
|
||||||
|
scsihw = "virtio-scsi-pci"
|
||||||
|
os_type = "cloud-init"
|
||||||
|
ipconfig0 = "ip=192.168.1.51/24,gw=192.168.1.1"
|
||||||
|
nameserver = "192.168.1.69"
|
||||||
|
ciuser = "ansible"
|
||||||
|
sshkeys = var.ssh_public_key
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A VM is defined using the resource type of `proxmox_vm_qemu` with a name. I really like to use the names of the service just translated to norwegian, so in this case, this VM is called `havneboks` (meaning docker box).
|
||||||
|
|
||||||
|
- name: The name of the VM (hostname)
|
||||||
|
- desc: A description of the VM
|
||||||
|
- target_node: Which node in the cluster should the VM be provisioned to, in this case i provision it to the node `poseidon`(hostname)
|
||||||
|
- agent: Just select 1
|
||||||
|
- onboot: Set the VM to start when the host boots
|
||||||
|
- clone: Which template to clone the VM from
|
||||||
|
- cores: How much horsepowa u want?
|
||||||
|
- sockets: I only got 1 cpu in each of my boxes
|
||||||
|
- memory: How much RAM u want?
|
||||||
|
|
||||||
|
Now, a really important part of this is the disk setup, as you have to mimic the setup of the template (sizes can be chosen freely). So in my case, i have the cloud-init disk on `ide2` and the OS disk on `scsi0` in the template. Therefore we create the same exact setup for this resource.
|
||||||
|
|
||||||
|
- network: Just mimic the cloud-init
|
||||||
|
- scsihw: Which hardware do you want the host system to use to provide scsi?
|
||||||
|
- os_type: I use cloud-init, so we select cloud-init
|
||||||
|
- ipconfig: Now this is quite interesting, you should set a static IP and gateway such that the VM starts with a proper IP adress (you can also use DHCP here)
|
||||||
|
- namesever: I use a custom dns on adress `.69`(nice) so i set that, but if this is not set it will use "same as host"
|
||||||
|
- ciuser: A user to be created by cloud-init for this VM
|
||||||
|
- sshkeys: Initial SSH public keys to allow access. This is stored in a variable in my case.
|
||||||
|
|
||||||
|
## Just run?
|
||||||
|
|
||||||
|
Bing bang bom. You can now deploy your VM fully automatically and about 43 seconds later access it via SSH. Now all i did was configure it with ansible, and i have a fully reproducible homelab setup.
|
||||||
|
|
||||||
|
If you want to have a look at my homelab infrastructure as code repo, you can find it at [polsevev/homelab](https://github.com/polsevev/homelab)
|
||||||
|
|
||||||
|

|
|
@ -4,4 +4,41 @@ description: Setting up my own CI with Woodpecker!
|
||||||
pubDate: 08.03.2024
|
pubDate: 08.03.2024
|
||||||
---
|
---
|
||||||
|
|
||||||
I am currently working on setting opp Woodpecker as my CI. Will write a post about this here :)
|
## Self hosted CI/CD!
|
||||||
|
|
||||||
|
Yesterday, i decided that i was tired of using Github Actions to deploy my code from Github. So i decided to self host my own CI/CD. This is mostly because i am not comfortable having port 22 on my web server be publicly accessible on the internet.
|
||||||
|
|
||||||
|
To do this, i went down quite the rabbit hole. First i looked at [TeamCity](https://www.jetbrains.com/teamcity/) from JetBrains as this is what i use at work. It looked promising, however i decided it was too complex and had too many features i did not really care about.
|
||||||
|
|
||||||
|
Then i stumbled across [Drone](https://www.drone.io/), which seemed to fit my use-case. However it has since gotten very corporate when it was bought up, so i decided to go with the open source fork called [Woodpecker](https://woodpecker-ci.org/)
|
||||||
|
|
||||||
|
This turned out to be a bit of a bigger challenge than i first thought, but i somehow got it up and running in the end. Follow along!
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
This was by far the easiest. As i have not gotten around to setting up my Kubernetes cluster yet, and i wanted to start of simple. I just used the docker compose provided by the Woodpecker team.
|
||||||
|
|
||||||
|
To provide integration with Github, i use a github Oauth2 App i made in the github UI, this is very well explained in the documentation of Woodpecker.
|
||||||
|
|
||||||
|
Now that i have configured the docker compose, i created a VM on [cronus](/homelab/servers/oceanus) and deployed the compose file using Ansible.
|
||||||
|
|
||||||
|
### Setting up a pipeline
|
||||||
|
|
||||||
|
Writing the pipeline was simple enough, as it has a very similar syntax to Github actions. However, i needed a docker image for the pipeline to run in. This actually turned out to be a challenge, as i currently do not have a docker registry in my homelab (i will be setting up Gitea in the future dw).
|
||||||
|
|
||||||
|
To solve the docker registry problem, i decided to simply build the image locally on the server. Ansible comes to the rescue again. I wrote a simple playbook that builds the docker image on the VM such that it is available to Woodpecker. Missing registry problem solved!
|
||||||
|
|
||||||
|
Now finally, i could make my own image that had all the dependencies for this website!
|
||||||
|
|
||||||
|
We were not out of the woods yet however, i still had to figure out how i wanted to transfer the files to the server they will be hosted on. Previously i had used rsync to transfer them into a directory on my web server, and i decided to do something similar this time.
|
||||||
|
|
||||||
|
However, since i did not want to put the SSH keys into the docker image.
|
||||||
|
So i ended up adding a private ssh key into the secret store of Woodpecker. This allows rsync to communicate with my web server.
|
||||||
|
|
||||||
|
This meant i have to distribute the public key to the web server beforehand, ansible saved the day again.
|
||||||
|
|
||||||
|
### Pipeline finished
|
||||||
|
|
||||||
|
Finally, i could deploy this very website, using woodpecker to my own web server, all without exposing port 22 on the web server to the internet.
|
||||||
|
|
||||||
|

|
|
@ -11,7 +11,7 @@ Oceanus is my main VM server. It used to be an office PC, but has since been re-
|
||||||
|
|
||||||
- MODEL: HP Elitedesk 600 G3
|
- MODEL: HP Elitedesk 600 G3
|
||||||
- CPU: i7 6700
|
- CPU: i7 6700
|
||||||
- RAM: 16 GB DDR4
|
- RAM: 32 GB DDR4
|
||||||
- Storage:
|
- Storage:
|
||||||
- 256 GB NVME SSD
|
- 256 GB NVME SSD
|
||||||
- 128 GB SATA SSD
|
- 128 GB SATA SSD
|
||||||
|
@ -20,15 +20,10 @@ Oceanus is my main VM server. It used to be an office PC, but has since been re-
|
||||||
|
|
||||||
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.
|
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
|
- Opnsense
|
||||||
- HAproxy load-balancer
|
- This server currently runs my firewall, which i have behind the ISP router using DMZ to not have double NAT (even though is technically still is double NAT)
|
||||||
- nginx-public
|
- Game servers
|
||||||
- Temporary NGINX until i get K3S up and running
|
- I run Factorio and Feed the Beast servers on this machine
|
||||||
- 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
|
|
||||||
|
|
||||||

|
|
||||||
|

|
|
@ -24,4 +24,4 @@ This server is running proxmox at the moment, to allow for virtualization of all
|
||||||
- k3s_worker
|
- k3s_worker
|
||||||
- Worker in my K3S cluster
|
- Worker in my K3S cluster
|
||||||
|
|
||||||

|

|
|
@ -2,9 +2,10 @@
|
||||||
title: 'Hades'
|
title: 'Hades'
|
||||||
lastUpdated: '03.08.2024'
|
lastUpdated: '03.08.2024'
|
||||||
---
|
---
|
||||||
|
## What is it?
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
## Specs
|
||||||
- MODEL: HP Elitedesk 705 G3 mini
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
- CPU: AMD A10-8770E
|
- CPU: AMD A10-8770E
|
||||||
- RAM: 16 GB DDR4
|
- RAM: 16 GB DDR4
|
||||||
|
@ -21,4 +22,4 @@ This server is running proxmox at the moment, to allow for virtualization of all
|
||||||
- k3s_worker
|
- k3s_worker
|
||||||
- Worker in my K3S cluster
|
- Worker in my K3S cluster
|
||||||
|
|
||||||

|

|
|
@ -2,9 +2,9 @@
|
||||||
title: 'Hermes'
|
title: 'Hermes'
|
||||||
lastUpdated: '03.08.2024'
|
lastUpdated: '03.08.2024'
|
||||||
---
|
---
|
||||||
|
## What is it?
|
||||||
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.
|
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.
|
||||||
|
## Specs
|
||||||
- MODEL: HP Elitedesk 705 G3 mini
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
- CPU: AMD A10-8770E
|
- CPU: AMD A10-8770E
|
||||||
- RAM: 16 GB DDR4
|
- RAM: 16 GB DDR4
|
||||||
|
@ -21,4 +21,4 @@ This server is running proxmox at the moment, to allow for virtualization of all
|
||||||
- k3s_worker
|
- k3s_worker
|
||||||
- Worker in my K3S cluster
|
- Worker in my K3S cluster
|
||||||
|
|
||||||

|

|
23
src/content/servers/hyperion.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
title: 'Hyperion'
|
||||||
|
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: i5 6500
|
||||||
|
- RAM: 16 GB DDR4
|
||||||
|
- Storage:
|
||||||
|
- 256 GB NVME SSD
|
||||||
|
- 128 GB SATA SSD
|
||||||
|
|
||||||
|
## What is on it?
|
||||||
|
|
||||||
|
This is one of the more powerful nodes in my Proxmox cluster. Mostly used for decent CPU performance tasks.
|
||||||
|
|
||||||
|

|
BIN
src/content/servers/images/cluster.jpg
Normal file
After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 717 KiB |
BIN
src/content/servers/images/elitedesk_800.jpg
Normal file
After Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 542 KiB |
|
@ -2,9 +2,9 @@
|
||||||
title: 'Poseidon'
|
title: 'Poseidon'
|
||||||
lastUpdated: '03.08.2024'
|
lastUpdated: '03.08.2024'
|
||||||
---
|
---
|
||||||
|
## What is it?
|
||||||
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.
|
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.
|
||||||
|
## Specs
|
||||||
- MODEL: HP Elitedesk 705 G3 mini
|
- MODEL: HP Elitedesk 705 G3 mini
|
||||||
- CPU: AMD A10-8770E
|
- CPU: AMD A10-8770E
|
||||||
- RAM: 16 GB DDR4
|
- RAM: 16 GB DDR4
|
||||||
|
@ -21,4 +21,4 @@ This server is running proxmox at the moment, to allow for virtualization of all
|
||||||
- k3s_worker
|
- k3s_worker
|
||||||
- Worker in my K3S cluster
|
- Worker in my K3S cluster
|
||||||
|
|
||||||

|

|
|
@ -22,4 +22,4 @@ This server is running proxmox at the moment, to allow for virtualization of all
|
||||||
- k3s_worker
|
- k3s_worker
|
||||||
- Worker in my K3S cluster
|
- Worker in my K3S cluster
|
||||||
|
|
||||||

|

|
|
@ -42,6 +42,9 @@ const { title, description, pubDate, updatedDate} = Astro.props;
|
||||||
.last-updated-on {
|
.last-updated-on {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
img{
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@ import Layout from "../layouts/BlogPost.astro";
|
||||||
description="Lorem ipsum dolor sit amet"
|
description="Lorem ipsum dolor sit amet"
|
||||||
pubDate={new Date("08.02.2024")}
|
pubDate={new Date("08.02.2024")}
|
||||||
>
|
>
|
||||||
<p>Hi!</p><p>
|
<p>Hi!</p>
|
||||||
This intoduction thing is not really my style, but first of all my name is
|
<p>
|
||||||
Rolf.
|
My name is Rolf, i am 2024-2000 years old and live in Norway.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
I currently work as a devops engineer / infrastructure guy. As you probably can tell from this website, front-end is not really my strong suit hehe.
|
I currently work as a devops engineer / infrastructure guy for an insurance company. As you probably can tell from this website, front-end is not really my strong suit hehe.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
I have a strong love for all things self-hosted. Due to this, i currently run my own "little" homelab from my living room, i use this lab as a learning platform and just an all around
|
I have a strong love for all things self-hosted. Due to this, i currently run my own "little" homelab from my living room, i use this lab as a learning platform and just an all around
|
||||||
|
@ -21,4 +21,8 @@ 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 also spend a lot of my time as a member of the student organization <a href="https://fribyte.no">friByte</a>. Even though i am no longer a student, it is hard to quit an orginization with so many dedicated
|
||||||
|
and nerdy members
|
||||||
|
</p>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -7,7 +7,10 @@ import { getCollection } from 'astro:content';
|
||||||
import FormattedDate from '../../components/FormattedDate.astro';
|
import FormattedDate from '../../components/FormattedDate.astro';
|
||||||
|
|
||||||
const posts = (await getCollection('blog')).sort(
|
const posts = (await getCollection('blog')).sort(
|
||||||
(a, b) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
|
(b, a) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
|
||||||
|
);
|
||||||
|
const homelab_posts = (await getCollection('homelab')).sort(
|
||||||
|
(b, a) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -54,12 +57,12 @@ const posts = (await getCollection('blog')).sort(
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgb(var(--black));
|
color: rgb(0,255,159);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
.date {
|
.date {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgb(var(--gray));
|
color: rgb(white);
|
||||||
}
|
}
|
||||||
ul li a:hover h4,
|
ul li a:hover h4,
|
||||||
ul li a:hover .date {
|
ul li a:hover .date {
|
||||||
|
@ -83,11 +86,22 @@ const posts = (await getCollection('blog')).sort(
|
||||||
font-size: 1.563em;
|
font-size: 1.563em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
blogheader {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<Header />
|
<Header />
|
||||||
<main>
|
<main>
|
||||||
|
<blogheader>
|
||||||
|
<h1>Blog</h1>
|
||||||
|
<p>
|
||||||
|
This page contains a blog about nothing and everything going on with me.
|
||||||
|
I will probably post mostly random stuff or opinion pieces. What it will be about i have no idea.
|
||||||
|
So stay tuned!
|
||||||
|
</p>
|
||||||
|
</blogheader>
|
||||||
<section>
|
<section>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
|
@ -102,6 +116,16 @@ const posts = (await getCollection('blog')).sort(
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
{ homelab_posts.map((post) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/homelab/${post.slug}/`}>
|
||||||
|
<h4 class="title">{post.data.title}</h4>
|
||||||
|
<p class="date">
|
||||||
|
<FormattedDate date={post.data.pubDate} />
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -8,9 +8,7 @@ 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'));
|
const servers = (await getCollection('servers'));
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -20,31 +18,9 @@ const servers = (await getCollection('servers'));
|
||||||
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
<style>
|
<style>
|
||||||
main {
|
main {
|
||||||
width: 100%;
|
width: 960px;
|
||||||
}
|
|
||||||
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 {
|
.title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgb(0,255,159);
|
color: rgb(0,255,159);
|
||||||
|
@ -54,51 +30,18 @@ const servers = (await getCollection('servers'));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: rgb(var(--gray));
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
site_header{
|
site_header{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
left{
|
|
||||||
width: 75%;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
right{
|
|
||||||
width: 25%;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#column{
|
|
||||||
float:left;
|
|
||||||
}
|
|
||||||
box{
|
box{
|
||||||
display: flex;
|
text-align: center;
|
||||||
}
|
|
||||||
box left,right{
|
|
||||||
border-color: white;
|
|
||||||
border-width: 0.2em;
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 1em;
|
|
||||||
margin: 0.2em;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -107,11 +50,9 @@ const servers = (await getCollection('servers'));
|
||||||
<Header />
|
<Header />
|
||||||
<main>
|
<main>
|
||||||
<site_header>
|
<site_header>
|
||||||
<h2>All bout the homelab!</h2>
|
<h2>What is in my homelab now?</h2>
|
||||||
</site_header>
|
</site_header>
|
||||||
<box>
|
<box>
|
||||||
<left class="column">
|
|
||||||
<h3>What is in my homelab now?</h3>
|
|
||||||
<p>
|
<p>
|
||||||
So my current homelab has gotten quite extensive, which honestly is a pain because electricity is expensive as hell.
|
So my current homelab has gotten quite extensive, which honestly is a pain because electricity is expensive as hell.
|
||||||
</p>
|
</p>
|
||||||
|
@ -120,43 +61,15 @@ const servers = (await getCollection('servers'));
|
||||||
let me explain each server, and what it is currently being used for.
|
let me explain each server, and what it is currently being used for.
|
||||||
</p>
|
</p>
|
||||||
<p>As you can probably tell, i use greek mythology for the naming scheme of physical machines :P</p>
|
<p>As you can probably tell, i use greek mythology for the naming scheme of physical machines :P</p>
|
||||||
<section>
|
<box>
|
||||||
<ul>
|
|
||||||
{
|
{
|
||||||
servers.map((s) => (
|
servers.map((s) => (
|
||||||
<li>
|
|
||||||
<a href={`/homelab/servers/${s.slug}/`}>
|
<a href={`/homelab/servers/${s.slug}/`}>
|
||||||
<h5 class="title">🖥️ {s.data.title}</h5>
|
<h5 class="title">🖥️ {s.data.title}</h5>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</box>
|
||||||
</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>
|
</box>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -1,22 +1,63 @@
|
||||||
---
|
---
|
||||||
import BaseHead from '../components/BaseHead.astro';
|
import BaseHead from "../components/BaseHead.astro";
|
||||||
import Header from '../components/Header.astro';
|
import Header from "../components/Header.astro";
|
||||||
import Footer from '../components/Footer.astro';
|
import Footer from "../components/Footer.astro";
|
||||||
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
import { SITE_TITLE, SITE_DESCRIPTION } from "../consts";
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
}
|
||||||
|
main left,
|
||||||
|
right {
|
||||||
|
margin: 0.2em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
left {
|
||||||
|
max-width: 600px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
right {
|
||||||
|
max-width: 400px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
box {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
p{
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<h1>Yo! Welcome to my humble site</h1>
|
<h1>Rolf Glomsrud</h1>
|
||||||
<p>
|
<img src="images/self.png" />
|
||||||
This site is a continual WIP, and this is just an alpha of what i hope it will become :)
|
|
||||||
</p>
|
<h3>Hello!</h3>
|
||||||
|
<p>Welcome to my little corner of the interwebs, glad to have you!</p>
|
||||||
|
|
||||||
|
<p>This site is a little project of mine where is hope to share my adventures both on and off line.</p>
|
||||||
|
|
||||||
|
<p>Here are some useful links to my stuff:</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p>I self host my code online using Forgejo! <a href="https://code.polsevev.dev">code.polsevev.dev</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p>I document my homelab! <a href="/homelab">/homelab</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
||||||
|
|
||||||
export async function GET(context) {
|
export async function GET(context) {
|
||||||
const posts = await getCollection('blog');
|
const posts = await getCollection('blog');
|
||||||
|
const homelab = await getCollection('homelab');
|
||||||
return rss({
|
return rss({
|
||||||
title: SITE_TITLE,
|
title: SITE_TITLE,
|
||||||
description: SITE_DESCRIPTION,
|
description: SITE_DESCRIPTION,
|
||||||
|
@ -11,6 +12,9 @@ export async function GET(context) {
|
||||||
items: posts.map((post) => ({
|
items: posts.map((post) => ({
|
||||||
...post.data,
|
...post.data,
|
||||||
link: `/blog/${post.slug}/`,
|
link: `/blog/${post.slug}/`,
|
||||||
})),
|
})).concat(homelab.map((post) => ({
|
||||||
|
...post.data,
|
||||||
|
link: `/homelab/${post.slug}`
|
||||||
|
}))),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,22 +30,19 @@
|
||||||
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;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: repeating-linear-gradient(to bottom, #522258 0%, #8c3061, #522258 100%);
|
background: repeating-linear-gradient(to bottom, #522258 0%, #8c3061, #522258 100%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
color: cyan;
|
color: cyan;
|
||||||
|
@ -54,7 +51,7 @@ body {
|
||||||
}
|
}
|
||||||
@media screen and (min-width:600px) {
|
@media screen and (min-width:600px) {
|
||||||
body {
|
body {
|
||||||
width: 80%;
|
width: 95%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width:600px){
|
@media screen and (max-width:600px){
|
||||||
|
@ -63,12 +60,13 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
|
flex: 1;
|
||||||
width: 720px;
|
width: 720px;
|
||||||
max-width: calc(100% - 2em);
|
max-width: calc(100% - 2em);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: 3em 1em;
|
padding: 1em 1em;
|
||||||
margin-bottom: -4em;
|
margin-bottom: -2em;
|
||||||
}
|
}
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
|
@ -100,10 +98,10 @@ b {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: var(--accent);
|
color: white;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover {
|
||||||
color: var(--accent);
|
color: black;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
@ -128,8 +126,8 @@ img {
|
||||||
}
|
}
|
||||||
code {
|
code {
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
background-color: rgb(var(--gray-light));
|
background-color: black;
|
||||||
border-radius: 2px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
|
|