A step-by-step guide for deploying a Rails application using Ansible, Docker, Nginx, and AWS EC2.
Table of Contents
Project Overview
This guide covers deploying a Ruby on Rails application using Ansible, Docker, Docker Compose, and Nginx. We will automate the setup using Ansible playbooks, configure Docker and Docker Compose for Rails, and set up Nginx as a reverse proxy on an AWS EC2 instance.
AWS EC2 Setup
Step 1: Launch an EC2 Instance
Follow these steps to set up an EC2 instance on AWS:
- Log in to the AWS Management Console.
- Navigate to the EC2 Dashboard and click on “Launch Instance.”
- Select an Amazon Machine Image (AMI), such as “Ubuntu Server 20.04 LTS.”
- Choose an instance type (e.g., t2.micro for testing purposes).
- Configure the instance’s security group to allow SSH (port 22) and HTTP (port 80) access.
- Launch the instance and download the .pem key file for SSH access.
Step 2: Configure Security Group
Ensure that the EC2 instance’s security group has the following rules:
Type | Protocol | Port Range | Source |
---|---|---|---|
SSH | TCP | 22 | 0.0.0.0/0 (or restrict to your IP for security) |
HTTP | TCP | 80 | 0.0.0.0/0 |
Step 3: SSH into EC2 Instance
Once the instance is running, SSH into it using the downloaded .pem key:
# Replace "your-key.pem" and "ec2-user@your-ec2-ip" with your key and instance IP
$ ssh -i "your-key.pem" ubuntu@your-ec2-ip
Environment Setup
Step 1: Install Ansible on Local Machine
First, install Ansible on your local machine. This allows you to run playbooks that automate deployment tasks on the remote server.
# Update package lists
$ sudo apt update
# Install Ansible
$ sudo apt install ansible -y
For more information, visit the Ansible Installation Guide.
Step 2: Configure SSH Access
Ensure you have SSH access to the target server. Generate an SSH key and copy it to the server:
# Generate SSH key (if not already created)
$ ssh-keygen -t rsa -b 4096
# Copy SSH key to the server
$ ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@your_server_ip
Setting Up Inventory and Group Variables
Inventory File
Create an inventory
file that lists your servers under the [rails_servers]
group:
[rails_servers]
your_ec2_ip ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/your-key.pem
Group Variables
Create a file named group_vars/rails_servers.yml
to define server-specific settings:
# Git repository details
git_repo_url: "https://your-username:your-password@github.com/your-username/your-repo.git"
# Application directory
app_directory: "/home/ubuntu/current"
# Database credentials
db_username: "postgres"
db_password: "secure_password"
# Server configuration
server_name: "your-server-name-or-ip"
Roles and Playbooks
Playbook Structure
Set up the directory structure for your Ansible project:
ansible_project/
├── group_vars/
│ └── rails_servers.yml
├── inventory
├── rails_deploy.yml
├── roles/
├── deploy_rails_app/
│ └── tasks/
│ └── main.yml
├── setup_docker/
│ └── tasks/
│ └── main.yml
└── setup_docker_compose/
└── tasks/
└── main.yml
Docker and Docker Compose Setup
Dockerfile for Rails Application
Create a Dockerfile in your Rails application directory to build a container image for the Rails app.
# Use an official Ruby runtime as a parent image
FROM ruby:3.2
# Set working directory in the container
WORKDIR /app
# Install dependencies
RUN apt-get update -qq && apt-get install -y \
nodejs \
npm
# Install Yarn for JavaScript dependencies
RUN npm install --global yarn
# Copy Gemfile and install gems
COPY Gemfile* ./
RUN bundle install
# Copy the rest of the application code
COPY . .
# Install JavaScript dependencies
RUN yarn install
# Expose port 3000 for the Rails app
EXPOSE 3000
# Default command to run Rails
CMD ["bin/dev"]
docker-compose.yml Configuration
Create a docker-compose.yml
file to manage the Rails and Nginx services.
version: '3'
services:
web:
build: .
command: bin/dev
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- db
environment:
- DATABASE_USERNAME=postgres
- DATABASE_PASSWORD=secure_password
db:
image: postgres:13
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
volumes:
postgres_data:
Nginx Configuration
Create an nginx.conf
file to configure Nginx as a reverse proxy:
worker_processes 1;
events { worker_connections 1024; }
http {
server {
listen 80;
location / {
proxy_pass http://web:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Executing the Playbook
Run the playbook to deploy the Rails application to your EC2 instance:
$ ansible-playbook rails_deploy.yml -i inventory
Command Table with Detailed Explanations
Command | Description |
---|---|
ansible-inventory --list -i inventory |
List all hosts in the inventory file to verify setup. |
ansible all -m ping -i inventory |
Ping all servers in the inventory to test connectivity. |
ansible-playbook rails_deploy.yml -i inventory |
Run the deployment playbook on all specified servers. |
docker-compose up -d |
Run Docker Compose to start services in detached mode. |
docker ps |
List all active Docker containers to verify deployment. |
Common Questions & Answers
Why use Ansible roles?
Ansible roles allow you to organize tasks, variables, and templates into modular, reusable components, making it easier to manage and maintain your playbooks.
How do I securely manage sensitive data?
Use ansible-vault
to encrypt files containing sensitive information, such as passwords or API keys, to keep them secure.
Best Practices
- Use
ansible-vault
for sensitive data. - Keep your Dockerfiles and Ansible roles modular.
- Use environment variables for configuration flexibility.
- Test with
--check
flag to ensure safety before deploying.