Setting up multiple Rails applications on a single DigitalOcean droplet can be a highly efficient way to manage resources and reduce costs, especially if you're running several small to medium-sized apps. This guide will walk you through setting up multiple Rails apps on a single droplet, configuring Redis for Turbo and ActionCable, securing your setup with SSL and firewalls, monitoring system resources, and implementing a CI/CD pipeline to automate deployments using `zsh`.
Prerequisites
Before we start, make sure you have:
- A DigitalOcean account with a droplet running Ubuntu (or a similar Linux distribution).
- Basic knowledge of the terminal, Rails, and server management.
- Domains set up to point to your droplet (for example: `app1.example.com` and `app2.example.com`).
Step 1: Initial Droplet Setup with Zsh
1.1. Update and Upgrade the System
First, ensure your droplet's packages are up to date:
sudo apt update && sudo apt upgrade -y
1.2. Install Necessary Dependencies
Install essential tools like Git, Curl, and Build Tools for compiling Ruby:
sudo apt install -y git curl build-essential libssl-dev libreadline-dev zlib1g-dev
1.3. Install Zsh and Make it the Default Shell
To install and switch to `zsh`, use the following commands:
sudo apt install zsh chsh -s $(which zsh)
Log out and log back in to start using `zsh`.
1.4. Install Oh My Zsh (Optional)
Oh My Zsh is a helpful framework for managing your zsh configuration. Install it like this:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
After installation, customize your `.zshrc` as needed, and don't forget to source it:
source ~/.zshrc
1.5. Install Rbenv for Ruby Management
To manage Ruby versions across multiple Rails apps, use `rbenv`:
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/main/bin/rbenv-installer | zsh echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc echo 'eval "$(rbenv init -)"' >> ~/.zshrc source ~/.zshrc
Install Ruby:
rbenv install 3.1.2 rbenv global 3.1.2
Note: You want to make sure to install a current version of ruby, or install the version that is required by the application which you wish to host.
Step 2: Install Passenger with Nginx
We’ll install Passenger, which is an easy-to-use web and application server that integrates seamlessly with Nginx. Follow these steps to install Passenger properly on your system.
2.1. Install Necessary Tools for Passenger
Before installing Passenger, you need to ensure your system has HTTPS support and PGP key management tools:
sudo apt-get install -y dirmngr gnupg apt-transport-https ca-certificates curl
2.2. Add the Phusion Passenger PGP Key
Download and add the Passenger PGP key:
curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null
2.3. Add the Passenger APT Repository
Next, add the Passenger APT repository to your sources list:
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger noble main > /etc/apt/sources.list.d/passenger.list'
2.4. Update Package List and Install Passenger
Update the package list to include the new Passenger repository, and then install Passenger:
sudo apt-get update sudo apt-get install -y passenger
2.5. Verify Passenger Installation
Finally, verify that Passenger is installed and configured correctly. If you’re using Passenger with Nginx, check the Nginx configuration:
sudo nginx -t
If the configuration is valid, restart Nginx to apply the changes:
sudo systemctl restart nginx
Step 3: Configure Nginx for Multiple Applications
Now that Passenger is installed and integrated with Nginx, let’s configure Nginx to serve multiple Rails apps using Passenger.
For each Rails app, we'll create a separate Nginx configuration file.
Nginx Config for `app1`
Create the config file `/etc/nginx/sites-available/app1`:
server { listen 80; server_name app1.example.com; root /home/deploy/apps/app1/current/public; passenger_enabled on; passenger_ruby /home/deploy/.rbenv/shims/ruby; location / { try_files $uri/index.html $uri @app1; } location @app1 { passenger_enabled on; passenger_app_root /home/deploy/apps/app1/current; } location /cable { passenger_app_root /home/deploy/apps/app1/current; passenger_enabled on; passenger_set_header Upgrade $http_upgrade; passenger_set_header Connection "Upgrade"; passenger_set_header Host $host; passenger_set_header X-Real-IP $remote_addr; passenger_set_header X-Forwarded-For $proxy_add_x_forwarded_for; passenger_set_header X-Forwarded-Proto $scheme; } error_page 500 502 503 504 /500.html; }
Repeat the process for `app2` with the appropriate paths and server name.
Enable the Nginx config for each app:
sudo ln -s /etc/nginx/sites-available/app1 /etc/nginx/sites-enabled/ sudo ln -s /etc/nginx/sites-available/app2 /etc/nginx/sites-enabled/ sudo systemctl restart nginx
Step 3: Set Up Redis for Turbo, Hotwire, and ActionCable
Redis is used by Rails to handle Turbo streams and ActionCable connections. You can configure Redis for each app to use a different namespace or Redis database to avoid conflicts.
3.1. Install Redis
Install Redis on your droplet:
sudo apt install redis-server sudo systemctl enable redis-server
3.2. Configure Redis for Each App
For `app1`
In `config/cable.yml`, configure Redis to use database 1 and a namespace for `app1`:
production: adapter: redis url: redis://localhost:6379/1 channel_prefix: app1_production
For `app2`
In `config/cable.yml`, configure Redis to use database 2 for `app2`:
production: adapter: redis url: redis://localhost:6379/2 channel_prefix: app2_production
3.3. Secure Redis
Edit Redis configuration to bind it to localhost, making it accessible only from the droplet:
sudo nano /etc/redis/redis.conf
Change the `bind` directive:
bind 127.0.0.1
Restart Redis:
sudo systemctl restart redis-server
Step 4: Secure Your Setup with SSL and Firewalls
4.1. Install SSL Certificates with Certbot
Use Certbot to obtain SSL certificates for your domains:
sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d app1.example.com sudo certbot --nginx -d app2.example.com
Certbot will automatically configure Nginx to use SSL. Set up auto-renewal:
sudo certbot renew --dry-run
4.2. Configure DigitalOcean Firewall
- Go to "Networking > Firewalls" in your DigitalOcean dashboard.
- Create a firewall rule that:
- Allows SSH (port 22) only from your IP address.
- Allows HTTP (port 80) and HTTPS (port 443) for all.
- Blocks Redis from external access (only allow `localhost` access).
Step 5: Automate Deployment with Capistrano
Capistrano is a powerful tool that automates deployment steps like fetching code, running migrations, and restarting the server.
5.1. Install Capistrano for Each App
In each Rails app, add Capistrano to your `Gemfile`:
gem 'capistrano', '~> 3.16' gem 'capistrano-rails' gem 'capistrano-passenger' gem 'capistrano-rbenv'
Run Capistrano's installer:
bundle exec cap install
5.2. Configure Capistrano for Each App
Edit `config/deploy.rb` for `app1`:
set :application, "app1" set :repo_url, "git@github.com:your-username/app1.git" set :deploy_to, "/home/deploy/apps/app1" set :rbenv_ruby, '3.0.2' set :passenger_restart_with_touch, true # Shared config files and directories append :linked_files, 'config/database.yml', '.env' append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets'
Configure the server in `config/deploy/production.rb`:
server 'your-droplet-ip', user: 'deploy', roles: %w{app db web}
Run the following to deploy the app:
bundle exec cap production deploy
Repeat this for `app2`.
Step 6: Set Up Log Management and Monitoring
6.1. Install Logrotate for Log Management
Logrotate prevents your logs from growing indefinitely. Create a config file for Nginx logs:
sudo nano /etc/logrotate.d/nginx
Add the following:
/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 640 root adm sharedscripts postrotate [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid` endscript }
Repeat this for Rails logs (`/home/deploy/apps/app1/log/*.log`).
6.2. Monitor Redis and System Usage
Monitor Redis:
redis-cli monitor
To check memory usage:
redis-cli info memory
Monitor System Resources with `htop`:
sudo apt-get install htop htop
Alternatively, use DigitalOcean's monitoring tools in the dashboard to set up alerts for CPU, memory, and disk usage.
Conclusion
By following this detailed guide, you've now set up a powerful server capable of running multiple Rails applications on a single DigitalOcean droplet, with Redis handling real-time features for Turbo and ActionCable, automated deployments via Capistrano, secure SSL-encrypted traffic, and proper resource management. This setup is highly scalable and efficient, allowing you to add more apps or increase your server's capacity as needed.