Skip to content

Instantly share code, notes, and snippets.

@mickzijdel
Last active May 17, 2025 13:01
Show Gist options
  • Select an option

  • Save mickzijdel/2c5d1ab56b80f9b5a5ac1f0f7e634f4a to your computer and use it in GitHub Desktop.

Select an option

Save mickzijdel/2c5d1ab56b80f9b5a5ac1f0f7e634f4a to your computer and use it in GitHub Desktop.
# Existing content..
# Ignore master key for decrypting credentials and more.
/config/master.key
/config/credentials/*
# config/database.yml
# PostgreSQL. Versions 9.3 and up are supported.
#
# Install the pg driver:
# gem install pg
# On macOS with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem "pg"
#
# Warning: This is different from the default, even though it does not affect production.
# I prefer storing my development database credentials in the Rails credentials, but use whatever method you prefer.
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= Rails.application.credentials.dig(:database, :username) %>
password: <%= Rails.application.credentials.dig(:database, :password) %>
host: localhost
development:
<<: *default
database: <your-service-name>_development
# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: <your-service-name>_test
# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
# production:
# url: <%= ENV["MY_APP_DATABASE_URL"] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
production:
primary: &primary_production
<<: *default
username: <%= ENV["POSTGRES_USER"] %>
database: <%= ENV["POSTGRES_DB"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
host: <%= ENV["DB_HOST"] %>
port: 5432
cache:
<<: *primary_production
database: <%= ENV["POSTGRES_DB"] %>_cache
migrations_paths: db/cache_migrate
queue:
<<: *primary_production
database: <%= ENV["POSTGRES_DB"] %>_queue
migrations_paths: db/queue_migrate
cable:
<<: *primary_production
database: <%= ENV["POSTGRES_DB"] %>_cable
migrations_paths: db/cable_migrate
# config/deploy.yml
# Name of your application. Used to uniquely configure containers.
service: <your-service-name>
# Name of the container image.
# <your-user> is your Docker Hub username or the username for your private registry.
image: <your-user>/<your-service-name>
# Deploy to these servers.
servers:
web:
- <your-server-ip>
# job:
# hosts:
# - 192.168.0.1
# cmd: bin/jobs
# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server.
# Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer.
#
# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption.
proxy:
ssl: true
host: app.example.com
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
username: <your-user>
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .kamal/secrets).
env:
secret:
- RAILS_MASTER_KEY
- POSTGRES_PASSWORD
clear:
# Run the Solid Queue Supervisor inside the web server's Puma process to do jobs.
# When you start using multiple servers, you should split out job processing to a dedicated machine.
SOLID_QUEUE_IN_PUMA: true
DB_HOST: <your-service-name>-postgres
POSTGRES_USER: <your-service-name>
POSTGRES_DB: <your-service-name>_production
# Set number of processes dedicated to Solid Queue (default: 1)
# JOB_CONCURRENCY: 3
# Set number of cores available to the application on each server (default: 1).
# WEB_CONCURRENCY: 2
# Log everything from Rails
# RAILS_LOG_LEVEL: debug
# Aliases are triggered with "bin/kamal <alias>". You can overwrite arguments on invocation:
# "bin/kamal logs -r job" will tail logs from the first server in the job section.
aliases:
console: app exec --interactive --reuse "bin/rails console"
shell: app exec --interactive --reuse "bash"
logs: app logs -f
dbc: app exec --interactive --reuse "bin/rails dbconsole"
# Use a persistent storage volume for sqlite database files and local Active Storage files.
# Recommended to change this to a mounted volume path that is backed up off server.
volumes:
- "<your-service-name>_storage:/rails/storage"
# Bridge fingerprinted assets, like JS and CSS, between versions to avoid
# hitting 404 on in-flight requests. Combines all files from new and old
# version inside the asset_path.
asset_path: /rails/public/assets
# Configure the image builder.
builder:
arch: amd64
# # Build image via remote server (useful for faster amd64 builds on arm64 computers)
# remote: ssh://docker@docker-builder-server
#
# # Pass arguments and secrets to the Docker build process
# args:
# RUBY_VERSION: ruby-3.4.1
# secrets:
# - GITHUB_TOKEN
# - RAILS_MASTER_KEY
# Use a different ssh user than root
ssh:
user: deploy
# Use accessory services (secrets come from .kamal/secrets).
accessories:
postgres:
image: postgres:15
host: <your-server-ip>
# If you define a port here, that port will be accessible from the host machine.
# This means that you cannot use the same port for multiple services/accessories.
# This will cause issues if you have multiple services with a postgres accessory,
# and you will need to modify which port each accessory uses by modifying the number before the :.
# You can still access the database using `<your-service-name>-psotgres` as the hostname and `5432` as the port
# regardless of which port you expose here.
# Warning: If you remove the `127.0.0.1` part, this port is exposed to the world.
# port: "127.0.0.1:5432:5432"
env:
clear:
# Make sure this perfectly matches the POSTGRES_USER value defined above in the env section.
POSTGRES_USER: <your-service-name>
secret:
- POSTGRES_PASSWORD
files:
- db/production_setup.sql:/docker-entrypoint-initdb.d/setup.sql
directories:
- data:/var/lib/postgresql/data
# redis:
# image: redis:7.0
# host: 192.168.0.2
# port: 6379
# directories:
# - data:/data
# Add this before rails assets:precompile at roughly line 48 (in Rails 8.0.2)
# Adjust binfiles to be executable on Linux
RUN chmod +x bin/* && \
sed -i "s/\r$//g" bin/* && \
sed -i 's/ruby\.exe$/ruby/' bin/*
# EXISTING:
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
-- db/production_setup.sql
CREATE DATABASE <your-service-name>_production;
CREATE DATABASE <your-service-name>_production_cache;
CREATE DATABASE <your-service-name>_production_queue;
CREATE DATABASE <your-service-name>_production_cable;
# .kamal/secrets
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
# Example of extracting secrets from 1password (or another compatible pw manager)
# SECRETS=$(kamal secrets fetch --adapter 1password --account your-account --from Vault/Item KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY)
# KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD ${SECRETS})
# RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY ${SECRETS})
# Use a GITHUB_TOKEN if private repositories are needed for the image
# GITHUB_TOKEN=$(gh config get -h github.com oauth_token)
# Grab the registry password from ENV
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
# or if you followed my file-based setup:
# KAMAL_REGISTRY_PASSWORD=$(cat config/credentials/kamal_registry_password.key)
# Improve security by using a password manager. Never check config/master.key into git!
RAILS_MASTER_KEY=$(cat config/master.key)
POSTGRES_PASSWORD=$(cat config/credentials/postgres.key)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment