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;" ]
@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