diff --git a/package.json b/package.json
index 3c26b13..04e5409 100644
--- a/package.json
+++ b/package.json
@@ -20,8 +20,10 @@
"@fontsource/ibm-plex-mono": "^5.2.5",
"@resvg/resvg-js": "^2.6.2",
"@tailwindcss/vite": "^4.0.12",
+ "@types/sanitize-html": "^2.13.0",
"astro": "^5.4.2",
"lodash.kebabcase": "^4.1.1",
+ "markdown-it": "^14.1.0",
"remark-collapse": "^0.1.2",
"remark-toc": "^9.0.0",
"satori": "^0.12.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d7d30b8..ad81fca 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -29,12 +29,18 @@ importers:
'@tailwindcss/vite':
specifier: ^4.0.12
version: 4.0.12(vite@6.2.1(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))
+ '@types/sanitize-html':
+ specifier: ^2.13.0
+ version: 2.13.0
astro:
specifier: ^5.4.2
version: 5.4.2(jiti@2.4.2)(lightningcss@1.29.2)(rollup@4.35.0)(typescript@5.8.2)(yaml@2.7.0)
lodash.kebabcase:
specifier: ^4.1.1
version: 4.1.1
+ markdown-it:
+ specifier: ^14.1.0
+ version: 14.1.0
remark-collapse:
specifier: ^0.1.2
version: 0.1.2
@@ -875,6 +881,9 @@ packages:
'@types/node@17.0.45':
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
+ '@types/sanitize-html@2.13.0':
+ resolution: {integrity: sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==}
+
'@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
@@ -1217,6 +1226,19 @@ packages:
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
dset@3.1.4:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'}
@@ -1496,6 +1518,9 @@ packages:
html-void-elements@3.0.0:
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+ htmlparser2@8.0.2:
+ resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+
http-cache-semantics@4.1.1:
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
@@ -1669,6 +1694,9 @@ packages:
linebreak@1.1.0:
resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
+ linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+
load-yaml-file@0.2.0:
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
engines: {node: '>=6'}
@@ -1708,6 +1736,10 @@ packages:
magicast@0.3.5:
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+ markdown-it@14.1.0:
+ resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
+ hasBin: true
+
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
@@ -1759,6 +1791,9 @@ packages:
mdast-util-toc@7.1.0:
resolution: {integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==}
+ mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -2091,6 +2126,10 @@ packages:
property-information@7.0.0:
resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
+ punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -2367,6 +2406,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+
ufo@1.5.4:
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
@@ -3379,6 +3421,10 @@ snapshots:
'@types/node@17.0.45': {}
+ '@types/sanitize-html@2.13.0':
+ dependencies:
+ htmlparser2: 8.0.2
+
'@types/sax@1.2.7':
dependencies:
'@types/node': 17.0.45
@@ -3841,6 +3887,24 @@ snapshots:
dlv@1.1.3: {}
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
dset@3.1.4: {}
emmet@2.4.11:
@@ -4199,6 +4263,13 @@ snapshots:
html-void-elements@3.0.0: {}
+ htmlparser2@8.0.2:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ entities: 4.5.0
+
http-cache-semantics@4.1.1: {}
ignore@5.3.2: {}
@@ -4326,6 +4397,10 @@ snapshots:
base64-js: 0.0.8
unicode-trie: 2.0.0
+ linkify-it@5.0.0:
+ dependencies:
+ uc.micro: 2.1.0
+
load-yaml-file@0.2.0:
dependencies:
graceful-fs: 4.2.11
@@ -4365,6 +4440,15 @@ snapshots:
'@babel/types': 7.26.9
source-map-js: 1.2.1
+ markdown-it@14.1.0:
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+
markdown-table@3.0.4: {}
mdast-util-definitions@6.0.0:
@@ -4503,6 +4587,8 @@ snapshots:
unist-util-is: 6.0.0
unist-util-visit: 5.0.0
+ mdurl@2.0.0: {}
+
merge2@1.4.1: {}
micromark-core-commonmark@2.0.3:
@@ -4885,6 +4971,8 @@ snapshots:
property-information@7.0.0: {}
+ punycode.js@2.3.1: {}
+
punycode@2.3.1: {}
queue-microtask@1.2.3: {}
@@ -5237,6 +5325,8 @@ snapshots:
typescript@5.8.2: {}
+ uc.micro@2.1.0: {}
+
ufo@1.5.4: {}
ultrahtml@1.5.3: {}
diff --git a/src/data/blog/create-your-own-github-alt.md b/src/data/blog/create-your-own-github-alt.md
index da98923..c565f4e 100644
--- a/src/data/blog/create-your-own-github-alt.md
+++ b/src/data/blog/create-your-own-github-alt.md
@@ -1,13 +1,18 @@
---
-pubDatetime: 2025-03-20
-title: "Create your own GitHub alternative with Gitea and Forgejo"
+pubDatetime: 2025-03-21
+title: "Create your own GitHub alternative with Gitea, Opengist, and Forgejo"
description: Then you can deploy your apps and websites with Coolify on a cheap VPS. Easy peasy lemon squeezy.
featured: true
-draft: true
tags:
- selfhosting
- coolify
- github
- forgejo
- gitea
+ - opengist
+ - pikapods
---
+
+## Opengist example
+
+
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index cbdb83e..a9679c7 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -108,6 +108,10 @@ const structuredData = {
set:html={JSON.stringify(structuredData)}
/>
+
({
+ items: sortedPosts.map(({ data, id, rendered }) => ({
+ content: globalImageUrls(
+ SITE.website,
+ sanitizeHtml(rendered?.html, {
+ allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
+ }),
+ ),
link: `posts/${id}/`,
title: data.title,
description: data.description,