Skip to content

Instantly share code, notes, and snippets.

@satendra02
Last active October 21, 2024 06:09
Show Gist options
  • Save satendra02/1b335b06bfc5921df486f26bd98e0e89 to your computer and use it in GitHub Desktop.
Save satendra02/1b335b06bfc5921df486f26bd98e0e89 to your computer and use it in GitHub Desktop.
docker+rails+puma+nginx+postgres (Production ready)
Create docker folder in app root
-app_name
-app
-db
-config
-database.yml
...
-docker
-app
-DockerFile
-web
-DockerFile
-nginx.conf
-docker-compose.yml
FROM ruby:2.3.1
# Install dependencies
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
# Set an environment variable where the Rails app is installed to inside of Docker image:
ENV RAILS_ROOT /var/www/app_name
RUN mkdir -p $RAILS_ROOT
# Set working directory, where the commands will be ran:
WORKDIR $RAILS_ROOT
# Setting env up
ENV RAILS_ENV='production'
ENV RACK_ENV='production'
# Adding gems
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install --jobs 20 --retry 5 --without development test
# Adding project files
COPY . .
RUN bundle exec rake assets:precompile
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
default: &default
adapter: postgresql
encoding: unicode
username: postgres
password:
pool: 5
host: db
production:
<<: *default
database: app_name_production
version: '3'
volumes:
postgres_data: {}
services:
app:
build:
context: .
dockerfile: ./docker/app/DockerFile
depends_on:
- db
db:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
web:
build:
context: .
dockerfile: ./docker/web/DockerFile
depends_on:
- app
ports:
- 80:80
# This is a template. Referenced variables (e.g. $RAILS_ROOT) need
# to be rewritten with real values in order for this file to work.
upstream rails_app {
server app:3000;
}
server {
# define your domain
server_name www.example.com;
# define the public application root
root $RAILS_ROOT/public;
index index.html;
# define where Nginx should write its logs
access_log $RAILS_ROOT/log/nginx.access.log;
error_log $RAILS_ROOT/log/nginx.error.log;
# deny requests for files that should never be accessed
location ~ /\. {
deny all;
}
location ~* ^.+\.(rb|log)$ {
deny all;
}
# serve static (compiled) assets directly if they exist (for rails production)
location ~ ^/(assets|images|javascripts|stylesheets|swfs|system)/ {
try_files $uri @rails;
access_log off;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
# send non-static file requests to the app server
location / {
try_files $uri @rails;
}
location @rails {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://rails_app;
}
}
# Base image:
FROM nginx
# Install dependencies
RUN apt-get update -qq && apt-get -y install apache2-utils
# establish where Nginx should look for files
ENV RAILS_ROOT /var/www/app_name
# Set our working directory inside the image
WORKDIR $RAILS_ROOT
# create log directory
RUN mkdir log
# copy over static assets
COPY public public/
# Copy Nginx config template
COPY docker/web/nginx.conf /tmp/docker.nginx
# substitute variable references in the Nginx config template for real values from the environment
# put the final config in its place
RUN envsubst '$RAILS_ROOT' < /tmp/docker.nginx > /etc/nginx/conf.d/default.conf
EXPOSE 80
# Use the "exec" form of CMD so Nginx shuts down gracefully on SIGTERM (i.e. `docker stop`)
CMD [ "nginx", "-g", "daemon off;" ]
@fguillen
Copy link

@satendra02 when you write RAKE_ENV do you mean RACK_ENV

@belgoros
Copy link

belgoros commented Aug 1, 2018

@fguillen: puma accepts RACK_ENV, so I think you are right and the following line:

ENV RAKE_ENV='production'

should be changed to:

ENV RACK_ENV='production'

@satendra02
Copy link
Author

@belgoros @fguillen: Yes exactly it should be RACK_ENV, It was a typo. Updated the gist.

@fera2k
Copy link

fera2k commented Oct 16, 2018

How to you expose $RAILS_ROOT/public folder, inside 'app' image into 'web' nginx image ?

I'm trying a similar setup, but I want to NGINX to serve all static files and in my case, my Nginx doesn´t see files generated inside app container/image.

@satendra02
Copy link
Author

@fera2k Read the detailed blog I have written. Also go through the comments section as well.

https://itnext.io/docker-rails-puma-nginx-postgres-999cd8866b18

Hope it helps

@monteirobrena
Copy link

The @rails should be @rails_app?

@satendra02
Copy link
Author

satendra02 commented Aug 2, 2019

@monteirobrena Check out detailed response here.

@ksbek
Copy link

ksbek commented Nov 8, 2019

assets give me 404 error.
assets folder is not created on web container.
public folder is empty.
# copy over static assets COPY public public/
Can you help me?
@satendra02

@satendra02
Copy link
Author

Hi @ksbek,

Make sure you are keeping your static assets inside the public folder in your application.

The COPY command just copying your application public folder to the web container public folder.

Please send me a detailed mail with the error log I will look at it.

@belkhiriaa
Copy link

@satendra02 this means that the assets should be compiled from local terminal and not in the app.Dockerfile

@belkhiriaa
Copy link

Here is a nice article presenting 3 different ways, on how to expose rails assets to nginx with docker:
https://medium.com/faun/three-methods-to-share-rails-assets-with-nginx-f39c90bb7d68
Enjoy ;)

@theankushjain
Copy link

My ruby application doesn't have an index.html page. Any request coming to it is redirected to login page using routes.rb. What should I specify in place of index.html while configuring nginx?

@Bodlund
Copy link

Bodlund commented Sep 2, 2020

assets give me 404 error.
assets folder is not created on web container.
public folder is empty.
# copy over static assets COPY public public/
Can you help me?
@satendra02

Changing "COPY public public/" to "COPY public/ public/" will solve a lot of your headaches. This will copy the public/assets folder content also and will result in no 404 on your assets requests for Nginx.

@joaoscotto
Copy link

I created a project with the recent versions of ruby and rails. I wrote a post too, you can see my post and repository:
https://scotto.medium.com/2021-docker-ruby-3-rails-6-puma-nginx-postgres-d84c95f68637

@satendra02
Copy link
Author

satendra02 commented May 10, 2021

I created a project with the recent versions of ruby and rails. I wrote a post too, you can see my post and repository:
https://scotto.medium.com/2021-docker-ruby-3-rails-6-puma-nginx-postgres-d84c95f68637

@joaoscotto That's Great. I am going to link this up in my medium blog

@truonglocbinh
Copy link

How can I apply it on production server like EC2 ?

@daniel-reinhold
Copy link

Looks pretty good, but how do we run our migrations?

@truonglocbinh
Copy link

Looks pretty good, but how do we run our migrations?

You can try docker-compose run app bundle exec rails db:migrate

@flyfy1
Copy link

flyfy1 commented Jul 3, 2021

How about blue-green deployment?

@JoaoPedroAssis
Copy link

Looks pretty good, but how do we run our migrations?

You can add a start.sh to the root of your project and make it the entry point of your container. The file looks something like this:

#!/bin/sh

# Run database migrations
rails db:migrate

# Init server
bundle exec puma -C config/puma.rb

With this script you can customize your app startup process

@nejdetkadir
Copy link

I want to run migrations when project dockerize. Can anyone help me?

@satendra02
Copy link
Author

@nejdetkadir Check this SO answer to run migrations on docker container

@vishalsabhaya
Copy link

@satendra02
thank you for sharing.
I am using.
ruby "3.1.2"
gem "rails", "> 7.0.3"
gem "puma", "
> 5.0"

I tried with the same configuration. but I am facing an issue with the below error. can you teach me? how can i solve this error?
`bundler: failed to load command: puma (/usr/local/bundle/bin/puma)

/usr/local/bundle/gems/puma-5.6.4/lib/puma/dsl.rb:83:in `read': No such file or directory @ rb_sysopen - config/puma.rb (Errno::ENOENT)

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/dsl.rb:83:in `_load_from'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/configuration.rb:219:in `block in load'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/configuration.rb:219:in `each'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/configuration.rb:219:in `load'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/launcher.rb:60:in `initialize'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/cli.rb:72:in `new'

from /usr/local/bundle/gems/puma-5.6.4/lib/puma/cli.rb:72:in `initialize'

from /usr/local/bundle/gems/puma-5.6.4/bin/puma:8:in `new'

from /usr/local/bundle/gems/puma-5.6.4/bin/puma:8:in `<top (required)>'

from /usr/local/bundle/bin/puma:25:in `load'

from /usr/local/bundle/bin/puma:25:in `<top (required)>'

from /usr/local/lib/ruby/3.1.0/bundler/cli/exec.rb:58:in `load'

from /usr/local/lib/ruby/3.1.0/bundler/cli/exec.rb:58:in `kernel_load'

from /usr/local/lib/ruby/3.1.0/bundler/cli/exec.rb:23:in `run'

from /usr/local/lib/ruby/3.1.0/bundler/cli.rb:484:in `exec'

from /usr/local/lib/ruby/3.1.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'

from /usr/local/lib/ruby/3.1.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'

from /usr/local/lib/ruby/3.1.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'

from /usr/local/lib/ruby/3.1.0/bundler/cli.rb:31:in `dispatch'

from /usr/local/lib/ruby/3.1.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'

from /usr/local/lib/ruby/3.1.0/bundler/cli.rb:25:in `start'

from /usr/local/lib/ruby/gems/3.1.0/gems/bundler-2.3.7/libexec/bundle:48:in `block in <top (required)>'

from /usr/local/lib/ruby/3.1.0/bundler/friendly_errors.rb:103:in `with_friendly_errors'

from /usr/local/lib/ruby/gems/3.1.0/gems/bundler-2.3.7/libexec/bundle:36:in `<top (required)>'

from /usr/local/bin/bundle:25:in `load'

from /usr/local/bin/bundle:25:in `

'


`

@satendra02
Copy link
Author

@vishalsabhaya please check this comment

@vishalsabhaya
Copy link

@satendra02 thank you for response.
I referred that comment yesterday.
it’s working fine.

@ftdev23
Copy link

ftdev23 commented Jun 6, 2023

@satendra02
Thank you for this collection.
Do you mind also adding a config for Sidekiq as well ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment