Add 300 and update CSS for better code
This commit is contained in:
parent
fbd05a21af
commit
f7b73bc2ff
10 changed files with 276 additions and 24 deletions
136
blog/300.html
Normal file
136
blog/300.html
Normal file
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta content="width=device-width, initial-scale=1" charset="utf-8" />
|
||||
<link rel="icon" href="/assets/askiiart.gif" type="image/icon">
|
||||
<title>300</title>
|
||||
<link href="/style.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/prism.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="line-numbers">
|
||||
<h1 id="section">300</h1>
|
||||
<p>No, not the movie. I'm a nerd who's spent half their day so
|
||||
far configuring nginx, it should be obvious at this point.</p>
|
||||
<hr />
|
||||
<p>Since I have my code 1) <a
|
||||
href="https://git.askiiart.net/askiiart/askiiart-net">on my
|
||||
self-hosted Gitea (soon Forgejo) instance</a>, and 2) <a
|
||||
href="https://github.com/askiiart/askiiart.github.io">mirrored</a>
|
||||
on GitHub, I didn't just want to set up a simple <a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308">308
|
||||
Permanent Redirect</a> from <a href="/.git">/.git</a> to my code
|
||||
in one place. I wanted users to be able to see both options,
|
||||
both Gitea and GitHub, and apparently there's actually a thing
|
||||
for that already, I can just use that!</p>
|
||||
<h2 id="ok-but-how">ok but how?</h2>
|
||||
<p>300 seems great, but there's no standardized way to use it.
|
||||
The number, and the <code>Location</code> header as the
|
||||
preferred choice is all that's actually standardized. Straight
|
||||
from <a
|
||||
href="https://httpwg.org/specs/rfc9110.html#status.300">RFC
|
||||
9110</a>:</p>
|
||||
<blockquote>
|
||||
<p>If the server has a preferred choice, the server
|
||||
<em>SHOULD</em> generate a Location header field containing a
|
||||
preferred choice's URI reference. The user agent MAY use the
|
||||
Location field value for automatic redirection.</p>
|
||||
<p>For request methods other than HEAD, the server
|
||||
<em>SHOULD</em> generate content in the 300 response containing
|
||||
a list of representation metadata and URI reference(s) from
|
||||
which the user or user agent can choose the one most
|
||||
preferred.</p>
|
||||
</blockquote>
|
||||
<p>Does this mean to return some HTML? A JSON dict? YAML? An
|
||||
image of a pickle with that info overlaid on top of it!?
|
||||
<em>Nobody knows!</em> And from the Mozilla docs:</p>
|
||||
<blockquote>
|
||||
<p>As there is no standardized way of choosing one of the
|
||||
responses, this response code is very rarely used.</p>
|
||||
</blockquote>
|
||||
<p>Very helpful.</p>
|
||||
<h2 id="ok-but-actually-how">ok but actually how?</h2>
|
||||
<p>After a bit of Googling, I found <a
|
||||
href="https://stackoverflow.com/questions/8905545/what-is-the-exact-response-structure-for-http-status-code-300-multiple-choices">this
|
||||
Stack Overflow thread</a>, which just says
|
||||
this<sup>[<a href="#browser-specific-info">note</a>]</sup>:</p>
|
||||
<blockquote>
|
||||
<p>The "multiple choices" are done by sending the links in
|
||||
hypertext (HTML) content and let the <em>user</em> pick.</p>
|
||||
</blockquote>
|
||||
<p>Well, that's boring. Guess I'll do that then.</p>
|
||||
<pre class="language-nginx"><code> location /.git {
|
||||
add_header Location "https://git.askiiart.net/askiiart/askiiart-net";
|
||||
return 300 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
}</code></pre>
|
||||
<h2 id="nginx-is-hard">nginx is hard</h2>
|
||||
<p>That config looks fine, right? It just sets the
|
||||
<code>Location</code> header and returns this basic menu to pick
|
||||
from. But it won't open in any browsers, Firefox displays
|
||||
nothing, and has <code>NS_ERROR_WONT_HANDLE_CONTENT</code> in
|
||||
the developer tools, and Chrome shows a
|
||||
<code>ERR_INVALID_RESPONSE</code> error. Running
|
||||
<code>curl -I https://askiiart.net</code>, and...</p>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="language-sh"><code class="language-bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">HTTP/1.1</span> 300 </span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">Server:</span> nginx/1.25.3</span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Date:</span> Wed, 06 Dec 2023 16:36:01 GMT</span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">Content-Type:</span> application/octet-stream</span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ex">Content-Length:</span> 223</span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ex">Connection:</span> keep-alive</span></code></pre></div>
|
||||
<p>There's no Location header there! And the browsers are
|
||||
probably refusing to show it because of the wrong
|
||||
<code>Content-Type</code>—and no, adding a header with
|
||||
<code>add_header</code> doesn't work for that one, either.</p>
|
||||
<p>Turns out in order to be able to use <code>add_header</code>,
|
||||
you first need to set <code>default_type</code> (which sets a
|
||||
default <code>Content-Type</code>). I could've set that in the
|
||||
<code>location /.git</code> block, but I just decided to make it
|
||||
global.</p>
|
||||
<p>So here's the fixed config:</p>
|
||||
<pre class="language-nginx"><code> # actually much higher in file
|
||||
default_type "text/html";
|
||||
|
||||
location /.git {
|
||||
add_header Location "https://git.askiiart.net/askiiart/askiiart-net";
|
||||
return 300 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
}</code></pre>
|
||||
<p>Yep, that works! I had set up my IP address pages the same
|
||||
way, so let's fix that:</p>
|
||||
<pre class="language-nginx"><code> location /ip {
|
||||
default_type text/plain;
|
||||
return 200 "$remote_addr";
|
||||
}
|
||||
|
||||
location /ip/json {
|
||||
default_type application/json;
|
||||
return 200 '{"ip":"$remote_addr"}';
|
||||
}</code></pre>
|
||||
<p>These still don't work, they just return my reverse proxy
|
||||
container's gateway's address, but that's for another time.</p>
|
||||
<h2 id="open-your-eyes...-wake-up-link">Open your eyes... wake
|
||||
up, <em>Link</em></h2>
|
||||
<p>Turns out might be a standard way to do it! From <a
|
||||
href="https://httpwg.org/specs/rfc9110.html#status.300">RFC
|
||||
9110</a>, again:</p>
|
||||
<blockquote>
|
||||
<p>It is possible to communicate the list using a set of Link
|
||||
header fields <a
|
||||
href="https://httpwg.org/specs/rfc9110.html#RFC8288">RFC5988</a>,
|
||||
each with a relationship of "alternate", though deployment is a
|
||||
chicken-and-egg problem.</p>
|
||||
</blockquote>
|
||||
<p>I'll probably figure out the <code>Link</code> header some
|
||||
other time and will add this later, at which point I'll post an
|
||||
addendum. Until then, bye I guess!</p>
|
||||
<h2 id="footnotes-and-stuff">Footnotes and stuff</h2>
|
||||
<h4 id="browser-specific-info">browser-specific info</h4>
|
||||
<p>Elsewhere in the Quora thread it says, in short, that Firefox
|
||||
and Chrome just displays the HTML, and Safari will follow the
|
||||
<code>Location</code> header. [<a
|
||||
href="#ok-but-actually-how">Back</a>]</p>
|
||||
<script src="/prism.js"></script>
|
||||
</body>
|
||||
<footer>
|
||||
<p><a href="https://git.askiiart.net/askiiart/askiiart-net">code</a> (<a href="https://github.com/askiiart/askiiart.github.io">mirror</a>) <a href="/feed.xml">rss</a> <a href="/pubkey.asc">pubkey</a></p>
|
||||
</footer>
|
||||
</html>
|
95
blog/300.md
Normal file
95
blog/300.md
Normal file
|
@ -0,0 +1,95 @@
|
|||
# 300
|
||||
|
||||
No, not the movie. I'm a nerd who's spent half their day so far configuring nginx, it should be obvious at this point.
|
||||
|
||||
---
|
||||
|
||||
Since I have my code 1) [on my self-hosted Gitea (soon Forgejo) instance](https://git.askiiart.net/askiiart/askiiart-net), and 2) [mirrored](https://github.com/askiiart/askiiart.github.io) on GitHub, I didn't just want to set up a simple [308 Permanent Redirect](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308) from [/.git](/.git) to my code in one place. I wanted users to be able to see both options, both Gitea and GitHub, and apparently there's actually a thing for that already, I can just use that!
|
||||
|
||||
## ok but how?
|
||||
|
||||
300 seems great, but there's no standardized way to use it. The number, and the `Location` header as the preferred choice is all that's actually standardized. Straight from [RFC 9110](https://httpwg.org/specs/rfc9110.html#status.300):
|
||||
|
||||
> If the server has a preferred choice, the server *SHOULD* generate a Location header field containing a preferred choice's URI reference. The user agent MAY use the Location field value for automatic redirection.
|
||||
>
|
||||
> For request methods other than HEAD, the server *SHOULD* generate content in the 300 response containing a list of representation metadata and URI reference(s) from which the user or user agent can choose the one most preferred.
|
||||
|
||||
Does this mean to return some HTML? A JSON dict? YAML? An image of a pickle with that info overlaid on top of it!? *Nobody knows!* And from the Mozilla docs:
|
||||
|
||||
> As there is no standardized way of choosing one of the responses, this response code is very rarely used.
|
||||
|
||||
Very helpful.
|
||||
|
||||
## ok but actually how?
|
||||
|
||||
After a bit of Googling, I found [this Stack Overflow thread](https://stackoverflow.com/questions/8905545/what-is-the-exact-response-structure-for-http-status-code-300-multiple-choices), which just says this<sup>[<a href="#browser-specific-info">note</a>]</sup>:
|
||||
|
||||
> The "multiple choices" are done by sending the links in hypertext (HTML) content and let the *user* pick.
|
||||
|
||||
Well, that's boring. Guess I'll do that then.
|
||||
|
||||
```language-nginx
|
||||
location /.git {
|
||||
add_header Location "https://git.askiiart.net/askiiart/askiiart-net";
|
||||
return 300 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
}
|
||||
```
|
||||
|
||||
## nginx is hard
|
||||
|
||||
That config looks fine, right? It just sets the `Location` header and returns this basic menu to pick from. But it won't open in any browsers, Firefox displays nothing, and has `NS_ERROR_WONT_HANDLE_CONTENT` in the developer tools, and Chrome shows a `ERR_INVALID_RESPONSE` error. Running `curl -I https://askiiart.net`, and...
|
||||
|
||||
```sh
|
||||
HTTP/1.1 300
|
||||
Server: nginx/1.25.3
|
||||
Date: Wed, 06 Dec 2023 16:36:01 GMT
|
||||
Content-Type: application/octet-stream
|
||||
Content-Length: 223
|
||||
Connection: keep-alive
|
||||
```
|
||||
|
||||
There's no Location header there! And the browsers are probably refusing to show it because of the wrong `Content-Type`—and no, adding a header with `add_header` doesn't work for that one, either.
|
||||
|
||||
Turns out in order to be able to use `add_header`, you first need to set `default_type` (which sets a default `Content-Type`). I could've set that in the `location /.git` block, but I just decided to make it global.
|
||||
|
||||
So here's the fixed config:
|
||||
|
||||
```language-nginx
|
||||
# actually much higher in file
|
||||
default_type "text/html";
|
||||
|
||||
location /.git {
|
||||
add_header Location "https://git.askiiart.net/askiiart/askiiart-net";
|
||||
return 300 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
}
|
||||
```
|
||||
|
||||
Yep, that works! I had set up my IP address pages the same way, so let's fix that:
|
||||
|
||||
```language-nginx
|
||||
location /ip {
|
||||
default_type text/plain;
|
||||
return 200 "$remote_addr";
|
||||
}
|
||||
|
||||
location /ip/json {
|
||||
default_type application/json;
|
||||
return 200 '{"ip":"$remote_addr"}';
|
||||
}
|
||||
```
|
||||
|
||||
These still don't work, they just return my reverse proxy container's gateway's address, but that's for another time.
|
||||
|
||||
## Open your eyes... wake up, *Link*
|
||||
|
||||
Turns out might be a standard way to do it! From [RFC 9110](https://httpwg.org/specs/rfc9110.html#status.300), again:
|
||||
|
||||
> It is possible to communicate the list using a set of Link header fields [RFC5988](https://httpwg.org/specs/rfc9110.html#RFC8288), each with a relationship of "alternate", though deployment is a chicken-and-egg problem.
|
||||
|
||||
I'll probably figure out the `Link` header some other time and will add this later, at which point I'll post an addendum. Until then, bye I guess!
|
||||
|
||||
## Footnotes and stuff
|
||||
|
||||
#### browser-specific info
|
||||
|
||||
Elsewhere in the Quora thread it says, in short, that Firefox and Chrome just displays the HTML, and Safari will follow the `Location` header. \[[Back](#ok-but-actually-how)\]
|
|
@ -5,11 +5,15 @@
|
|||
<title>askiiart.net blog</title>
|
||||
<description>The feed for askiiart.net but just the blog, I guess</description>
|
||||
<link>https://askiiart.net/blog/</link>
|
||||
<lastBuildDate>Sun, 19 Nov 2023 23:10:34 +0000</lastBuildDate>
|
||||
<lastBuildDate>Wed, 06 Dec 2023 17:42:13 +0000</lastBuildDate>
|
||||
<item>
|
||||
<title>Marlin Boot Animations</title>
|
||||
<link>https://askiiart.net/til/marlin-boot-animations.html</link>
|
||||
</item>
|
||||
<item>
|
||||
<title>300</title>
|
||||
<link>https://askiiart.net/til/300.html</link>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
|
@ -116,7 +116,7 @@ server {
|
|||
# There is no standard way to present options, but in the rare cases that 300 is used it just has a list of links. The Location header is for preferred thing.
|
||||
default_type "text/html";
|
||||
add_header Location "https://git.askiiart.net/askiiart/askiiart-net";
|
||||
return 200 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
return 300 '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body><a href="https://git.askiiart.net/askiiart/askiiart-net">Self-hosted</a><br><a href="https://github.com/askiiart/askiiart-net">GitHub</a></body></html>';
|
||||
}
|
||||
|
||||
error_page 300 /error/300.html;
|
||||
|
|
14
feed.xml
14
feed.xml
|
@ -5,15 +5,15 @@
|
|||
<title>askiiart.net</title>
|
||||
<description>The feed for askiiart.net, I guess</description>
|
||||
<link>https://askiiart.net</link>
|
||||
<lastBuildDate>Sun, 19 Nov 2023 23:10:34 +0000</lastBuildDate>
|
||||
<item>
|
||||
<title>My Stack</title>
|
||||
<link>https://askiiart.net/stack.html</link>
|
||||
</item>
|
||||
<lastBuildDate>Wed, 06 Dec 2023 17:42:13 +0000</lastBuildDate>
|
||||
<item>
|
||||
<title>Marlin Boot Animations</title>
|
||||
<link>https://askiiart.net/blog/marlin-boot-animations.html</link>
|
||||
</item>
|
||||
<item>
|
||||
<title>300</title>
|
||||
<link>https://askiiart.net/blog/300.html</link>
|
||||
</item>
|
||||
<item>
|
||||
<title>Akkoma in Docker</title>
|
||||
<link>https://askiiart.net/til/akkoma-in-docker.html</link>
|
||||
|
@ -22,6 +22,10 @@
|
|||
<title>Using JSON with docker compose</title>
|
||||
<link>https://askiiart.net/til/using-json-with-docker-compose.html</link>
|
||||
</item>
|
||||
<item>
|
||||
<title>My Stack</title>
|
||||
<link>https://askiiart.net/stack.html</link>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
|
@ -6,7 +6,7 @@
|
|||
printf "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n\n<channel>\n <title>askiiart.net</title>\n <description>The feed for askiiart.net, I guess</description>\n <link>https://askiiart.net</link>\n <lastBuildDate>$(TZ='UTC' date --rfc-2822)</lastBuildDate>" >feed.xml
|
||||
find . -path ./error -prune -o -name '*.html' -print | while read -r item; do
|
||||
# Skip template.html, wishlist.html, resume.html, and portfolio.html
|
||||
if [[ ${item} == "./index.html" || ${item} == "./template.html" || ${item} == "./wishlist.html" || ${item} == "./resume.html" || ${item} == "./portfolio.html" ]]; then
|
||||
if [[ ${item} == "./index.html" || ${item} == "./template.html" || ${item} == "./wishlist.html" || ${item} == "./resume.html" || ${item} == "./portfolio.html" || ${item} == "./opx.html" ]]; then
|
||||
continue
|
||||
fi
|
||||
item="${item%.*}"
|
||||
|
@ -20,7 +20,6 @@ printf "\n\n</channel>\n</rss>" >>feed.xml
|
|||
cd ./til
|
||||
printf "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n\n<channel>\n <title>askiiart.net TIL</title>\n <description>The feed for askiiart.net but just TIL, I guess</description>\n <link>https://askiiart.net/til/</link>\n <lastBuildDate>$(TZ='UTC' date --rfc-2822)</lastBuildDate>" >feed.xml
|
||||
find . -name "*.html" | while read -r item; do
|
||||
# Skip template.html, wishlist.html, resume.html, and portfolio.html
|
||||
item="${item%.*}"
|
||||
item="${item#./}"
|
||||
TITLE=$(grep -m 1 -oP '(?<=^# ).*' ${item}.md | cat)
|
||||
|
@ -33,7 +32,6 @@ cd ..
|
|||
cd ./blog
|
||||
printf "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n\n<channel>\n <title>askiiart.net blog</title>\n <description>The feed for askiiart.net but just the blog, I guess</description>\n <link>https://askiiart.net/blog/</link>\n <lastBuildDate>$(TZ='UTC' date --rfc-2822)</lastBuildDate>" >feed.xml
|
||||
find . -name "*.html" | while read -r item; do
|
||||
# Skip template.html, wishlist.html, resume.html, and portfolio.html
|
||||
item="${item%.*}"
|
||||
item="${item#./}"
|
||||
TITLE=$(grep -m 1 -oP '(?<=^# ).*' ${item}.md | cat)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* PrismJS 1.29.0
|
||||
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript+arduino+bash+c+csharp+cpp+css-extras+csv+docker+excel-formula+git+java+javadoc+javadoclike+javastacktrace+json+json5+log+markdown+nix+powershell+python+rust+vim+wiki&plugins=line-numbers+toolbar+copy-to-clipboard */
|
||||
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript+arduino+bash+c+csharp+cpp+css-extras+csv+docker+excel-formula+git+java+javadoc+javadoclike+javastacktrace+json+json5+log+markdown+nginx+nix+python+rust+vim+wiki&plugins=line-numbers+toolbar+copy-to-clipboard */
|
||||
code[class*=language-],
|
||||
pre[class*=language-] {
|
||||
color: #f8f8f2;
|
||||
background: 0 0;
|
||||
text-shadow: 0 1px rgba(0, 0, 0, .3);
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
font-family: 'Nimbus Mono PS', 'Liberation Mono', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', 'Lucida Console', monospace;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
|
|
4
prism.js
4
prism.js
File diff suppressed because one or more lines are too long
33
style.css
33
style.css
|
@ -1,3 +1,21 @@
|
|||
code {
|
||||
background: #121212;
|
||||
font: 1.0em/1.35 'Nimbus Mono PS', 'Liberation Mono', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', 'Lucida Console', monospace;
|
||||
padding: 0.2em;
|
||||
padding-top: 0.4em;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
|
||||
background: #121212;
|
||||
font-size: 1.5em/1.35;
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #dadada;
|
||||
background: #202020;
|
||||
|
@ -23,15 +41,6 @@ h3 {
|
|||
line-height: 1.2
|
||||
}
|
||||
|
||||
code {
|
||||
background: #121212
|
||||
}
|
||||
|
||||
pre {
|
||||
|
||||
background: #121212
|
||||
}
|
||||
|
||||
wrap {
|
||||
word-wrap: break-word
|
||||
}
|
||||
|
@ -65,4 +74,10 @@ wrap {
|
|||
|
||||
footer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid #59997a;
|
||||
padding-left: 1em;
|
||||
margin-left: 0.5;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<title>askiiart.net TIL</title>
|
||||
<description>The feed for askiiart.net but just TIL, I guess</description>
|
||||
<link>https://askiiart.net/til/</link>
|
||||
<lastBuildDate>Sun, 19 Nov 2023 23:10:34 +0000</lastBuildDate>
|
||||
<lastBuildDate>Wed, 06 Dec 2023 17:42:13 +0000</lastBuildDate>
|
||||
<item>
|
||||
<title>Akkoma in Docker</title>
|
||||
<link>https://askiiart.net/til/akkoma-in-docker.html</link>
|
||||
|
|
Loading…
Reference in a new issue