Diary

Welcome! :-)

This is both a wiki (a website editable by all) and a blog (an online diary about the stuff Alex Schroeder reads and does). If you’re a friend or relative, you might be interested in reading Life instead of this page. If you’ve come here from an RPG blog, you might want to head over to RPG. There are other similar categories to be found on the SiteMap.

Für Rollenspieler gibt es ebenfalls eine eigene RSP Kategorie.

2016-06-23 Perl MIME Tools

Gaah!

alex@kallobombus:~$ cpanm MIME::Tools
--> Working on MIME::Tools
Fetching http://www.cpan.org/authors/id/D/DS/DSKOLL/MIME-tools-5.507.tar.gz ... OK
Configuring MIME-tools-5.507 ... OK
Building and testing MIME-tools-5.507 ... FAIL
! Installing MIME::Tools failed. See /home/alex/.cpanm/work/1466665678.15341/build.log for details. Retry with --force to force install it.

Dianne says: “Confirmed. MailTools 2.15 changed the way headers are parsed.” [1]

Thus:

alex@kallobombus:~$ cpanm http://search.cpan.org/CPAN/authors/id/M/MA/MARKOV/MailTools-2.14.tar.gz
--> Working on http://search.cpan.org/CPAN/authors/id/M/MA/MARKOV/MailTools-2.14.tar.gz
Fetching http://search.cpan.org/CPAN/authors/id/M/MA/MARKOV/MailTools-2.14.tar.gz ... OK
Configuring MailTools-2.14 ... OK
Building and testing MailTools-2.14 ... OK
Successfully installed MailTools-2.14
1 distribution installed
alex@kallobombus:~$ cpanm MIME::Tools
--> Working on MIME::Tools
Fetching http://www.cpan.org/authors/id/D/DS/DSKOLL/MIME-tools-5.507.tar.gz ... OK
Configuring MIME-tools-5.507 ... OK
Building and testing MIME-tools-5.507 ... OK
Successfully installed MIME-tools-5.507
1 distribution installed

Tags:

Add Comment

2016-06-22 Love

Yesterday I was running my game and we’re once again going off into unprepared territory. We’re approaching a small town called Corkbridge in the Outlands (Planescape), halfling apple farmers, the party is looking for a healer and so there’s this hedge wizard halfling, they knock at her door, and I’m trying to think of something surprising to say. So… uhhh… “She has tears in her eyes as she opens the door but wipes them away as looks at you and asks how she can help you.”

The players are surprised! Good. OK, they’ll probably want to help, so how about something even more surprising… uh, she doesn’t want our help! “A personal thing, family. Nothing you can do but thank you for offering to help.”

The players are intrigued. Good! They decide to invite her to the inn and gain her confidence over a drink to two, and so she goes with them and tells her the sad story of her brother and his failing marriage, his wife always going off and him being angry and sad and alone, and jealous. The players nod and look at each other. Nothing to do here, they agree.

The wizard leaves and the innkeeper shows them their room. On a whim, he says: “So, she told you about her brother, eh? Married an adventurer he did. And she’s always off, can’t just stay and work the orchards, always chasing after some rumors, looking for treasure and all that.” The players nod and grin and remember a former halfling player character. He continues, “So how’s your love life? Anybody waiting for you at home, hoping you’ll come back, hoping that this time you’ll stay?” And he goes around the table, asking the player characters.

Too busy studying books and magic, says one. I’m a frog man and we don’t really do relationships, you know, says the other. One day I’ll retire to Monkey Island and there will be other giant apes like me and I’ll find myself a woman and settle down, says the third. I loved it.

Tags:

Add Comment

2016-06-18 Trade Barriers

Techdirt published Beijing Regulators Block Sales Of iPhones, Claiming The Design Is Too Close To Chinese Company's Phone and gave me a chuckle. “Until US patent officials finally understand that patents are not about innovation, but are really about restraints on trade, innovation and competition, we’re only going to see more and more stories like this.”

Tags:

Add Comment

2016-06-16 Blütenpracht

I created a new gallery with pictures of flowers I see on the way to work. Who ever decided to let wild flowers grow along the tram between Bahnhof Altstetten and Toni Areal: Thank you!

Flowers

Tags:

Comments on 2016-06-16 Blütenpracht

Awesome.

– AlexDaniel 2016-06-17 20:18 UTC

Add Comment

2016-06-15 Oddmuse and Windows

Today I ran the Oddmuse test suite on Windows and it worked! I am amazed.

All tests successful.
Files=136, Tests=2907, 1028 wallclock secs ( 0.41 usr  0.45 sys + 211.30 cusr 219.98 csys = 432.14 CPU)
Result: PASS

I had already installed Cygwin and had used it to install Perl v5.22.2. I don’t think I ever ran cpan on this system because I had to set it up. It created $USERPROFILE/AppData/Roaming/perl5/ for me and set up local::lib.

And then I started installing.

I needed some libraries and a compiler which I installed via Cygwin. I already had the diff utils installed, but perhaps you never needed them. Oddmuse needs them.

diffutils
gcc-g++
libcrypt-devel
libexpat-devel
libxml2-devel
libgd-devel
libdb-devel

Then I started by installing cpanm.

cpan App::cpanminus

I had to add /usr/local/bin to my PATH.

cpanm CGI XML::Atom IO::Pipely Mojolicious Mojolicious::Plugin::CGI Toadfarm HTTP::Server::Simple Pod::Strip Crypt::Rijndael Crypt::Random::Seed RPC::XML HTML::Template Capture::Tiny MLDBM Captcha::reCAPTCHA DB_File XML::LibXML GD Time::ParseDate

And with that, I could finally run prove t. I’ll note, however, that make test caused t/big-brother.t to fail, perhaps because it runs with 4 jobs which overwhelmed my machine.

Tags:

Comments on 2016-06-15 Oddmuse and Windows

Perhaps add that info here: https://oddmuse.org/wiki/Unit_Testing ?

– AlexDaniel 2016-06-17 20:18 UTC


Good idea.

– Alex Schroeder 2016-06-17 21:00 UTC

Add Comment

2016-06-09 If I run a Science Fiction RPG

I was looking at Ed Ortiz’s post, To Vesper Skies: Prologue, where he talks about aliens:

“The crazier, the better. So I want my game to have a decent amount of playable alien races from the get go. Of course, you have to wonder, where humans fit in all this. With exotic races with some weird abilities, how do you make the baseline humans more interesting?”

And I’m reminded of two things:

  1. “In essence, we’d be Space Orcs.” You can follow the thread up an down on Tumble to find variations on that theme.
  2. “But if you’re hurt, if you’re trapped, if you need someone to fetch help? You really want a human.” Such a lovely thing.

All the aliens would be smaller, weaker, brittle, lonely, vulnerable, inflexible. Perhaps richer, perhaps more cunning, perhaps more powerful, but we are mammals.

Tags:

Add Comment

2016-06-01 Rules

Court rules in favor of cloned tabletop game – No protection under US copyright law: «The court points out that “Unlike a book or movie plot, the rules and procedures, including the winning conditions, that make up a card-game system of play do not themselves produce the artistic or literary content that is the hallmark of protectable expression.” They note that past game copyright victories were won by parties based on infringement of visual appearance or other protectable elements.»

Tags:

Add Comment

2016-05-31 letsencrypt.sh instead

I’ve been using the official Let’s Encrypt client, now Certbot on GitHub, using the webroot plugin, but then I saw Andreas Gohr’s blog post Simple Let's Encrypt on Debian/Apache, based on the German post letsencrypt.sh, based on Lukas Schauer’s letsencrypt.sh on GitHub.

Setting it up required a bit of fiddling.

I created the so-called BASEDIR /etc/letsencrypt.sh, with an empty domains.txt file, the suggested hook.sh and a config (no longer config.sh!) as follows:

hook.sh:

#!/bin/bash

if [ ${1} == "deploy_cert" ]; then
    echo " + Hook: Restarting Apache..."
    service apache2 reload
else
    echo " + Hook: Nothing to do..."
fi

config:

BASEDIR="/etc/letsencrypt.sh/"
WELLKNOWN="/var/www/letsencrypt.sh/"
PRIVATE_KEY="${BASEDIR}/private_key.pem"
HOOK="${BASEDIR}/hook.sh"
CONTACT_EMAIL="kensanata@gmail.com"

I also created /var/www/letsencrypt.sh/. These are the permissions and ownership I’m looking for:

drwxr-xr-x 2 www-data www-data 4096 May 31 12:50 letsencrypt.sh

I followed the Import from official letsencrypt client instructions. In the bash file, I had to set BASEDIR="/etc/letsencrypt.sh" or it wouldn’t work, and I had to run it as root. This created the certs subdirectory in my BASEDIR with all the certificates and it populated the domains.txt file. I had to look over the list of domains because five out of six domains didn’t have the www subdomain I wanted. Probably because the very first time I made those calls I had forgotten about them.

The perl file just required me to cpanm --sudo Crypt::OpenSSL::RSA and cpanm --sudo Crypt::OpenSSL::Bignum. The result of calling it I piped into private_key.pem in my BASEDIR.

For all my sites, I replaced all the .pem locations.

Old:

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/alexschroeder.ch/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/alexschroeder.ch/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/alexschroeder.ch/chain.pem
SSLVerifyClient None

New:

SSLEngine on
SSLCertificateFile /etc/letsencrypt.sh/certs/alexschroeder.ch/cert.pem
SSLCertificateKeyFile /etc/letsencrypt.sh/certs/alexschroeder.ch/privkey.pem
SSLCertificateChainFile /etc/letsencrypt.sh/certs/alexschroeder.ch/chain.pem
SSLVerifyClient None

Do this for all sites in sites-enabled.

Don’t forget to place the following in /etc/apache2/conf.d/letsencrypt:

Alias /.well-known/acme-challenge /var/www/letsencrypt.sh/

<Directory /var/www/letsencrypt.sh/>
        Options None
        AllowOverride None
        Order allow,deny
        Allow from all
</Directory>

When I ran ~/src/letsencrypt.sh/letsencrypt.sh -c the first time, I got an error, presumably because I had forgotten to restart Apache and so the challenge wasn’t being served:

alex@kallobombus:~/src/letsencrypt.sh$ sudo ~/src/letsencrypt.sh/letsencrypt.sh -c
# INFO: Using main config file /etc/letsencrypt.sh/config
Processing alexschroeder.ch with alternative names: www.alexschroeder.ch
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: alexschroeder.ch
 + Configured names: alexschroeder.ch www.alexschroeder.ch
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:16:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for alexschroeder.ch...
 + Requesting challenge for www.alexschroeder.ch...
 + Hook: Nothing to do...
 + Responding to challenge for alexschroeder.ch...
 + Hook: Nothing to do...
ERROR: Challenge is invalid! (returned: invalid) (result: {
...
})

When I tried to sudo service apache2 reload I got an error in my config. The problem was that my config was referring to the chain.pem but the import script hadn’t copied it over!

I was forced to run something like the following: cd /etc/letsencrypt.sh/certs; for d in *; do echo $d; cp -i /etc/letsencrypt/live/$d/chain.pem /etc/letsencrypt.sh/certs/$d/chain-1464687792.pem; cd /etc/letsencrypt.sh/certs/$d; ln -s chain-1464687792.pem chain.pem; done (I had picked the timestamp by looking at the other files).

Finally reloading Apache worked.

Just to be sure, I created a little text file as /var/www/letsencrypt.sh/test and tried to read it using https://alexschroeder.ch/.well-known/acme-challenge/test. That seemed to work.

And now it worked!

alex@kallobombus:~$ sudo ~/src/letsencrypt.sh/letsencrypt.sh -c
# INFO: Using main config file /etc/letsencrypt.sh/config
Processing alexschroeder.ch with alternative names: www.alexschroeder.ch
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: alexschroeder.ch
 + Configured names: alexschroeder.ch www.alexschroeder.ch
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:16:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for alexschroeder.ch...
 + Requesting challenge for www.alexschroeder.ch...
 + Hook: Nothing to do...
 + Responding to challenge for alexschroeder.ch...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.alexschroeder.ch...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!
Processing arabisch-lernen.org with alternative names: www.arabisch-lernen.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug  6 17:27:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing campaignwiki.org with alternative names: www.campaignwiki.org
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: campaignwiki.org
 + Configured names: campaignwiki.org www.campaignwiki.org
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:17:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for campaignwiki.org...
 + Requesting challenge for www.campaignwiki.org...
 + Hook: Nothing to do...
 + Responding to challenge for campaignwiki.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.campaignwiki.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!
Processing communitywiki.org with alternative names: www.communitywiki.org
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: communitywiki.org
 + Configured names: communitywiki.org www.communitywiki.org
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:17:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for communitywiki.org...
 + Requesting challenge for www.communitywiki.org...
 + Hook: Nothing to do...
 + Responding to challenge for communitywiki.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.communitywiki.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!
Processing korero.org with alternative names: www.korero.org
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: korero.org
 + Configured names: korero.org www.korero.org
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:18:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for korero.org...
 + Requesting challenge for www.korero.org...
 + Hook: Nothing to do...
 + Responding to challenge for korero.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.korero.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!
Processing oddmuse.org with alternative names: www.oddmuse.org
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: oddmuse.org
 + Configured names: oddmuse.org www.oddmuse.org
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:18:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for oddmuse.org...
 + Requesting challenge for www.oddmuse.org...
 + Hook: Nothing to do...
 + Responding to challenge for oddmuse.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.oddmuse.org...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!
Processing orientalisch.info with alternative names: www.orientalisch.info
 + Checking domain name(s) of existing cert... changed!
 + Domain name(s) are not matching!
 + Names in old certificate: orientalisch.info
 + Configured names: orientalisch.info www.orientalisch.info
 + Forcing renew.
 + Checking expire date of existing cert...
 + Valid till Jun 10 09:18:00 2016 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for orientalisch.info...
 + Requesting challenge for www.orientalisch.info...
 + Hook: Nothing to do...
 + Responding to challenge for orientalisch.info...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Hook: Nothing to do...
 + Responding to challenge for www.orientalisch.info...
 + Hook: Nothing to do...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Hook: Restarting Apache...
[ ok ] Reloading web server config: apache2.
 + Done!

Note the message saying that Apache is reloading.

And to verify it, I use curl and look for the line saying “expire date”:

alex@kallobombus:~$ curl --verbose --head --silent https://alexschroeder.ch/
* About to connect() to alexschroeder.ch port 443 (#0)
*   Trying 127.0.0.1...
* connected
* Connected to alexschroeder.ch (127.0.0.1) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server key exchange (12):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*        subject: CN=alexschroeder.ch
*        start date: 2016-05-31 09:32:00 GMT
*        expire date: 2016-08-29 09:32:00 GMT
*        subjectAltName: alexschroeder.ch matched
*        issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*        SSL certificate verify ok.
...

Yay!

Now all I have to do is install this.

I copied /home/alex/src/letsencrypt.sh/letsencrypt.sh to /etc/letsencrypt.sh/letsencrypt.sh and created the file /etc/cron.weekly/letsencrypt.sh which calls it:

#!/bin/sh
exec /etc/letsencrypt.sh/letsencrypt.sh -c

I made sure to grant it +x permissions, too. :)

And now, just to test things, let’s run the cron job:

alex@kallobombus:~$ sudo /etc/cron.weekly/letsencrypt.sh
# INFO: Using main config file /etc/letsencrypt.sh/config
Processing alexschroeder.ch with alternative names: www.alexschroeder.ch
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:32:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing arabisch-lernen.org with alternative names: www.arabisch-lernen.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug  6 17:27:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing campaignwiki.org with alternative names: www.campaignwiki.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:32:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing communitywiki.org with alternative names: www.communitywiki.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:32:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing korero.org with alternative names: www.korero.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:32:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing oddmuse.org with alternative names: www.oddmuse.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:33:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...
Processing orientalisch.info with alternative names: www.orientalisch.info
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 29 09:33:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...

Very nice.

Tags:

Comments on 2016-05-31 letsencrypt.sh instead

I really should read the draft for the ACME protocol (via their GitHub).

– Alex Schroeder 2016-05-31 13:56 UTC


I did the same for Emacs Wiki. Since I’m using nginx as the front-end, there are small differences. Here’s the excerpt from /etc/nginx/sites-enabled/emacswiki:

server {
        listen 443 ssl;
        server_name www.emacswiki.org po6.ferrier.me.uk;

        # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.4.6&openssl=1.0.1f&hsts=yes&profile=modern
        # using Nginx, Modern, Server Version 1.4.6 and OpenSSL Version 1.0.1f with HSTS
        ssl_certificate     /etc/letsencrypt.sh/certs/www.emacswiki.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt.sh/certs/www.emacswiki.org/privkey.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;

        # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
        # using openssl dhparam -out dhparam.pem 2048
        ssl_dhparam         /etc/nginx/dhparam.pem;

        # modern configuration. tweak to your needs.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
        ssl_prefer_server_ciphers on;

        # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        # are we ready?
        # add_header Strict-Transport-Security max-age=15768000;

        # OCSP Stapling ---
        # fetch OCSP records from URL in ssl_certificate and cache them
        ssl_stapling on;
        ssl_stapling_verify on;

        # verify chain of trust of OCSP response using Root CA and Intermediate certs
        # https://community.letsencrypt.org/t/will-does-the-letsencrypt-client-create-a-cert-chain-usable-with-ocsp-stapling/2072/15
        ssl_trusted_certificate /etc/letsencrypt/live/www.emacswiki.org/chain.pem;

        ...

        location /.well-known/acme-challenge {
                 alias /var/www/letsencrypt.sh/;
        }
}

And /etc/letsencrypt.sh/hook.sh is also different, of course:

#!/bin/bash
if [ ${1} == "deploy_cert" ]; then
    echo " + Hook: Reloading Nginx..."
    service nginx reload
else
    echo " + Hook: Nothing to do..."
fi

And the output:

# INFO: Using main config file /etc/letsencrypt.sh/config
Processing www.emacswiki.org with alternative names: emacswiki.org
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 14 06:27:00 2016 GMT (Longer than 30 days). Skipping renew!
 + Hook: Nothing to do...

– Alex Schroeder 2016-06-10 09:16 UTC

Add Comment

2016-05-31 Zombie Apocalypse on the Toadfarm

I’ve been using the Toadfarm/Mojolicious/Oddmuse setup for alexschroeder.ch for quite a while, now. I’ve decided I wanted to switch to a similar setup for emacswiki.org, but small differences keep annoying me. I already wrote about my inability to start and stop the user process using Monit. Here’s another problem: Even though I’m not using the toadfarm at the moment (port 80 is nginx acting as the proxy cache for Apache which runs on port 8080 where as Toadfarm runs on port 8081 and thus isn’t getting used unless I use it – plus port scanners, I guess), zombies are accumulating.

Today I killed and restarted Toadfarm and all the zombies were cleaned up. Good! But that doesn’t sounds like a good solution. What could be the difference between alexschroeder.ch and emacswiki.org to result in one system accumulating lots of zombies?

emacswiki.org:

One hundred zombies

alexschroeder.ch:

Null pr

I noticed that on the system that doesn’t have a zombie problem, I’ve been using some older software. Let’s upgrade the working system and see whether the zombies start appearing. I know something is wrong about this line of reasoning but I can’t help thinking that newer is better.

Perl Module alexschroeder.ch emacswiki.org
Toadfarm 0.670.74
Mojolicious 6.196.62
Mojolicious::Plugin::CGI0.230.32

So, a few hours ago I upgrade the software on alexschroeder.ch. When looking at the following numbers, remember that Toadfarm on emacswiki.org is basically not being used.

emacswiki.org:

One

alexschroeder.ch:

A thousand zombie

I’ve added the following rule to my Monit setup:

    if children > 250 then restart

The result after a few hours:

The reaper

I already dread trying to convince the developers that they broke something in that recent upgrade.

On the same server, I have a pure Toadfarm/Mojolicious application that doesn’t use Mojolicious::Plugin::CGI which I just restarted. Let’s see whether korero.org also starts accumulating zombies.

For the moment, korero.org after a restart (and thus using the new versions of Toadfarm and Mojolicious):

alex@kallobombus:~/korero.org$ sudo ps fax|grep korero\\.org
 6239 ?        Ss     0:00 /home/alex/korero.org/server.pl
 6240 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6241 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6242 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6243 ?        S      0:00  \_ /home/alex/korero.org/server.pl

As compared to alexschroeder.ch (using the new versions of Toadfarm and Mojolicious and Mojolicious::Plugin::CGI):

alex@kallobombus:~/korero.org$ sudo ps fax|grep "farm.*defunct"|wc -l
243
alex@kallobombus:~/korero.org$ sudo ps fax|grep farm\\b|tail
 5991 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 5992 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 5999 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6001 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6013 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6246 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6293 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6322 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6460 ?        Z      0:00      \_ [/home/alex/farm] <defunct>
 6545 ?        Z      0:00      \_ [/home/alex/farm] <defunct>

A little stress testing showed that Mojolicious::Plugin::CGI must be the culprit.

Sending a few hundred requests to korero.org, which doesn’t use Mojolicious::Plugin::CGI using this:

I=1; for f in *; do I=$(( $I+1 )); (curl --silent https://korero.org/ > test$I &); done

Checking for zombies:

alex@kallobombus:~$ sudo ps fax|grep korero
 9021 pts/0    S+     0:00              \_ grep korero
 6239 ?        Ss     0:00 /home/alex/korero.org/server.pl
 6240 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6241 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6242 ?        S      0:00  \_ /home/alex/korero.org/server.pl
 6243 ?        S      0:00  \_ /home/alex/korero.org/server.pl

No zombies!

Let’s check how many zombies there are for alexschroeder.ch, which uses Mojolicious::Plugin::CGI:

alex@kallobombus:~$ sudo ps fax|grep "farm.*defunct"|wc -l
161

Sending a few hundred requests:

I=1; for f in *; do I=$(( $I+1 )); (curl --silent https://alexschroeder.ch/ > test$I &); done

Count zombies again:

alex@kallobombus:~$ sudo ps fax|grep "farm.*defunct"|wc -l
500

OK, so next is to figure out when this change appeared.

The only strange thing is that for emacswiki.org, which uses Mojolicious::Plugin::CGI, but doesn’t get much traffic, the zombie count has stayed at 1. Let’s test it!

Count:

kensanata@po6:~$ sudo ps fax|grep \\bdefunct | wc -l
1

Stress:

I=1; for f in test*; do I=$(( $I+1 )); (curl --silent http://www.emacswiki.org:8081/wiki > test$I &); done

Count:

kensanata@po6:~$ sudo ps fax|grep \\bdefunct | wc -l
15

Hm, that’s not a lot. I wonder what’s going on. A file that isn’t being closed? A log file that cannot be written to?

Well, the bug apparently got introduced in Mojolicious::Plugin::CGI 0.27. Note that in the following output, the one hit I keep getting is the grep process itself. ;-)

alex@kallobombus:~$ cd src/mojolicious-plugin-cgi/
alex@kallobombus:~/src/mojolicious-plugin-cgi$ git checkout 0.25
Previous HEAD position was 035d5e3... Released version 0.24
HEAD is now at 5df5779... Released version 0.25
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo monit restart toadfarm                                                                                         alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo ps fax|grep "farm.*defunct"|wc -l
1
alex@kallobombus:~/src/mojolicious-plugin-cgi$ for i in `seq 100`; do (curl --silent https://alexschroeder.ch/ > /dev/null &); done
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo ps fax|grep "farm.*defunct"|wc -l
1
alex@kallobombus:~/src/mojolicious-plugin-cgi$ git checkout 0.26
Previous HEAD position was 5df5779... Released version 0.25
HEAD is now at dd98a07... Released version 0.26
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo monit restart toadfarm
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo ps fax|grep "farm.*defunct"|wc -l
1
alex@kallobombus:~/src/mojolicious-plugin-cgi$ for i in `seq 100`; do (curl --silent https://alexschroeder.ch/ > /dev/null &); done
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo ps fax|grep "farm.*defunct"|wc -l
1
alex@kallobombus:~/src/mojolicious-plugin-cgi$ git checkout 0.27
Previous HEAD position was dd98a07... Released version 0.26
HEAD is now at 83949da... Released version 0.27
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo monit restart toadfarm
alex@kallobombus:~/src/mojolicious-plugin-cgi$ for i in `seq 100`; do (curl --silent https://alexschroeder.ch/ > /dev/null &); done
alex@kallobombus:~/src/mojolicious-plugin-cgi$ sudo ps fax|grep "farm.*defunct"|wc -l
41

I’m going to leave it at 0.26 and then I can look at it when I have some time.

Looking g

One way to do it:

cpanm --sudo https://cpan.metacpan.org/authors/id/J/JH/JHTHORSEN/Mojolicious-Plugin-CGI-0.26.tar.gz

Tags:

Comments on 2016-05-31 Zombie Apocalypse on the Toadfarm

I opened an issue on GitHub, and I wrote a test to go along with it.

– Alex Schroeder 2016-06-03 11:04 UTC


And it was merged!

– Alex Schroeder 2016-06-07 22:17 UTC

Add Comment

2016-05-31 Monit strangeness

I’m using Toadfarm on two machines. I can start the farm using my own username, and monitor it using Monit, but I can’t start or stop the farm using Monit – even though I use “as uid” and “as gid”:

check process toadfarm with pidfile /home/kensanata/farm/farm.pid
    start program = "/home/kensanata/farm/farm start" as uid "kensanata" and gid "kensanata"
    stop program = "/home/kensanata/farm/farm stop"
    ...

Weird.

At first, I thought that this actually worked on the older machine, but as it turns out, it never worked. I wonder why.

I rewrote it as follows:

check process toadfarm with pidfile /home/kensanata/farm/farm.pid
    start program = "/bin/bash -c '/home/kensanata/farm/farm start &> /home/kensanata/farm/start.log'" as uid kensanata
    stop program = "/bin/bash -c '/home/kensanata/farm/farm stop &> /home/kensanata/farm/stop.log'" as uid kensanata
    ...

The log file revealed that the hypnotoad executable was not on the path. So I added the following to my farm file:

$ENV{PATH} .= ":/usr/local/bin";

Now it will start – but not serve! I’m assuming this has to do with permissions somehow?

I think I’m giving up…

kensanata@po6:~/farm$ cat start.log
Server available at http://www.emacswiki.org:8081
farm (17832) started.

Testing:

alex@Megabombus:~$ curl http://www.emacswiki.org:8081/wiki
curl: (52) Empty reply from server

It takes a bit longer than 15s… Looks like an Oddmuse timeout?

I give up. I even added a call to id:

kensanata@po6:~/farm$ cat start.log
uid=1001(kensanata) gid=1001(kensanata) groups=1001(kensanata),0(root)
Server available at http://www.emacswiki.org:8081
farm (18294) started.

It looks good, but it doesn’t work.

I tried to make sure that I’m not using any relative paths. Log file, script, everything is getting absolute paths. And I’ve made some progress. I’m finally seeing some Mojolicious logs:

kensanata@po6:~/farm$ cat farm.log 
[Wed Jun  1 00:14:25 2016] [info] Mounting emacs with conditions
[Wed Jun  1 00:14:25 2016] [info] Loading plugin Toadfarm::Plugin::AccessLog
[Wed Jun  1 00:14:26 2016] [info] Mounting emacs with conditions
[Wed Jun  1 00:14:26 2016] [info] Loading plugin Toadfarm::Plugin::AccessLog
[Wed Jun  1 00:14:26 2016] [info] Listening at "http://www.emacswiki.org:8081"
[Wed Jun  1 00:14:26 2016] [info] Manager 19291 started
[Wed Jun  1 00:14:26 2016] [debug] Worker 19292 started
[Wed Jun  1 00:14:26 2016] [debug] Worker 19293 started
[Wed Jun  1 00:14:26 2016] [info] Creating process id file "/home/kensanata/farm/farm.pid"
[Wed Jun  1 00:14:26 2016] [debug] Worker 19295 started
[Wed Jun  1 00:14:26 2016] [debug] Worker 19294 started
[Wed Jun  1 00:14:36 2016] [debug] GET "/wiki"
[Wed Jun  1 00:14:36 2016] [debug] Routing to application "Mojolicious::Lite"
[Wed Jun  1 00:14:36 2016] [debug] Routing to a callback
[Wed Jun  1 00:14:36 2016] [debug] [CGI:CODE(0x2740360):19299] START /home/kensanata/farm/wiki.pl
[Wed Jun  1 00:14:36 2016] [error] STDERR: : Permission denied at /usr/local/share/perl/5.18.2/Mojolicious/Plugin/CGI.pm line 62.
...

I wonder what this is.

The code in question:

 open STDERR, $STDERR[0], $STDERR[1] or die "STDERR: @$stderr: $!";

Ah! There was an error logfile with not absolute path… Good, fixed, works!

So now, this is how Monit starts the Toadfarm:

kensanata@po6:~/farm$ sudo cat /etc/monit/conf.d/toadfarm.conf
check process toadfarm with pidfile /home/kensanata/farm/farm.pid
    start program = "/home/kensanata/farm/farm start" as uid www-data and gid www-data
    stop program = "/home/kensanata/farm/farm stop" as uid www-data and gid www-data
    if failed host www.emacswiki.org port 8081 type tcp protocol http
      and request "/wiki" for 5 cycles then restart
    if totalmem > 500 MB for 5 cycles then restart
    if 3 restarts within 15 cycles then timeout

This defines the Toadfarm:

kensanata@po6:~/farm$ cat farm
#! /usr/bin/perl
use Toadfarm -init;

$ENV{PATH} .= ":/usr/local/bin";

logging {
  combined => 1,
  file     => "/home/kensanata/farm/farm.log",
  level    => "debug",
};

my $farm = '/home/kensanata/farm';

mount "$farm/emacs.pl" => {
  "Host" => qr{www.emacswiki.org:8081$},
  mount_point => '/wiki',
};

plugin "Toadfarm::Plugin::AccessLog";

start ["http://www.emacswiki.org:8081"], {proxy => 1}; # needs to be at the last line

(Must change “debug” back to “warn”!)

The wiki itself:

kensanata@po6:~/farm$ cat emacs.pl
#! /usr/bin/env perl
use Mojolicious::Lite;

plugin CGI => {
  support_semicolon_in_query_string => 1,
};

plugin CGI => {
  route => '/',
  script => '/home/kensanata/farm/wiki.pl',
  run => \&OddMuse::DoWikiRequest,
  before => sub {
      my $c = shift;
      $OddMuse::RunCGI = 0;
      $OddMuse::DataDir = '/home/kensanata/emacswiki';
      require '/home/kensanata/farm/wiki.pl' unless defined &OddMuse::DoWikiRequest;
  },
  env => {},
  errlog => '/home/kensanata/farm/emacs.log', # path to where STDERR from cgi script goes
};

app->start;

Note all the absolute paths. :)

This server is now also running a Toadfarm started by Monit. Yay!

Don’t forget permissions: key files and directories need to belong to www-data.kensanata (my user’s group so that I can also edit these files).

  1. the farm directory needs to be writable by www-data so that the pid file can be written; without it, Monit can start the toadfarm but will still claim it failed (pid file is missing) and stopping it will also fail (use ps fax to figure out which process to sudo kill)
  2. the farm log needs to be writable by www-data so that the toadfarm can log
  3. the application log file needs to be writable by www-data so that the wiki itself can log

To wit:

kensanata@po6:~$ ls -la farm
total 1368
drwxrwxr-x  2 www-data  kensanata    4096 Jun  2 17:00 .
drwxr-xr-x 12 kensanata kensanata    4096 Jun  1 00:24 ..
-rw-r--r--  1 www-data  kensanata   27935 Jun  2 16:34 emacs.log
-rw-rw-r--  1 kensanata kensanata     549 Jun  1 00:22 emacs.pl
-rw-rw-r--  1 kensanata kensanata     528 Jun  1 00:12 emacs.pl~
-rwxrwxr-x  1 kensanata kensanata     432 Jun  2 16:32 farm
-rwxrwxr-x  1 kensanata kensanata     433 Jun  1 00:13 farm~
-rw-r--r--  1 www-data  kensanata 1002606 Jun  2 16:34 farm.log
-rw-r--r--  1 www-data  www-data        5 Jun  2 17:00 farm.pid
-rw-rw-r--  1 kensanata kensanata     322 May 29 12:01 Makefile
-rw-rw-r--  1 kensanata kensanata     384 May 29 11:59 Makefile~
-rwxrwxr-x  1 kensanata kensanata  159959 Jun  1 00:10 wiki.pl
-rwxrwxr-x  1 kensanata kensanata  159988 Jun  1 00:07 wiki.pl~

And why is that? Because I want the process to have few permissions elsewhere, and the existing wiki is being run as a CGI script by Apache using www-data which is why the data directory has the same ownership – owned by user www-data and writable by a group I belong to.

Tags:

Add Comment

More...

Comments


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. 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.

Referrers: Gothridge Manor Back to the Dungeon!: Gamer Music: Uriah Heep - The Wizard Dreams of Mythic Fantasy ZENOPUS ARCHIVES rsp-blogs.de Planet Emacsen ... in der Mitte der ZauberFerne