mirror of https://github.com/omar-polo/gmid.git
change how the site is built
copy the kamid/site "framework" here too; in other words: don't maintain two copies of every page! \o/
This commit is contained in:
parent
964686ce0b
commit
ac42bb6c7f
|
@ -1,19 +1,70 @@
|
||||||
.PHONY: all serve-www serve-gemini upload
|
MANPAGES = ../gmid.1 \
|
||||||
|
../gg.1
|
||||||
|
|
||||||
all: gmid.1.html gmid.1.txt
|
PAGES = index.gmi \
|
||||||
|
changelog.gmi \
|
||||||
|
contrib.gmi \
|
||||||
|
quickstart.gmi
|
||||||
|
|
||||||
gmid.1.html: ../gmid.1
|
TITLE_index.gmi = home
|
||||||
./mdoc2html.sh $? $@
|
TITLE_changelog.gmi = changelog
|
||||||
|
TITLE_contrib.gmi = contrib
|
||||||
|
TITLE_quickstart.gmi = quickstart
|
||||||
|
|
||||||
gmid.1.txt: ../gmid.1
|
REPOLOGY_BANNER = https://repology.org/badge/vertical-allrepos/gmid.svg
|
||||||
MANWIDTH=72 man -Tutf8 -l $? | col -b > $@
|
REPOLOGY_URL = https://repology.org/project/gmid/versions
|
||||||
|
|
||||||
|
SUBST = ./subst GITHUB=https://github.com/omar-polo/gmid \
|
||||||
|
VERS=1.7.5 \
|
||||||
|
CURV=1.7 \
|
||||||
|
NEXTV=1.8
|
||||||
|
|
||||||
|
SUBST_GEM = ${SUBST} MANEXT=txt EXT=gmi REPOLOGY=${REPOLOGY_URL}
|
||||||
|
SUBST_WWW = ${SUBST} MANEXT=html EXT=html REPOLOGY=${REPOLOGY_BANNER}
|
||||||
|
|
||||||
|
.PHONY: all dirs manpages serve-www serve-gemini upload clean titles
|
||||||
|
|
||||||
|
all: dirs manpages pages
|
||||||
|
cp style.css www/
|
||||||
|
cp vim-screenshot.png www/
|
||||||
|
cp vim-screenshot.png gemini/
|
||||||
|
|
||||||
|
dirs:
|
||||||
|
mkdir -p gemini www
|
||||||
|
|
||||||
|
manpages:
|
||||||
|
.for m in ${MANPAGES}
|
||||||
|
./mdoc2html.sh $m www/${m:T}.html
|
||||||
|
man -O width=65 -Tutf8 -l $m | col -b > gemini/${m:T}.txt
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
pages:
|
||||||
|
.for p in ${PAGES}
|
||||||
|
${MAKE} titles-gem | ./menu.pl $p gemini > gemini/$p
|
||||||
|
${SUBST_GEM} $p >> gemini/$p
|
||||||
|
|
||||||
|
${SUBST_WWW} TITLE=${TITLE_${p}:Q} header.html > www/${p:.gmi=.html}
|
||||||
|
${MAKE} titles-www | ./menu.pl "${p:.gmi=.html}" html >> www/${p:.gmi=.html}
|
||||||
|
${SUBST_WWW} $p | ./gem2html >> www/${p:.gmi=.html}
|
||||||
|
cat footer.html >> www/${p:.gmi=.html}
|
||||||
|
.endfor
|
||||||
|
|
||||||
serve-www:
|
serve-www:
|
||||||
python3 -m http.server 8888
|
python3 -m http.server --directory www 8888
|
||||||
|
|
||||||
serve-gemini:
|
serve-gemini:
|
||||||
../gmid -p 1966 .
|
gmid -p 1966 ./gemini
|
||||||
|
|
||||||
upload:
|
upload:
|
||||||
rsync --delete -a . op:sites/gmid.omarpolo.com
|
rsync --delete -a www/ op:sites/gmid.omarpolo.com
|
||||||
rsync --delete -a . op:gemini/gmid.omarpolo.com
|
rsync --delete -a gemini/ op:gemini/gmid.omarpolo.com
|
||||||
|
|
||||||
|
titles-gem:
|
||||||
|
.for p in ${PAGES}
|
||||||
|
@printf "%s %s\n" "${p}" ${TITLE_${p}:Q}
|
||||||
|
.endfor
|
||||||
|
|
||||||
|
titles-www:
|
||||||
|
.for p in ${PAGES}
|
||||||
|
@printf "%s %s\n" "${p:.gmi=.html}" ${TITLE_${p}:Q}
|
||||||
|
.endfor
|
||||||
|
|
|
@ -1,232 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>gmid | contrib</title>
|
|
||||||
<meta charset="utf8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
max-width: 780px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
padding-bottom: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1::before {
|
|
||||||
content: "# ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2::before {
|
|
||||||
content: "## ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h3::before {
|
|
||||||
content: "### ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote::before {
|
|
||||||
content: "> ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote p {
|
|
||||||
font-style: italic;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.link::before {
|
|
||||||
content: "→ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
strong::before { content: "*" }
|
|
||||||
strong::after { content: "*" }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: 0;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #222;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: 2em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.banner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #9d109d;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #222;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: aqua;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: #353535;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #ff4cff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
pre.banner { font-size: 9px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
pre.banner { font-size: 10px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<a href="index.html">Home</a> |
|
|
||||||
contrib |
|
|
||||||
<a href="quickstart.html">Quickstart</a> |
|
|
||||||
<a href="gmid.1.html">docs</a>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<h1>contrib</h1>
|
|
||||||
<p>
|
|
||||||
This directory is for additional contributed files which may be
|
|
||||||
useful.
|
|
||||||
</p>
|
|
||||||
<p>Contents:</p>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#dockerfile">Dockerfile</a></li>
|
|
||||||
<li><a href="#gencert">gencert</a></li>
|
|
||||||
<li><a href="#openbsd-rc">OpenBSD rc file</a></li>
|
|
||||||
<li><a href="#systemd-unit-file">Systemd unit file</a></li>
|
|
||||||
<li><a href="#renew-certs">renew certificates automatically</a></li>
|
|
||||||
<li><a href="#vim-syntax-files">Vim syntax files</a></li>
|
|
||||||
</ul>
|
|
||||||
<hr />
|
|
||||||
<h2 id="dockerfile">Dockerfile</h2>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/Dockerfile">contrib/Dockerfile</a>
|
|
||||||
is a simple Dockerfile. The resulting image is a classic alpine
|
|
||||||
linux image with a statically linked gmid installed as
|
|
||||||
<code>/bin/gmid</code>.
|
|
||||||
</p>
|
|
||||||
<p>To build the image:</p>
|
|
||||||
<pre># docker build -f contrib/Dockerfile -t gmid .</pre>
|
|
||||||
<p>and then run it with something along the lines of:</p>
|
|
||||||
<pre># docker run --rm -it -p 1965:1965 \
|
|
||||||
-v gmid.conf:/etc/gmid.conf:ro \
|
|
||||||
-v path/to/keys:/tls:ro \
|
|
||||||
-v /var/gemini:/var/gemini:ro \
|
|
||||||
gmid -c /etc/gmid.conf</pre>
|
|
||||||
<h2 id="gencert">gencert</h2>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/gencert">contrib/gencert</a>
|
|
||||||
is a simple script to generate self-signed certificates.
|
|
||||||
</p>
|
|
||||||
<h2 id="openbsd-rc">OpenBSD rc file</h2>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/gmid">contrib/gmid</a>
|
|
||||||
is a sample service file for OpenBSD <code>rc(8)</code>.
|
|
||||||
To install it:
|
|
||||||
</p>
|
|
||||||
<pre># cp contrib/gmid /etc/rc.d</pre>
|
|
||||||
<p>
|
|
||||||
then the usual
|
|
||||||
<code>rcctl [start|stop|enable|restart] gmid</code>
|
|
||||||
are available.
|
|
||||||
</p>
|
|
||||||
<h2 id="systemd-unit-file">Systemd unit file</h2>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/gmid.service">contrib/gmid.service</a>
|
|
||||||
is a simple service file for
|
|
||||||
systemd. To install it:
|
|
||||||
</p>
|
|
||||||
<pre># cp contrib/gmid.service /lib/systemd/system/gmid.service</pre>
|
|
||||||
<p>
|
|
||||||
then the usual
|
|
||||||
<code>systemctl [status|start|enable|stop] gmid</code>
|
|
||||||
commands can be used to manage the server.
|
|
||||||
</p>
|
|
||||||
<p>Some things to keep in mind:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
the <code>ExecStart</code> path may depend on the installation.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
a <code>gmid</code> user needs to be created for e.g. with:
|
|
||||||
<pre># useradd --system --no-create-home -s /bin/nologin -c "gmid Gemini server" gmid</pre>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
logs can be inspected with <code>journalctl(1)</code>:
|
|
||||||
<pre># journalctl -t gmid</pre>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="renew-certs">renew certificates automatically</h2>
|
|
||||||
<p>
|
|
||||||
<strong>NB:</strong> this script requires features that are
|
|
||||||
currently available only in the master branch.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/renew-certs">contrib/renew-certs</a>
|
|
||||||
is a script meant to be run in a crontab that watch for
|
|
||||||
certificate expiration. It can optionally renew the certs and
|
|
||||||
restart gmid too.
|
|
||||||
</p>
|
|
||||||
<p>Read the documentation with: <code>perldoc renew-certs</code>.</p>
|
|
||||||
<h2 id="vim-syntax-files">Vim syntax files</h2>
|
|
||||||
<p>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/vim">contrib/vim</a>
|
|
||||||
contains a syntax highlighting for vim. To install it, just
|
|
||||||
copy the files to <code>~/.vim</code>
|
|
||||||
or <code>/usr/share/vim/vimfiles</code>, e.g.
|
|
||||||
</p>
|
|
||||||
<pre>$ mkdir -p ~/.vim
|
|
||||||
$ cp -R contrib/vim/* ~/.vim/</pre>
|
|
||||||
<p>To enable Syntastic checker, add to your vimrc:</p>
|
|
||||||
<pre>let g:syntastic_gmid_checkers = ['gmid']</pre>
|
|
||||||
<p>The end result is something like this:</p>
|
|
||||||
<a href="vim-screenshot.png">
|
|
||||||
<img src="vim-screenshot.png" alt="Screenshot of vim editing gmid.conf with syntax highlighting" />
|
|
||||||
</a>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,114 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Omar Polo <op@openbsd.org>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
use v5.10;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $in_pre = 0;
|
||||||
|
my $in_list = 0;
|
||||||
|
|
||||||
|
while (<>) {
|
||||||
|
chomp;
|
||||||
|
if ($in_pre && m/^```/) {
|
||||||
|
$in_pre = 0;
|
||||||
|
say "</pre>";
|
||||||
|
} elsif (!$in_pre && m/^```/) {
|
||||||
|
if ($in_list) {
|
||||||
|
$in_list = 0;
|
||||||
|
say "</ul>";
|
||||||
|
}
|
||||||
|
$in_pre = 1;
|
||||||
|
print "<pre>";
|
||||||
|
} elsif ($in_pre) {
|
||||||
|
say san($_);
|
||||||
|
} elsif ($in_list && m/^$/) {
|
||||||
|
say "</ul>";
|
||||||
|
$in_list = 0;
|
||||||
|
} elsif (m/^\*\s+(.*)/) { # NB: at least one space
|
||||||
|
if (!$in_list) {
|
||||||
|
$in_list = "item";
|
||||||
|
say "<ul>";
|
||||||
|
} elsif ($in_list eq "link") {
|
||||||
|
$in_list = "item";
|
||||||
|
say "</ul>";
|
||||||
|
say "<ul>";
|
||||||
|
}
|
||||||
|
output("li", $1);
|
||||||
|
} elsif (m/^=>\s*([^\s]*)\s*(.*)$/) {
|
||||||
|
my $href = $1;
|
||||||
|
my $alt = $2;
|
||||||
|
|
||||||
|
# special case: images
|
||||||
|
if ($1 =~ /\.(png|jpg|svg)$/) {
|
||||||
|
if ($in_list) {
|
||||||
|
say "</ul>";
|
||||||
|
$in_list = 0;
|
||||||
|
}
|
||||||
|
say "<img src='$href' alt='$alt' />";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$in_list) {
|
||||||
|
$in_list = "link";
|
||||||
|
say "<ul class='link-list'>";
|
||||||
|
} elsif ($in_list eq "item") {
|
||||||
|
$in_list = "link";
|
||||||
|
say "</ul>";
|
||||||
|
say "<ul class='link-list'>";
|
||||||
|
}
|
||||||
|
$_ = $alt || $href;
|
||||||
|
say "<li><a href='$href'>". san() ."</a></li>";
|
||||||
|
} elsif (m/^###\s*(.*)$/) {
|
||||||
|
output("h3", $1);
|
||||||
|
} elsif (m/^##\s*(.*)$/) {
|
||||||
|
output("h2", $1);
|
||||||
|
} elsif (m/^#\s*(.*)$/) {
|
||||||
|
output("h1", $1);
|
||||||
|
} elsif (m/^>\s*(.*)$/) {
|
||||||
|
output("blockquote", $1);
|
||||||
|
} else {
|
||||||
|
output("p", $_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub san {
|
||||||
|
s/&/\&/g;
|
||||||
|
s/</\</g;
|
||||||
|
s/>/\>/g;
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub output {
|
||||||
|
my ($tn, $content) = @_;
|
||||||
|
|
||||||
|
if (!$in_list && $tn eq "li") {
|
||||||
|
$in_list = 1;
|
||||||
|
say "<ul>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($in_list && $tn ne "li") {
|
||||||
|
$in_list = 0;
|
||||||
|
say "</ul>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tn eq "p" && $content eq "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_ = $content;
|
||||||
|
say "<$tn>". san() ."</$tn>";
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>TITLE | gmid</title>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
377
site/index.html
377
site/index.html
|
@ -1,377 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>gmid</title>
|
|
||||||
<meta charset="utf8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
max-width: 780px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
padding-bottom: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1::before {
|
|
||||||
content: "# ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2::before {
|
|
||||||
content: "## ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h3::before {
|
|
||||||
content: "### ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote::before {
|
|
||||||
content: "> ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote p {
|
|
||||||
font-style: italic;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.link::before {
|
|
||||||
content: "→ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
strong::before { content: "*" }
|
|
||||||
strong::after { content: "*" }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: 0;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #222;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: 2em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.banner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #9d109d;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #222;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: aqua;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: #353535;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #ff4cff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
pre.banner { font-size: 9px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
pre.banner { font-size: 10px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
Home |
|
|
||||||
<a href="contrib.html">contrib</a> |
|
|
||||||
<a href="quickstart.html">Quickstart</a> |
|
|
||||||
<a href="gmid.1.html">docs</a>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<h1>gmid</h1>
|
|
||||||
<blockquote>
|
|
||||||
<p>A Gemini server</p>
|
|
||||||
</blockquote>
|
|
||||||
<h2>Features</h2>
|
|
||||||
<ul>
|
|
||||||
<li>sandboxed by default on OpenBSD, FreeBSD and Linux</li>
|
|
||||||
<li>able to reload the configuration on-the-fly without loosing connections</li>
|
|
||||||
<li>punycode and IRI support</li>
|
|
||||||
<li>reverse proxying</li>
|
|
||||||
<li>CGI and FastCGI support</li>
|
|
||||||
<li>virtual hosts and per-location rules</li>
|
|
||||||
<li>low memory footprint</li>
|
|
||||||
<li>event-based asynchronous I/O model</li>
|
|
||||||
<li>rich configuration file</li>
|
|
||||||
</ul>
|
|
||||||
<h2>Install</h2>
|
|
||||||
<p>Some distros provide a package — thanks to the maintainers!</p>
|
|
||||||
<p>
|
|
||||||
<a href="https://repology.org/project/gmid/versions">
|
|
||||||
<img src="https://repology.org/badge/vertical-allrepos/gmid.svg" alt="Packaging status">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>Source code and precompiled binaries for linux are available:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/gmid-1.7.5.tar.gz">gmid-1.7.5.tar.gz</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://git.omarpolo.com/gmid/">git repository</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="gemini://git.omarpolo.com/gmid.git/">git repository via Gemini</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid">GitHub mirror</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/gmid.linux.aarch64">gmid.linux.aarch64</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/gmid.linux.amd64">gmid.linux.amd64</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
When in doubt, compile from source: it’s easy and takes less
|
|
||||||
than a minute on a raspberry pi 3. The dependencies are:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>libevent</li>
|
|
||||||
<li>OpenSSL/LibreSSL</li>
|
|
||||||
<li>libtls (from either LibreSSL or LibreTLS)</li>
|
|
||||||
<li>yacc or GNU bison</li>
|
|
||||||
</ul>
|
|
||||||
<p>Once all the dependencies are installed, building is as easy as:</p>
|
|
||||||
<pre>$ curl -LO https://github.com/omar-polo/gmid/releases/download/1.7.5/gmid-1.7.5.tar.gz
|
|
||||||
$ tar xzvf gmid-1.7.5.tar.gz
|
|
||||||
$ cd gmid-1.7.5
|
|
||||||
$ ./configure
|
|
||||||
$ make
|
|
||||||
$ sudo make install # eventually</pre>
|
|
||||||
<p>
|
|
||||||
A SHA256 file is available. However, that only checks for
|
|
||||||
accidental corruption: you can use signify (SHA256.sig and the
|
|
||||||
public key gmid-1.7.pub) or GPG. The hash of the signify public
|
|
||||||
key is also included in the SHA256 file and thus signed with my
|
|
||||||
GPG. The signify public key for the next release ‘gmid-1.8.pub’
|
|
||||||
is also included.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/SHA256">SHA256</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/SHA256.gpg">SHA256.gpg</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/omar-polo/gmid/releases/download/1.7.5/SHA256.sig">SHA256.sig</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>To verify the signatures with signify(1)</p>
|
|
||||||
<pre>$ signify -C -p gmid-1.7.pub -x SHA256.sig
|
|
||||||
Signature Verified
|
|
||||||
gmid-1.7.pub: OK
|
|
||||||
gmid-1.7.5.tar.gz: OK
|
|
||||||
gmid-1.8.pub: OK
|
|
||||||
gmid.linux.aarch64: OK
|
|
||||||
gmid.linux.amd64: OK</pre>
|
|
||||||
<h2>Changelog for the last versions</h2>
|
|
||||||
<p>1.7.5 “Space-dye Vest” fifth bugfix release — Released October 15, 2021</p>
|
|
||||||
<p>This version includes the following bugfix:</p>
|
|
||||||
<ul>
|
|
||||||
<li>don't die when a connection is closed before being accepted by gmid (i.e. handle <code>ECONNRESET</code>)</li>
|
|
||||||
</ul>
|
|
||||||
<hr />
|
|
||||||
<p>1.7.4 “Space-dye Vest” fourth bugfix release — Released September 24, 2021</p>
|
|
||||||
<p>This version includes the following bugfix:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
fix a possible out-of-bound access when handling a request for
|
|
||||||
a non-existent file in the root directory of a vhost that's
|
|
||||||
matched by the cgi option
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>and the relative regression test.</p>
|
|
||||||
<hr />
|
|
||||||
<p>1.7.3 “Space-dye Vest” third bugfix release — Released September 18, 2021</p>
|
|
||||||
<h3>Improvements</h3>
|
|
||||||
<ul>
|
|
||||||
<li>follows symlinks</li>
|
|
||||||
<li>improved documentation and added key generation example (thanks! Anna)</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Bugfix</h3>
|
|
||||||
<ul>
|
|
||||||
<li>fix syslog logging on FreeBSD. Reported by Karl Jeacle, thanks!</li>
|
|
||||||
<li>don't crash if <code>-c</code> is missing in configtest mode (<code>-n</code>). Reported by heph, thanks!</li>
|
|
||||||
<li>allow fstat64 on linux (needed by glibc on aarch64). Reported by pine, thanks!</li>
|
|
||||||
</ul>
|
|
||||||
<hr />
|
|
||||||
<p>1.7.2 “Space-dye Vest” second bugfix release — Released July 19, 2021</p>
|
|
||||||
<p>This version includes the following bugfix:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
An un-initialized field in the configless code path leads to a
|
|
||||||
crash on the first request.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>and the relative regression test.</p>
|
|
||||||
<hr />
|
|
||||||
<p>1.7.1 “Space-dye Vest” bugfix release — Released July 11, 2021</p>
|
|
||||||
<p>This version includes two bugfixes:</p>
|
|
||||||
<ul>
|
|
||||||
<li>use <code>${MAKE}</code> to recursively call make.</li>
|
|
||||||
<li>
|
|
||||||
fix the misleading example in the manpage: macros name may not
|
|
||||||
be reserved words.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<hr />
|
|
||||||
<p>1.7 “Space-dye Vest” — Released July 10, 2021</p>
|
|
||||||
<p>
|
|
||||||
Starting from this version gmid doesn't depend on lex anymore,
|
|
||||||
but yacc is still needed.
|
|
||||||
</p>
|
|
||||||
<h3>New Features</h3>
|
|
||||||
<ul>
|
|
||||||
<li>initial fastcgi support! (it’s still young!)</li>
|
|
||||||
<li>
|
|
||||||
added user-defined macros, either via <code>-Dname=val</code> or
|
|
||||||
directly in the configuration file.
|
|
||||||
</li>
|
|
||||||
<li>new <code>include</code> keyword to load additional configuration files.</li>
|
|
||||||
<li>new <code>env</code> rule to define environment vars for CGI scripts.</li>
|
|
||||||
<li>new <code>alias</code> rule to define hostname aliases for a server.</li>
|
|
||||||
<li>allow <code>root</code> to be specified per-location block.</li>
|
|
||||||
<li>pidfile support with the new <code>-P</code> cli flag.</li>
|
|
||||||
<li>
|
|
||||||
define <code>TLS_VERSION</code>, <code>TLS_CIPHER</code> and
|
|
||||||
<code>TLS_CIPHER_STRENGTH</code> for CGI scripts.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Improvements</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
remove limits on the number of virtual hosts and location
|
|
||||||
blocks that can be defined.
|
|
||||||
</li>
|
|
||||||
<li>print the datetime when logging to stderr.</li>
|
|
||||||
<li>
|
|
||||||
use <code>text/x-patch</code> for <code>.patch</code> and <code>.diff</code> files.
|
|
||||||
</li>
|
|
||||||
<li>sort the auto index alphabetically.</li>
|
|
||||||
<li>various improvements to the log management.</li>
|
|
||||||
<li>drop the dependency on lex.</li>
|
|
||||||
<li>
|
|
||||||
added <code>--help</code> as synonym of <code>-h</code> and
|
|
||||||
<code>-V</code>/<code>--version</code> to print the version.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
c-like handling of strings in the configuration file: when
|
|
||||||
two or more strings are next to each-others, are
|
|
||||||
automatically joined into a single string. This is
|
|
||||||
particularly useful with <code>$</code>-macros.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Bug fixes</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
correctly handle CGI scripts that replies with the maxium
|
|
||||||
header length allowed.
|
|
||||||
</li>
|
|
||||||
<li>fixed the <code>static</code> target.</li>
|
|
||||||
<li>
|
|
||||||
fixed recursive mkdirs for configless mode (i.e. create
|
|
||||||
<code>~/.local/share/gmid</code>)
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
logs sent to syslog now have proper priority (before every
|
|
||||||
message ended up as LOG_CRIT). Found by Anna
|
|
||||||
“CyberTailor”, thanks!
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
ensure <code>%p</code> (path) is always absolute in
|
|
||||||
<code>block return</code> rules.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
fix automatic certificate generation, it caused problems on
|
|
||||||
some adroid devices. Found by Gnuserland, thanks!
|
|
||||||
</li>
|
|
||||||
<li>document the <code>log</code> rule.</li>
|
|
||||||
<li>
|
|
||||||
the seccomp filter was reworked and now it’s known to
|
|
||||||
work properly on a vast range of architectures (to be more
|
|
||||||
specific: all the architectures supported by alpine linux),
|
|
||||||
see github issue #4. Prompted and tested by @begss, thanks!
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
various improvements to the configure script, notified and
|
|
||||||
fixed by Anna “CyberTailor”, thanks!
|
|
||||||
</li>
|
|
||||||
<li>added a timeout to the regression tests.</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Breaking changes</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
if duplicate rules are found in the configuration file, an
|
|
||||||
error is now raised instead of silently using only the last
|
|
||||||
value.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
(sort of) <code>gg</code> moved to <code>regress</code> as
|
|
||||||
it's only used in the regression suite.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
(notice) the <code>mime "mime-type" "extension"</code> rule was deprecated and
|
|
||||||
replaced by the new <code>map "mime-type" to-ext "extension"</code>. The
|
|
||||||
<code>mime</code> rule will be removed in a future version
|
|
||||||
because its syntax is incompatible with the new string
|
|
||||||
auto-concat mechanism.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use v5.10;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $page = shift or die 'missing page';
|
||||||
|
my $outtype = shift or die 'missing output type';
|
||||||
|
my @pages = ();
|
||||||
|
|
||||||
|
while (<>) {
|
||||||
|
chomp;
|
||||||
|
@pages = (@pages, $_);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $did = 0;
|
||||||
|
for (@pages) {
|
||||||
|
my ($href, $text) = m/^([^\s]*)\s*(.*)$/;
|
||||||
|
|
||||||
|
if ($outtype eq 'gemini') {
|
||||||
|
if ($href ne $page) {
|
||||||
|
say "=> $href $text";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$did) {
|
||||||
|
$did = 1;
|
||||||
|
} else {
|
||||||
|
print "| ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($href eq $page) {
|
||||||
|
print "$text ";
|
||||||
|
} else {
|
||||||
|
print "<a href='$href'>$text</a> ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
say "";
|
|
@ -1,291 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>gmid quickstart</title>
|
|
||||||
<meta charset="utf8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
max-width: 780px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
padding-bottom: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1::before {
|
|
||||||
content: "# ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2::before {
|
|
||||||
content: "## ";
|
|
||||||
}
|
|
||||||
|
|
||||||
h3::before {
|
|
||||||
content: "### ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote::before {
|
|
||||||
content: "> ";
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote p {
|
|
||||||
font-style: italic;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.link::before {
|
|
||||||
content: "→ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
strong::before { content: "*" }
|
|
||||||
strong::after { content: "*" }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border: 0;
|
|
||||||
height: 1px;
|
|
||||||
background-color: #222;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: 2em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre.banner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #9d109d;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #222;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: aqua;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: #353535;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, kbd {
|
|
||||||
color: #ff4cff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
pre.banner { font-size: 9px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
pre.banner { font-size: 10px; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<nav>
|
|
||||||
<a href="/">Home</a> |
|
|
||||||
<a href="contrib.html">contrib</a> |
|
|
||||||
Quickstart |
|
|
||||||
<a href="gmid.1.html">docs</a>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<h1>gmid quickstart</h1>
|
|
||||||
<p>gmid can be run in two different “modes”:</p>
|
|
||||||
<dl>
|
|
||||||
<dt>configless:</dt>
|
|
||||||
<dd>
|
|
||||||
a quick way to serve a directory tree from the shell, useful
|
|
||||||
for testing a capsule before uploading it
|
|
||||||
</dd>
|
|
||||||
<dt>daemon mode:</dt>
|
|
||||||
<dd>
|
|
||||||
gmid reads the configuration file and runs in the background
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<p>To run gmid in the “configless” mode, just type:</p>
|
|
||||||
<pre>$ gmid path/to/dir</pre>
|
|
||||||
<p>
|
|
||||||
gmid will then generate a certificate inside ~/.local/share/gmid
|
|
||||||
and serve the given directory locally.
|
|
||||||
</p>
|
|
||||||
<h2>Setting up a capsule with gmid</h2>
|
|
||||||
<p>
|
|
||||||
To host a Gemini capsule you need to run gmid in “daemon”
|
|
||||||
mode, and so a configuration file is needed. The format of the
|
|
||||||
configuration file is described in the manpage and is quite
|
|
||||||
flexible, but something like the following should be enough to
|
|
||||||
start:
|
|
||||||
</p>
|
|
||||||
<pre># /etc/gmid.conf
|
|
||||||
|
|
||||||
server "example.com" {
|
|
||||||
cert "/etc/ssl/example.com.pem"
|
|
||||||
key "/etc/ssl/private/example.com/key"
|
|
||||||
|
|
||||||
# path to the root directory of your capsule
|
|
||||||
root "/var/gemini/example.com"
|
|
||||||
}</pre>
|
|
||||||
<p>
|
|
||||||
A certificate is needed for the capsule. Generate one for
|
|
||||||
e.g. using
|
|
||||||
<a href="https://git.omarpolo.com/gmid/tree/contrib/gencert">contrib/gencert</a>:
|
|
||||||
</p>
|
|
||||||
<pre>$ ./contrib/gencert example.com
|
|
||||||
Generating a 4096 bit RSA private key
|
|
||||||
.................................................++++
|
|
||||||
..........++++
|
|
||||||
writing new private key to './example.com.key'
|
|
||||||
-----
|
|
||||||
|
|
||||||
Generated files:
|
|
||||||
./example.com.pem : certificate
|
|
||||||
./example.com.key : private key</pre>
|
|
||||||
<p>
|
|
||||||
Move ‘example.com.pem’ and ‘example.com.key’ to a safe place and
|
|
||||||
double check that the ‘cert’ and ‘key’ options in the
|
|
||||||
configuration points to these files.
|
|
||||||
</p>
|
|
||||||
<p>For example, save them in ‘/etc/ssl/’ (as root)</p>
|
|
||||||
<pre># mkdir -p /etc/ssl/private
|
|
||||||
# chown 700 /etc/ssl/private
|
|
||||||
# mv example.com.pem /etc/ssl/
|
|
||||||
# mv example.com.key /etc/ssl/private/</pre>
|
|
||||||
<p>
|
|
||||||
Make sure that the ‘cert’ and ‘key’ options in the configuration
|
|
||||||
file points to these files.
|
|
||||||
</p>
|
|
||||||
<p>Then running gmid is as easy as</p>
|
|
||||||
<pre>$ gmid -c /etc/gmid.conf</pre>
|
|
||||||
<p>Congratulations, your capsule is online!</p>
|
|
||||||
<h2>Securing your gmid installation</h2>
|
|
||||||
<p>
|
|
||||||
gmid employs various techniques to prevent the damage caused by
|
|
||||||
bugs, but some steps needs to be done manually.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If gmid was installed from your distribution package manager,
|
|
||||||
chance are that it already does all of this and is also
|
|
||||||
providing a service to run gmid automatically (e.g. a rc script,
|
|
||||||
a systemd unit file …) Otherwise, it’s heavily suggested to
|
|
||||||
create at least a dedicated user.
|
|
||||||
</p>
|
|
||||||
<h3>A dedicated user</h3>
|
|
||||||
<p>
|
|
||||||
Ideally, gmid should be started as root and drop privileges to a
|
|
||||||
local user. This way, the certificates can be readable only by
|
|
||||||
root. For example, on GNU/linux systems a ‘gmid’ user can be
|
|
||||||
created with:
|
|
||||||
</p>
|
|
||||||
<pre># useradd --system --no-create-home -s /bin/nologin -c "gmid Gemini server" gmid</pre>
|
|
||||||
<p>
|
|
||||||
Please consult your OS documentation for more information on the
|
|
||||||
matter.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The configuration then needs to be adjusted to include the
|
|
||||||
‘user’ directive at the top:
|
|
||||||
</p>
|
|
||||||
<pre># /etc/gmid.conf
|
|
||||||
user "gmid"
|
|
||||||
|
|
||||||
server "example.com" { … }</pre>
|
|
||||||
<p>
|
|
||||||
gmid then needs to be started with root privileges, but will
|
|
||||||
then switch to the provided user automatically. If by accident
|
|
||||||
the ‘user’ option is omitted and gmid is running as root, it
|
|
||||||
will complain loudly in the logs.
|
|
||||||
</p>
|
|
||||||
<h3>chroot</h3>
|
|
||||||
<p>
|
|
||||||
It’s a common practice for system daemons to chroot themselves
|
|
||||||
into a directory. From here on I’ll assume /var/gemini, but it
|
|
||||||
can be any directory.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
A chroot on UNIX-like OS is an operation that changes the
|
|
||||||
“apparent” root directory (i.e. the “/”) from the current
|
|
||||||
process and its child. Think of it like imprisoning a process
|
|
||||||
into a directory and never letting it escape until it
|
|
||||||
terminates.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Using a chroot may complicate the use of CGI scripts, because
|
|
||||||
then all the dependencies of the scripts (sh, perl, libraries…)
|
|
||||||
need to be installed inside the chroot too. For this very
|
|
||||||
reason gmid supports FastCGI.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The chroot feature requires a dedicate user, see the previous
|
|
||||||
section.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
To chroot gmid inside a directory, use the ‘chroot’ directive in
|
|
||||||
the configuration file:
|
|
||||||
</p>
|
|
||||||
<pre># /etc/gmid.conf
|
|
||||||
|
|
||||||
user "gmid"
|
|
||||||
|
|
||||||
# the given directory, /var/gemini in this case, must exists.
|
|
||||||
chroot "/var/gemini"</pre>
|
|
||||||
<p>
|
|
||||||
Note that once ‘chroot’ is in place, every ‘root’ directive is
|
|
||||||
implicitly relative to the chroot, but ‘cert’ and ‘key’ aren’t!
|
|
||||||
</p>
|
|
||||||
<p>For example, given the following configuration:</p>
|
|
||||||
<pre># /etc/gmid.conf
|
|
||||||
|
|
||||||
user "gmid"
|
|
||||||
chroot "/var/gemini"
|
|
||||||
|
|
||||||
server "example.com" {
|
|
||||||
cert "/etc/ssl/example.com.pem"
|
|
||||||
key "/etc/ssl/example.com.key"
|
|
||||||
root "/example.com"
|
|
||||||
}</pre>
|
|
||||||
<p>
|
|
||||||
The certificate and the key path are the specified ones, but the
|
|
||||||
root directory of the virtual host is actually
|
|
||||||
“/var/gemini/example.com/”.
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
max-width: 780px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
padding-bottom: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1::before {
|
||||||
|
content: "# ";
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2::before {
|
||||||
|
content: "## ";
|
||||||
|
}
|
||||||
|
|
||||||
|
h3::before {
|
||||||
|
content: "### ";
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote::before {
|
||||||
|
content: "> ";
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote p {
|
||||||
|
font-style: italic;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.link::before {
|
||||||
|
content: "→ ";
|
||||||
|
}
|
||||||
|
|
||||||
|
strong::before { content: "*" }
|
||||||
|
strong::after { content: "*" }
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #222;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin: 2em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.link-list {
|
||||||
|
list-style: disclosure-closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.banner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
code, kbd {
|
||||||
|
color: #9d109d;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background-color: #222;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: aqua;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: #353535;
|
||||||
|
}
|
||||||
|
|
||||||
|
code, kbd {
|
||||||
|
color: #ff4cff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
pre.banner { font-size: 9px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
pre.banner { font-size: 10px; }
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Omar Polo <op@omarpolo.com>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
#
|
||||||
|
# subst -- filter that replaces key=values pairs
|
||||||
|
#
|
||||||
|
# usage: subst key1=val1 [... keyn=valn] [files...]
|
||||||
|
#
|
||||||
|
# Use `--' before the first file if it may contain an = in its name.
|
||||||
|
# If no files are given, read and substitute from standard input.
|
||||||
|
|
||||||
|
use v5.10;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my @args = ();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
$_ = shift;
|
||||||
|
last if !$_;
|
||||||
|
|
||||||
|
if ($_ eq '--') {
|
||||||
|
last;
|
||||||
|
} elsif ($_ !~ m/=/) {
|
||||||
|
unshift @ARGV, $_;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($match, $repl) = m/^([^\s]*)=(.*)$/;
|
||||||
|
push @args, "-e", "s,$match,$repl,g";
|
||||||
|
}
|
||||||
|
|
||||||
|
# OK, shelling out to sed is a bit lame...
|
||||||
|
exec "sed", @args, @ARGV;
|
Loading…
Reference in New Issue