This is a step by step solution for running rails on a docker instance with nginx and pagespeed.
For www.epicpxls.com we are running Rails 5.2 so I wanted to transition from using passenger to nginx and leverage some of the modules of pagespeed.
What I intended to do was to use docker images that already have what I needed implemented. I also used some blog posts and other tutorials I found as a guide and I’ll list them at the bottom.
All of the code is in a gist I made so it can easily be navigated and updated:
What we’ll use:
- Ruby (2.6.6 but it’s easy to change this)
- Rails (5.2 but any version would do)
- Docker compose
What is the structure?
We’ll have 5 docker instances, the rails app, the nginx server, the redis, the db & the memcached instance.
Create the docker structure
First create a folder called docker in the rails application root. The structure of the directory should be as follows:
The DockerFile for the app
Create the docker/app/DockerFile with the following contents:
Notice here that I’m using ruby 2.6.6 but you can change that to what version you need based on the docker image.
I’m also using the Aptfile packages and installing those in case there are any defined. So in your root rails app you can add the Aptfile with any packages you need.
I’m also copying the entrypoint.sh file that is used as a cleanup script. It goes in and removes any server.pid file inside the app structure.
Last steps are for gem installation and asset precompilation.
The DockerFile for the server
This DockerFile is using a docker image that has nginx + pagespeed built.
The main thing I’m doing here is copying the various nginx configuration files into the /etc/nginx folder.
The Nginx configuration
Here I made different files to hold each component. It makes the whole structure easier to read and navigate. The biggest one is the pagespeed.conf file. I copied the documentation and added that over each filter to easily understand what you might want on and off.
The main nginx configuration:
The performance configuration:
The routing configuration:
The pagespeed configuration:
Create the docker compose file
Let’s wrap all of the above together into a docker-compose.yml file that sits in the root of the app.
The file defines the configuration for all instances that we need. In our case: rails, nginx, postgresql, redis and memcached.
Bonus: create a Makefile
To make things faster and shorter to trigger I also made a MakeFile. It holds some of the commands I use the most.
What happened to our server?
This is of course a short period of time but I wanted to show the difference.
For the heroku server for the sake of simplicity I decided to have 100% the same nginx structure and configuration as above but to utilise a buildpack (https://github.com/benmurden/nginx-pagespeed-buildpack).
We also have jemalloc but that was there before and it did not make a huge difference. https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
This is the main structure that I made for the docker implementation.
Next step after getting all of this together is to build the whole system. Using the Makefile above you can just run:
Next you have to start all the docker instances with:
You can access the application by opening the browser and typing http://localhost
Other tutorials/links that helped me:
- Gist docker+rails+puma+nginx+postgres (Production ready)
- Docker + Rails + Puma + Nginx + Postgres
- (2021) Docker + Ruby 3 + Rails 6 + Puma + Nginx + Postgres
- Docker image build for rails with: Aptfile, node
- Heroku buildpack nginx pagespeed
- Docker image for nginx + pagespeed
- Compile nginx module as a dynamic module for docker
- Docker image with nginx + passenger + pagespeed
- Build pagespeed from source