I received a Raspberry Pi 3 Model B last Christmas, but I did not know what to do with. Or at least not yet. The problem has little to do with the Pi and more of the fact that most of the projects that I do can easily be solved with an Arduino.
When I stumbled upon these series of posts by the Docker Captain Alex Ellis, I figured out that this is a perfect opportunity to learn a tool I have always wanted to use. I know virtual machines well, but I had a hard time understanding how to make Docker fit into my workflow. The idea of containers that I cannot simply SSH into (I now know that you can exec
bash to peek inside them, but that's not the point), just seemed absurd when I was first trying to use it. To be honest it felt too complex and cumbersome that I just dismissed it as something that was not worth it. Well, it turned out that I did not understand the philosophy behind it. I would like to talk about it and discuss images and containers in depth, but I decided that it will be better to have a dedicated post for that. After getting my hands dirty with Docker last weekend, I can say that I have attained a working proficiency with it and I can comfortably use it for my projects from here on.
After three days, I finally got it to work. The blog that you are reading right now is hosted on a Raspberry Pi with Docker Engine installed. I have two Docker containers running: the Ghost blog and the NGINX server that handles the caching. It took me a lot of trial and errors before I finally got it to work; I do not have any prior knowledge of NGINX when I embarked on this weekend project. The Pi's limited hardware made building images painstakingly slow. Building SQLite3 from source for the ARM architecture was excruciating.
I will be sharing my Dockerfiles and some configuration below. I won't go into more detail right now, but I am hoping that I will have the time to do so in my next post. Some of these are directly forked/copied from [Alex]((http://blog.alexellis.io)'s GitHub repositories; I could have pulled the images from Docker Hub or cloned the Dockerfiles but I decided to train my muscle memory by typing the Dockerfiles manually. I still have a lot to learn about NGINX and Docker in particular, but I consider this blog as a milestone.
Ghost Dockerfile
FROM alexellis2/node4.x-arm:latest
USER root
WORKDIR /var/www/
RUN mkdir -p ghost
RUN apt-get update && \
apt-get -qy install wget unzip && \
wget https://github.com/TryGhost/Ghost/releases/download/0.11.4/Ghost-0.11.4.zip && \
unzip Ghost-*.zip -d ghost && \
apt-get -y remove wget unzip && \
rm -rf /var/lib/apt/lists/*
RUN useradd ghost -m -G www-data -s /bin/bash
RUN chown ghost:www-data .
RUN chown ghost:www-data ghost
RUN chown ghost:www-data -R ghost/*
RUN npm install -g pm2
USER ghost
WORKDIR /var/www/ghost
RUN /bin/bash -c "time (npm install sqlite3)"
RUN npm install
EXPOSE 2368
EXPOSE 2369
RUN ls && pwd
ENV NODE_ENV production
RUN sed -e s/127.0.0.1/0.0.0.0/g ./config.example.js > ./config.js
CMD ["pm2", "start", "index.js", "--name", "blog", "--no-daemon"]
Blog Dockerfile
FROM johncrisostomo/ghost-on-docker-arm:0.11.4
ADD Vapor /var/www/ghost/content/themes/Vapor
RUN sed -i s/my-ghost-blog.com/blog.johncrisostomo.com/g config.js
NGINX Dockerfile
FROM resin/rpi-raspbian:latest
RUN apt-get update && apt-get install -qy nginx
WORKDIR /etc/nginx/
RUN rm /var/www/html/index.nginx-debian.html && \
rm sites-available/default && \
rm sites-enabled/default && \
rm nginx.conf
COPY nginx.conf /etc/nginx/
COPY johncrisostomo.com.conf conf.d/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
JOHNCRISOSTOMO.COM.CONF
server {
listen 80;
server_name blog.johncrisostomo.com;
access_log /var/log/nginx/blog.access.log;
error_log /var/log/nginx/blog.error.log;
location / {
proxy_cache blog_cache;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_ignore_headers Cache-Control;
proxy_cache_valid any 10m;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://blog:2368;
}
}
docker-compose.yml
version: "2.0"
services:
nginx:
ports:
- "80:80"
build: "./nginx/"
restart: always
blog:
ports:
- "2368:2368"
build: "./blog.johncrisostomo.com/"
volumes:
- ghost_apps:/var/www/ghost/content/apps
- ghost_data:/var/www/ghost/content/data
- ghost_images:/var/www/ghost/content/images
- ghost_themes:/var/www/ghost/content/themes
restart: always
volumes:
ghost_apps:
driver: local
ghost_data:
driver: local
ghost_images:
driver: local
ghost_themes:
driver: local
I have written several follow up posts about this project. Feel free to check them out as most of them are troubleshooting issues and optimizations that are built on top of this project.