]> Sergey Matveev's repositories - sgblog.git/blob - README.texi
More compact Base64 ETag
[sgblog.git] / README.texi
1 \input texinfo
2 @documentencoding UTF-8
3 @settitle SGBlog
4
5 @copying
6 Copyright @copyright{} 2020-2024 @email{stargrave@@stargrave.org, Sergey Matveev}
7 @end copying
8
9 @node Top
10 @top SGBlog
11
12 SGBlog is minimalistic and simple Git-backed CGI/UCSPI
13 @url{https://en.wikipedia.org/wiki/Blog, blogging} (@code{http://}/@code{https://}),
14 @url{https://en.wikipedia.org/wiki/Phlog, phlogging} (@code{gopher://}),
15 @url{https://twtxt.readthedocs.io/en/latest/index.html, twtxting}, and
16 @url{https://en.wikipedia.org/wiki/Gemini_(protocol), gemlogging} (@code{gemini://})
17 engine with email-backed comments support,
18 written on @url{https://go.dev/, Go}.
19
20 Its main competitive features:
21
22 @itemize
23 @item Single binary, responsible for both blog, phlog and gemlog
24 @item @url{https://git-scm.com/, Git} DVCS as a storage for posts and comments
25 @item Single small @url{https://hjson.github.io/, Hjson} configuration file
26 @item Uses @url{https://en.wikipedia.org/wiki/Common_Gateway_Interface, CGI}
27     interface (simplicity, remember?) for dealing with HTTP-server
28 @item Uses
29     @url{https://en.wikipedia.org/wiki/Inetd, inetd}/@url{http://cr.yp.to/ucspi-tcp.html, UCSPI-TCP}
30     interface for working as
31     @url{https://en.wikipedia.org/wiki/Gopher_(protocol), Gopher} server
32 @item Topics (tags/categories) support
33 @item Images linking support
34 @item Supports on the fly generation of
35     @url{https://en.wikipedia.org/wiki/Atom_(feed), Atom} feeds
36     for posts, comments and per-post comments
37 @item Single binary for email-backed comments posting
38 @item If access is granted, then everyone can easily create an offline
39     copy of your blog/phlog/gemlog!
40 @end itemize
41
42 All of that, except for comments, topics and phlog/gemlog, could be achieved
43 with some Git viewer like @url{https://git.zx2c4.com/cgit/about/, cgit}.
44 But SGBlog also is able to:
45
46 @itemize
47 @item Convert URLs to clickable links
48 @item Convert SHA1-like hashes to blog links itself
49 @item Include relative @code{<link rel>} links for ease of navigation in
50     some browsers
51 @item @url{https://facebook.github.io/zstd/, Zstandard}
52     compress both HTML pages and Atom feeds
53 @item Respect @url{https://en.wikipedia.org/wiki/HTTP_ETag, ETag}
54     caching for both of them above
55 @end itemize
56
57 @url{http://blog.stargrave.org/example/, Here} is an example blog.
58
59 SGBlog is free software, licenced under
60 @url{https://www.gnu.org/licenses/agpl-3.0.html, GNU AGPLv3}:
61 see the file COPYING for copying conditions.
62
63 @node Comments
64 @unnumbered Comments
65
66 Comments are posted through the email interface, just by sending the
67 message to special address. For example:
68
69 @example
70 $ mutt "mailto:comment@@blog.example.com?subject=BlaBlaBla%20(576540a5b98517b46d0efc791bb90b9121bf147e)" <<EOF
71 This is the comments contents.
72 Could be multilined of course.
73 EOF
74 @end example
75
76 Comments are stored in Git as a @url{https://git-scm.com/docs/git-notes, note}.
77 Those objects could be updated without touching the base commit itself.
78
79 Each comment is just a plaintext with @code{From} and @code{Date}
80 headers. @code{From} is a name of email sender (with email address
81 stripped off).
82
83 Only @code{text/plain} or @code{multipart/signed+text/plain} email
84 messages are accepted and only with UTF-8, US-ASCII, ISO-8859-1
85 character sets. Sane people won't send HTML email anyway, but this is
86 just a precaution.
87
88 Comments are stored in @dfn{recfiles} --
89 @url{https://www.gnu.org/software/recutils/, GNU recutils}
90 human-editable plaintext database format. But they do not contain
91 records description:
92
93 @verbatim
94 %rec: Comment
95 %doc: SGBlog's comment
96 %mandatory: From Date Body
97 %type: Date date
98 @end verbatim
99
100 @node Topics
101 @unnumbered Topics
102
103 Each post can have any number of attached topics (also known as tags or
104 categories). They are whitespace separated single words kept in separate
105 @url{https://git-scm.com/docs/git-notes, note} namespace. You can
106 add/change comments with commands like:
107
108 @example
109 $ git notes --ref=topics add -m "linux hate" @@
110 $ git push origin mybranch refs/notes/topics
111 @end example
112
113 To reset incorrectly added topic:
114
115 @example
116 $ git update-ref refs/notes/topics refs/notes/topics^
117 @end example
118
119 @node Images
120 @unnumbered Images
121
122 You can link any number of image files with your post. You need to put
123 them in a directory (@code{ImgPath} configuration file's option) which
124 path is equal to your post's hash, with two subdirectory levels. For
125 example directory for post @code{3e12180dd2b6fb3b44c77c365d355d5a3796a43f}
126 will be @code{ImgPath/3e/12/180dd2b6fb3b44c77c365d355d5a3796a43f}.
127 Filenames are lexically sorted. Filename without an extension will be
128 image's alternative text. Currently only @file{.jxl} and @file{.webp}
129 are recognized. @code{ImgDomain} configuration file's option will be
130 used to construct URL to @code{//ImgDomain/3e/12/180dd2b6fb3b44c77c365d355d5a3796a43f}.
131
132 @node Installation
133 @unnumbered Installation
134
135 SGBlog's is written on Go and uses its modules. Hopefully you can
136 install it just by running:
137
138 @example
139 $ go get go.stargrave.org/sgblog/cmd/sgblog
140 $ go get go.stargrave.org/sgblog/cmd/sgblog-comment-add # if you need commenting
141 @end example
142
143 Unfortunately by default it uses HTTPS and Go's third party servers
144 (@code{sum.golang.org}, @code{proxy.golang.org}) that trust neither
145 @code{CACert.org}'s CA (used previously) nor @code{ca.cypherpunks.ru}
146 CAs. So either disable their usage and trust that certificate:
147 @code{GOPRIVATE=go.stargrave.org/sgblog}, or clone its source code
148 manually and build in place:
149 @url{git://git.stargrave.org/sgblog.git},
150 @url{https://git.stargrave.org/sgblog.git}.
151
152 For enabling blog availability you have to use HTTP server with CGI
153 interface. Example part of @url{http://www.lighttpd.net/, lighttpd}'s
154 configuration:
155
156 @example
157 $HTTP["host"] == "blog.example.com" @{
158   server.document-root = www_dir + "/blog.example.com"
159   $HTTP["url"] =~ "^/example" @{
160     alias.url += ("/example" => "/path/to/sgblog")
161     cgi.assign = ("sgblog" => "/path/to/sgblog")
162     setenv.add-environment = (
163       "SGBLOG_CFG" => "/path/to/example.hjson",
164     )
165   @}
166 @}
167 @end example
168
169 And be sure that you have read access to the Git repository, for example
170 by placing @code{lighttpd} user into @code{git} group.
171
172 Example @command{inetd} configuration (for phlog):
173
174 @example
175 gopher stream tcp6 nowait lighttpd /path/to/sgblog sgblog -gopher /path/to/gopher.hjson
176 @end example
177
178 Example @command{UCSPI-TCP} service running under
179 @url{http://cr.yp.to/daemontools.html, daemontools}:
180
181 @example
182 # mkdir -p /var/service/.phlog-ipv6/log
183 # cd /var/service/.phlog-ipv6
184
185 # cat > run <<EOF
186 #!/bin/sh -e
187 uid=\`id -u lighttpd\`
188 gid=\`id -g git\`
189 addr=2001::123
190 exec tcpserver -DHR -u $uid -g $gid -l 0 $addr gopher \
191   sgblog -gopher /path/to/gopher.hjson
192 EOF
193
194 # cat > log/run <<EOF
195 #!/bin/sh -e
196 exec setuidgid whatever-user multilog t ./main
197 EOF
198
199 # chmod -R 755 /var/service/.phlog-ipv6
200 # mv /var/service/.phlog-ipv6 /var/service/phlog-ipv6
201 @end example
202
203 Gemlog uses Gemini protocol that requires TLS usage, that can be
204 achieved with @url{go.cypherpunks.ru/ucspi} tools:
205
206 @example
207 exec tcpserver -DRH -u $uid -g $gid -l 0 ::0 1965 \
208   tlss -key gemlog.key.pem -cert gemlog.pem \
209   sgblog -gemini /home/sgblog/gemlog.hjson 2>&1
210 @end example
211
212 For comments workability you have to configure your SMTP server to feed
213 incoming messages to @command{sgblog-comment-add} utility. For example,
214 Postfix'es @file{/etc/aliases} can contain:
215
216 @example
217 comment: "| /path/to/sgblog-comment-add -git-dir /path/to/blog.git -committer-email comment@@blog.example.com"
218 @end example
219
220 to run that utility for all @code{comment@@} address messages.
221 You must have enough permission to be able to write to Git repository,
222 but Postfix by default runs all that commands from a @code{nobody} user.
223 So possibly you will need to @code{setuid} that executable give
224 permission for @code{nobody} running:
225
226 @example
227 -rwsr-x--- git:nobody sgblog-comment-add
228 @end example
229
230 And also do not forget about @code{lighttpd} user's (possibly in
231 @code{git} group) read permission permissions. Make sure
232 @command{sgblog-comment-add} runs with correctly set @code{-umask} (027
233 by default) for newly created Git objects/files.
234
235 @node Configuration
236 @unnumbered Configuration
237
238 SGBlog is configured via Hjson configuration file. More or less
239 self-describing blog configuration looks like that and contains many
240 optional fields:
241
242 @example
243 @{
244   GitPath: /home/sgblog/blog.git
245   Branch: refs/heads/example
246   Title: "Example blog"
247
248   BaseURL: http://blog.example.com
249   URLPrefix: /example
250
251   AtomId: "urn:uuid:54e6e53f-c615-48f1-812c-6f6b094ebbdd"
252   AtomAuthor: John Doe
253
254   # URL to CSS file, optional
255   CSS: /style.css
256   # Email address of the webmaster, optional
257   Webmaster: "webmaster@@example.com"
258   # URL to about page, optional
259   AboutURL: /
260   # Optional list of optional Git URLs for corresponding <link rel="vcs-git">
261   GitURLs: [
262     git://git.example.com/blog.git
263     https://git.example.com/git/blog.git
264   ]
265
266   # If that ref is set, then comments will be loaded from it
267   CommentsNotesRef: refs/notes/comments
268   # Display link for comment writing, if email is set
269   CommentsEmail: something@@example.com
270
271   # If that ref is set, then topics will be loaded from it
272   TopicsNotesRef: refs/notes/topics
273   # Optional file for topics state caching
274   TopicsCachePath: /path/to/sgblog-topics-cache.gob
275
276   # If set, then images are searched in XX/YY/ZZZ...ZZZ directory
277   ImgPath: /path/to/directory/with/images
278   ImgDomain: img.blog.example.com
279 @}
280 @end example
281
282 Gopher configuration can use the same file, but it requires much less
283 options:
284
285 @example
286 @{
287   GitPath: /home/sgblog/blog.git
288   Branch: refs/heads/example
289   Title: "Example blog"
290
291   GopherDomain: phlog.example.com
292
293   AboutURL: http://blog.example.com/
294
295   # Both are optional
296   CommentsNotesRef: refs/notes/comments
297   CommentsEmail: something@@example.com
298
299   # Both are optional too
300   TopicsNotesRef: refs/notes/topics
301   TopicsCachePath: /path/to/sgblog-topics-cache.gob
302 @}
303 @end example
304
305 @bye