2018-10-08 Setting up Oddmuse 6

Here’s what I needed to do in order to get the Oddmuse 6 wiki up an running.

I downloaded and compiled the latest Rakudo Star sources (2018.06).

Install cro and Oddmuse 6:

zef install --/test cro
zef install Oddmuse6

🔥 When installing dependencies using zef as shown, you could be running into an OpenSSL issue even if you have the correct development libraries installed. On Debian, you need libssl-dev but apparently versions 1.1.0f and 1.1.0g won’t work. See issue #34. You could decide to ignore SSL support and opt to have a web server act as a proxy which provides SSL. That’s what I intend to do. In which case there is a terrible workaround available: run zef install --force-test IO::Socket::Async::SSL before you zef install Oddmuse6.

Create a new application. Remember that installing cro printed a message telling you where the binary got installed. I’m assuming you added $HOME/rakudo/share/perl6/site/bin to your PATH.

Start with a stub and accept all the defaults:

cro stub http oddmuse6 oddmuse6

Now edit oddmuse6/services.p6 and replace use Routes with use Oddmuse::Routes.

You can delete the oddmuse6/lib/Routes.pm6 which cro stub generated for you.

Your default wiki directory is oddmuse6/wiki, so we need to tell cro to ignore it. If you don’t, you’ll confuse cro to no end as soon as you start editing files! Add the following section section to your in oddmuse6/.cro.yml file:

ignore:
  - wiki/

Run it:

cd oddmuse6
cro run

Check it out by visiting http://localhost:20000. Your wiki is ready! 🙃

But this is not enough. I needed to get my own domain. My name service provider for oddmuse.org is Gandi so I logged in, found the entry and added a new subdomain called next pointing at the same IP, basically a copy of the www subdomain.

Next, I tell Apache about it. I’m using Dehydrated to get my oddmuse.org certificates from Let’s Encrypt and I’m just going to reuse them.

In the file /etc/dehydrated/domains.txt I added the new next.oddmuse.org domain:

oddmuse.org www.oddmuse.org next.oddmuse.org

Then I ran /usr/bin/dehydrated -c as root to check and possibly renew all my certificates.

I’m using Apache as my webserver. I edited /etc/apache2/sites-enabled/500-oddmuse.org.conf and added two new sections for next.oddmuse.org.

The first redirects HTTP traffic to HTTPS:

<VirtualHost *:80>
    ServerName next.oddmuse.org
    Redirect permanent / https://next.oddmuse.org/
</VirtualHost>

The second redirects all HTTPS traffic it receives back to HTTP on port 20000, which is where Oddmuse 6 is listening.

<VirtualHost *:443>
    ServerAdmin alex@oddmuse.org
    ServerName next.oddmuse.org

    RewriteEngine on
    RewriteCond "%{HTTP_USER_AGENT}" "Mastodon"
    RewriteRule ".*" "-" [redirect=403,last]

    SSLEngine on
    SSLCertificateFile      /var/lib/dehydrated/certs/oddmuse.org/cert.pem
    SSLCertificateKeyFile   /var/lib/dehydrated/certs/oddmuse.org/privkey.pem
    SSLCertificateChainFile /var/lib/dehydrated/certs/oddmuse.org/chain.pem
    SSLVerifyClient None

    ProxyPass /             http://next.oddmuse.org:20000/

</VirtualHost>

Thus, all connections to the wiki are encrypted. What about people connecting to port 20000 directly? Well, I have a file called /etc/apache2/conf-enabled/security.conf which has a few settings including this one:

# Setting this header will prevent access via HTTP.
# Requires mod_headers to be enabled.
# See https://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1.2
# The number of seconds is the equivalent of one year.
#
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

The rewrite rule for Mastodon is a simple defence against the spikes I get when I share links to my sites. In a second, all the servers seeing the link attempt to fetch a preview image and in order to avoid overloads, I just disallow these.

So now, finally, requests end up as simple HTTP on 20000. Unfortunately, the wiki is listening on localhost, not next.oddmuse.org.

So I wrote a little wrapper script to set all the options, write a PID file and all that. I called it ~/bin/oddmuse6.

#!/bin/bash
pidfile=$HOME/oddmuse6/nohup.pid
if test -f $pidfile; then
    echo Killing $(cat $pidfile)
    kill -SIGTERM $(cat $pidfile)
fi

export ODDMUSE_MENU="Home, Changes, About"
export ODDMUSE_QUESTION="Name a colour of the rainbow."
export ODDMUSE_ANSWER="red, orange, yellow, green, blue, indigo, violet"
export ODDMUSE_SECRET="rainbow-unicorn"
export ODDMUSE_HOST="next.oddmuse.org"
export ODDMUSE_PORT=20000

cd $HOME/oddmuse6
rm nohup.out
nohup /home/alex/rakudo/bin/perl6 service.p6 &
tail nohup.out
echo $! > $pidfile

But that still isn’t enough because ODDMUSE_HOST and ODDMUSE_PORT actually don’t match the environment variables used in oddmuse6/service.p6. Each cro service gets to environment variables that determine its host and its port. Their names depend on the name you provided when you called cro stub. If you called it oddmuse6 like I did in the example above, the two environment variables you need are called ODDMUSE6_HOST and ODDMUSE6_PORT. I just changed them to ODDMUSE_HOST and ODDMUSE_PORT in service.p6.

As you can see from the shell script, I’m not even using cro run to run my wiki. I’m using perl6 directly. I’ll have to think about that. I suspect there are benefits of using cro run when you use multiple applications. At the moment I don’t, so perl6 it is.

Since I’m not using cro run you could delete all these other files, actually. You really just need service.p6 and the wiki subdirectory.

The content of service.p6 is simple:

use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Oddmuse::Routes;

my Cro::Service $http = Cro::HTTP::Server.new(
    http => <1.1>,
    host => %*ENV<ODDMUSE_HOST> ||
        die("Missing ODDMUSE_HOST in environment"),
    port => %*ENV<ODDMUSE_PORT> ||
        die("Missing ODDMUSE_PORT in environment"),
    application => routes(),
    after => [
        Cro::HTTP::Log::File.new(logs => $*OUT, errors => $*ERR)
    ]
);
$http.start;
say "Listening at http://%*ENV<ODDMUSE_HOST>:%*ENV<ODDMUSE_PORT>";
react {
    whenever signal(SIGINT) {
        say "Shutting down...";
        $http.stop;
        done;
    }
}

Check it out: Oddmuse 6.

Tags:

Comments


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.