romanzolotarev.com: support and follow me on Mastodon
"SSG by @romanzolotarev is an impressively small static site generator with a tiny installed footprint. Really good for when you just need the core features."
— Simon Dann (@carbontwelve)"Thanks for writing ssg ;)"
— nixfloyd (@nixfloyd)"ssg by @romanzolotarev seems to be working a treat and great option for those of us who prefer static sites ..."
— Dylan (@GrimSysadmin)"...Thanks for providing ssg! It is helping me to (slowly) put my #OpenBSD musings into words..."
— fd0 (@fd0_nl)"...thanx again for ssg! Starting to move gists to my site and it couldn't have been more simple."
— (((Mischa 🕶 🐡 RCX))) (@mischapeters)"I am loving @romanzolotarev's romanzolotarev.com/ssg.html"
— Doppelvizsla (@doppelvizsla)"Thanks to @romanzolotarev's static site generator, I'm back on my "static site sausage machine for some extra pocket peanuts" kick again."
— pr1ntf (@pr1ntf)"It's really inspiring to see you give back much to the community. I appreciate your work - ssg, your how-to's for less familiar users, etc. I felt I should mention that to you 😀"
— H3artbl33d (@h3artbl33d)
Tested on OpenBSD 6.3
ssg is a static site generator writen in shell and powered by lowdown(1), rsync(1), and entr(1).
It generates a site from HTML and Markdown articles.
.* and _*,index.html,<h1> tag from every article to generate a
sitemap and use it as a page title,$DOCS/.
240 LoC. Enlarge, enhance, zoom!
ssg is one hundred times smaller than Jekyll.
ssg and its dependencies are about 800KB combined. Compare that
to 78MB of ruby with Jekyll and all the gems. So ssg can be
installed in just few seconds on almost any Unix-like operating
system.
Obviously, ssg is tailored for my needs, it has all features I
need and only those I use.
Keeping ssg helps you to master your Unix-shell skills: awk,
grep, sed, sh, cut, tr. As a web developer you work with
lots of text: code and data. So you better master these wonderful
tools.
100 pps. On modern computers ssg generates a hundred pages
per second. Half of a time for markdown rendering and another half
for wrapping articles into the template. I heard good static site
generators work—twice as fast—at 200 pps, so there's lots of
performance that can be gained. ;)
If you agree with the license, feel free to use this script, its HTML and CSS or/and re-write them for your needs.
Install dependencies and download ssg. For example, on OpenBSD:
as root install rsync(1), lowdown(1), and entr(1).
# pkg_add rsync-3.1.3-iconv lowdown entr quirks-2.414 signed on 2018-03-28T14:24:37Z rsync-3.1.3-iconv: ok lowdown-0.3.1: ok entr-4.0: ok The following new rcscripts were installed: /etc/rc.d/rsyncd See rcctl(8) for details. #
Then as a regular user change into ~/.bin directory.
$ cd ~/.bin $ ftp https://www.romanzolotarev.com/bin/ssg Trying 140.82.28.210... Requesting https://www.romanzolotarev.com/bin/ssg 100% |****************************************| 7257 00:00 7257 bytes received in 0.00 seconds (2.99 MB/s) $ chmod +x ssg $
Let's customize your ssg setup.
To configure ssg you need to set two variables:
$DOCS - path to web server document root directory$ROOT - root URL of your web siteThere are three more variables, but these are optional:
$WEBSITE_TITLE - title (suffix) for all pages$RSS_AUTHOR - author's full name for RSS feed$RSS_DESCRIPTION - RSS feed descriptionYou can set all those variables in enviornment with export or
env, but I recommend to create _ssg.conf file. For example, here
is mine:
#!/bin/sh
: "${DOCS:=/var/www/htdocs/www.romanzolotarev.com}"
ROOT='https://www.romanzolotarev.com'
WEBSITE_TITLE='Roman Zolotarev'
RSS_AUTHOR='hi@romanzolotarev.com (Roman Zolotarev)'
RSS_DESCRIPTION='Personal website'
Note: in this example if $DOCS is set, then ssg uses the original
value, not the value from _ssg.conf.
There is only one file required:
index.html or index.md - home pageExample of index.md:
# Jack
- [About](/about.html "01 Aug 2016")
ssg renders index.md to index.html and then generates the RSS feed
based on first 20 links, if they have the following syntax (it only uses
page URL and date from <a> tag):
...
<li><a href="/about.html" title="01 Aug 2016">About</a></li>
...
_header.html - header of every page_footer.html - and its footer_styles.css - styles, take mine and customizeIf you use my CSS, don't forget to wrap the content of _header.html
into <div class="header>...</div> and the content of _footer.html
into <div class="footer>...</div>.
There are also reserved filenames, these files are generated when you run
ssg build. Don't use these names.
rss.xml - reserved for RSS feedsitemap.xml - for the sitemapLet's create about.html with one header and some text about your site.
# About this site
...
ssg converts all .md article into .html and then uses content of the
first <h1> tag as a page title.
Nota bene: Don't use ===== in titles.
Now we are ready to build. If your current source directory looks like this:
.
|-- .git/
|-- _footer.html
|-- _header.html
|-- _styles.css
|-- about.md
`-- index.md
After you run ssg (don't forget to set $DOCS):
$ ssg build building /var/www/htdocs/www 2018-04-10T10:56:52+0000 4pp $
You have your static website ready in /var/www/htdocs/www.
.
|
|-- about.html
|-- index.html
|-- rss.xml
`-- sitemap.xml
For OpenBSD I suggest to run httpd locally.
For macOS and Linux you can run:
$ cd /var/www/htdocs/www $ python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000...
To re-build pages on change run:
$ ssg watch watching /home/jack/src/www building /var/www/htdocs/www 2018-04-10T11:04:11+0000 4pp
entr(1) watches changes in *.html, *.md, *.css, *.txt files and
runs ssg build on every file change.
If you'd like to delete all files in the destination directory during build, then run:
$ ssg build --clean building /home/jack/src/www/docs --clean 2018-04-16T09:03:32+0000 4pp $
The same option works for watching.
$ ssg watch --clean watching /home/jack/src/www building /home/jack/src/www/docs --clean 2018-04-16T09:04:25+0000 4pp
If you don't have a public server yet, try Vultr. To deploy to remote server you can use rsync(1) like this:
$ rsync -avPc /var/www/htdocs/www \ www.example.com:/var/www/htdocs/
Or if you want to clean up the target directory on the remote server use:
$ rsync -avPc --delete-excluded \
/var/www/htdocs/www \
www.example.com:/var/www/htdocs/
$
As root install rsync(1) and lowdown(1) packages on that server.
# pkg_add rsync-3.1.3-iconv lowdown quirks-2.414 signed on 2018-03-28T14:24:37Z rsync-3.1.3-iconv: ok lowdown-0.3.1: ok The following new rcscripts were installed: /etc/rc.d/rsyncd See rcctl(8) for details. #
Then as git user download ssg on the server:
# cd /home/git # su git $ mkdir -p /home/git/bin $ cd /home/git/bin $ ftp https://www.romanzolotarev.com/bin/ssg Trying 140.82.28.210... Requesting https://www.romanzolotarev.com/bin/ssg 100% |****************************************| 7257 00:00 7257 bytes received in 0.00 seconds (2.99 MB/s) $ chmod +x ssg $
Then add these lines to /home/git/REPOSITORY.git/hooks/post-receive:
#!/bin/sh
TMPDIR="$(mktemp -d)"
git archive --format=tar HEAD | (cd "$TMPDIR" && tar xf -)
cd "$TMPDIR"
DOCS='/var/www/htdocs/www.romanzolotarev.com' \
/home/git/ssg build --clean
As root make sure git user owns $DOCS directory:
# chown -R git:git /var/www/htdocs/www.romanzolotarev.com $
Thanks to
Denis Borovikov for reading the draft of this,
h3artbl33d, and
Mischa Peters, and
Tom Atkinson for testing ssg,
Kristaps Dzonsons for
lowdown(1) and
Eric Radman for
entr(1).