OddMuse Wiki Dockerized

Created 2018-02-05 / Edited 2018-02-05

I Dockerized this website yesterday! I had already built a cpanfile that declares the Perl5 dependencies of OddMuse, which made it easy. I'm also going to run this with the data directory directly bind-mounted.

First the Dockerfile:

FROM perl:latest

# Set up the deploy user
ARG uid=1000
ARG gid=1000
RUN echo groupadd -g $gid deploy
RUN groupadd -g $gid deploy
RUN useradd --create-home -u $uid -g $gid -ms /bin/bash deploy

WORKDIR /app

COPY cpanfile .
RUN cpanm -qn --installdeps .

USER deploy

The bit of fancyness here is the deploy user setup. Since I'm mounting the project directory for data files, I'd like new files and edits to be done by my normal user. On my cloud-server, this is uid 1000, which is easy to set as the default. On my laptop I run as user 1001, so the file is parameterized for this case. When I run locally, I have to build my docker image with docker build --build-arg uid=$(id -u) --build-arg gid=$(id -g). Not as much fun.

Otherwise, this starts with the Perl5 base image and installs the CPAN dependencies.

Next, the docker-compose.yml

version: '3'

services:

  web:
    build: .
    command: starman --workers=10 --max-requests=1 --access-log starman-access.log --error-log starman-error.log oddmuse.psgi
    volumes:
      - ".:/app"
    ports:
      - "5000" # For running locally

  nginx-ssl-proxy:
    image: danieldent/nginx-ssl-proxy
    restart: always
    environment:
      UPSTREAM: web:5000
      SERVERNAME: thelackthereof.org
      EXTRANAMES: www.thelackthereof.org
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/etc/letsencrypt"
    depends_on:
      - web

The first service runs cpan:Starman (this is similar to Unicorn for you Ruby folk). It mounts the project directory as /app, and runs oddmuse.psgi. We declare port 5000 anyway for local debugging -- we can then run only this service and it'll come up on a randomly assigned port that connects to port 5000. Other services on this network can connect to "web:5000" even without this declaration.

Which brings us to the second fancy bit. The danieldent/nginx-ssl-proxy image is a super cool image that gives an nginx proxy with automatic letsencrypt setup! You declare the domain name and the proxy destination (web:5000 is our Starman), and assuming that domain really is pointing here, it will work with letsencrypt to verify ownership and make certificates. The certs are stored in a docker-managed volume, and are periodically renewed. This takes less than a minute, so even if the volume gets accidentally deleted we can easily get a new cert.

Now running "docker-compose up -d" starts nginx and starman running in the background. All that remains is getting this running on boot. Since the startup command can be run over and over, worst case you can put it in a cronjob that runs frequently :)