oddmu - a wiki server
Oddmu is sometimes written Oddµ because µ is the letter mu.
Oddmu can be used as a static site generator, turning Markdown files into HTML files, or it can be used as a public or a private wiki server. If it runs as a public wiki server, a regular webserver should be used as reverse proxy.
Run Oddmu without any arguments to serve the current working directory as a wiki on port 8080. Point your browser to http://localhost:8080/ to use it. This redirects you to http://localhost:8080/view/index – the first page you'll create, most likely.
http://localhost:8080/view/index
See oddmu(5) for details about the page formatting.
If you request a page that doesn't exist, Oddmu tries to find a matching Markdown file by appending the extension ".md" to the page name. In the example above, the page name requested is "index" and the file name Oddmu tries to read is "index.md". If no such file exists, Oddmu offers you to create the page.
If your files don't provide their own title ("# title"), the file name (without ".md") is used for the page title.
Every file can be viewed as feed by using the extension ".rss". The feed items are based on links in bullet lists using the asterix ("*").
Subdirectories are created as necessary.
The wiki knows the following actions for a given page name and (optional) directory:
When calling the *save* and *append* action, the page name is taken from the URL path and the page content is taken from the *body* form parameter. To illustrate, here's how to edit the "welcome" page using *curl*:
curl --form body="Did you bring a towel?" \ http://localhost:8080/save/welcome
When calling the *drop* action, the query parameters used are *name* for the target filename and *file* for the file to upload. If the query parameter *maxwidth* is set, an attempt is made to decode and resize the image. JPG, PNG, WEBP and HEIC files can be decoded. Only JPG and PNG files can be encoded, however. If the target name ends in *.jpg*, the *quality* query parameter is also taken into account. To upload some thumbnails:
for f in *.jpg; do curl --form name="$f" --form file=@"$f" --form maxwidth=100 \ http://localhost:8080/drop/ done
When calling the *search* action, the search terms are taken from the query parameter *q*.
curl 'http://localhost:8080/search/?q=towel'
The page name to act upon is optionally taken from the query parameter *id*. In this case, the directory must also be part of the query parameter and not of the URL path.
curl 'http://localhost:8080/view/?id=man/oddmu.1.txt'
The base name for the *archive* action is used by the browser to save the downloaded file. For Oddmu, only the directory is important. The following zips the *man* directory and saves it as *man.zip*.
curl --remote-name 'http://localhost:8080/archive/man/man.zip
The template files are the HTML files in the working directory. Please change these templates!
The first change you should make is to replace the name and email address in the footer of *view.html*. Look for "Your Name" and "example.org".
The second change you should make is to replace the name, email address and domain name in "feed.html". Look for "Your Name" and "example.org".
See oddmu-templates(5) for more.
You can change the port served by setting the ODDMU_PORT environment variable.
You can change the address served by setting the ODDMU_ADDRESS environment variable to either an IPv4 address or an IPv6 address. If ODDMU_ADDRESS is unset, then the program listens on all available unicast addresses, both IPv4 and IPv6. Here are a few example addresses:
ODDMU_ADDRESS=127.0.0.1 # The loopback IPv4 address. ODDMU_ADDRESS=2001:db8::3:1 # An IPv6 address.
See the Socket Activation section for an alternative method of listening which supports Unix-domain sockets.
In order to limit language-detection to the languages you actually use, set the environment variable ODDMU_LANGUAGES to a comma-separated list of ISO 639-1 codes, e.g. "en" or "en,de,fr,pt".
You can enable webfinger to link fediverse accounts to their correct profile pages by setting ODDMU_WEBFINGER to "1". See oddmu(5).
If you use secret subdirectories, you cannot rely on the web server to hide those pages because some actions such as searching and archiving include subdirectories. They act upon a whole tree of pages, not just a single page. The ODDMU_FILTER can be used to exclude subdirectories from such tree actions. See oddmu-filter(7) and oddmu-apache(5).
Instead of specifying ODDMU_ADDRESS or ODDMU_PORT, you can start the service through socket activation. The advantage of this method is that you can use a Unix-domain socket instead of a TCP socket, and the permissions and ownership of the socket are set before the program starts. See oddmu.service(5), oddmu-apache(5) and oddmu-nginx(5) for an example of how to use socket activation with a Unix-domain socket under systemd and Apache.
If the machine you are running Oddmu on is accessible from the Internet, you must secure your installation. The best way to do this is use a regular web server as a reverse proxy. See oddmu-apache(5) and oddmu-nginx(5) for example configurations.
Oddmu assumes that all the users that can edit pages or upload files are trusted users and therefore their content is trusted. Oddmu does not perform HTML sanitization!
For an extra dose of security, consider using a Unix-domain socket.
Oddmu can be run on the command-line using various subcommands.
When saving a page, the page name is take from the URL and the page content is taken from the "body" form parameter. To illustrate, here's how to edit a page using *curl*(1):
curl --form body="Did you bring a towel?" \ http://localhost:8080/save/welcome
To compute the space used by your setup, use regular tools:
du --exclude='*/\.*' --exclude '*~' --block-size=M
This is a minimal wiki. There is no version history. It's well suited as a *secondary* medium: collaboration and conversation happens elsewhere, in chat, on social media. The wiki serves as the text repository that results from these discussions.
The idea is that the webserver handles as many tasks as possible. It logs requests, does rate limiting, handles encryption, gets the certificates, and so on. The web server acts as a reverse proxy and the wiki ends up being a content management system with almost no structure – or endless malleability, depending on your point of view. See oddmu-apache(5).
Page names are filenames with ".md" appended. If your filesystem cannot handle it, it can't be a page name. Filenames can contain slashes and Oddmu creates subdirectories as necessary.
Files may not end with a tilde ('~') – these are backup files. When saving pages and file uploads, the old file renamed to the backup file unless the backup file is less than an hour old, thus collapsing all edits made in an hour into a single diff when comparing backup and current version.
The **index** page is the default page. People visiting the "root" of the site are redirected to "/view/index".
The **changes** page is where links to new and changed files are added. As an author, you can prevent this from happening by deselecting the checkbox "Add link to the list of changes." The changes page can be edited like every other page, so it's easy to undo mistakes.
Links on the changes page are grouped by date. When new links are added, the current date of the machine Oddmu is running on is used. If a link already exists on the changes page, it is moved up to the current date. If that leaves an old date without any links, that date heading is removed.
If you want to link to the changes page, you need to do this yourself. Add a link from the index, for example. The "view.html" template currently doesn't do it. See oddmu-templates(5) if you want to add the link to the template.
A page whose name starts with an ISO date (YYYY-MM-DD, e.g. "2023-10-28") is called a **blog** page. When creating or editing blog pages, links to it are added from other pages.
If the blog page name starts with the current year, a link is created from the index page back to the blog page being created or edited. Again, you can prevent this from happening by deselecting the checkbox "Add link to the list of changes." The index page can be edited like every other page, so it's easy to undo mistakes.
For every **hashtag** used, another link might be created. If a page named like the hashtag exists, a backlink is added to it, linking to the new or edited blog page.
If a link to the new or edited blog page already exists but it's title is no longer correct, it is updated.
New links added for blog pages are added at the top of the first unnumbered list using the asterisk ('*'). If no such list exists, a new one is started at the bottom of the page. This allows you to have a different unnumbered list further up on the page, as long as it uses the minus for items ('-').
Changes made locally do not create any links on the changes page, the index page or on any hashtag pages. See oddmu-notify(1) for a way to add the necessary links to the changes page and possibly to the index and hashtag pages.
A hashtag consists of a number sign ('#') followed by Unicode letters, numbers or the underscore ('_'). Thus, a hashtag ends with punctuation or whitespace.
The page names, titles and hashtags are loaded into memory when the server starts. If you have a lot of pages, this takes a lot of memory.
Oddmu watches the working directory and any subdirectories for changes made directly. Thus, in theory, it's not necessary to restart it after making such changes.
You cannot edit uploaded files. If you upload a file called "hello.txt" and attempt to edit it by using "/edit/hello.txt" you create a page with the name "hello.txt.md" instead.
In order to delete uploaded files via the web, create an empty file and upload it. In order to delete a wiki page, save an empty page.
Note that some HTML file names are special: they act as templates. See oddmu-templates(5) for their names and their use.
If you run Oddmu as a web server:
If you run Oddmu as a static site generator or pages offline and sync them with Oddmu running as a webserver:
If you want to stop using Oddmu:
Maintained by Alex Schroeder alex@gnu.org.