Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nplusp/301bf8f202cb43a460aed2b83c54de98 to your computer and use it in GitHub Desktop.
Save nplusp/301bf8f202cb43a460aed2b83c54de98 to your computer and use it in GitHub Desktop.

How to deploy a Rails 7.1 app with Postgres and Kamal on a single server

I think you have looked at the tutorial from Mr. Heinemeier Hansson at least once or twice and have a similar setup.

rails new kamal_pg --css tailwind --skip-test --database=postgresql

cd kamal_pg

git add .

git commit -m 'initial commit'

rails g scaffold Post title content:text

rails db:create

rails db:migrate

You have edited routes.rb

# Defines the root path route ("/")
root "posts#index"

# Start Rails
bin/dev

Created your first post - added and commited the changes

git add .
git commit -m 'Post scaffold with edited routes'

Initialized Kamal

kamal init
git add .; git commit -m 'kamal init'
# .env
KAMAL_REGISTRY_PASSWORD=change-this
RAILS_MASTER_KEY=use-your-master-key
POSTGRES_PASSWORD=012345678912345678

Next steps

  • Get your IP address
  • Create a production.sql (in folder db - like in the dhh video)

In your database.yml use the ENVs

production:
  <<: *default
  database: kamal_pg_production
  username: kamal_pg
  password: <%= ENV["POSTGRES_PASSWORD"] %>
  host: <%= ENV["DB_HOST"] %>

In your config/environments/production.rb

config.force_ssl = false

In your deploy.yml you enable the env section, add POSTGRES_PASSWORD, change the service from my-app to your-app, as well as the name for the container image and your registry username

You add your postgres accessory. And for me 2 builder 'settings' work.

And since is a test - 1 IP address for all ;)

# Name of your application. Used to uniquely configure containers.
service: kamal-pg

# Name of the container image.
image: your-name/kamal-pg

# Deploy to these servers.
servers:
  web:
    hosts:
      - 192.168.0.1

# 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-name

  # Always use an access token rather than real password when possible.
  password:
    - KAMAL_REGISTRY_PASSWORD

# Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes!
env:
  clear:
    DB_HOST: 192.168.0.1
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD

# Use a different ssh user than root
# ssh:
#   user: app

# Configure builder setup.
builder:
  args:
    RUBY_VERSION: 3.2.2
#   secrets:
#     - GITHUB_TOKEN
  remote:
    arch: amd64
#     host: ssh://app@192.168.0.1

# Use accessory services (secrets come from .env).
accessories:
  db:
    image: postgres:15
    host: 192.168.0.1
    port: 5432
    env:
      clear:
        POSTGRES_USER: "kamal_pg"
        POSTGRES_DB: "kamal_pg_production"
      secret:
        - POSTGRES_PASSWORD
    files:
      - db/production.sql:/docker-entrypoint-initdb.d/setup.sql
    directories:
      - data:/var/lib/postgresql/data

#   redis:
#     image: redis:7.0
#     host: 192.168.0.1
#     port: 6379
#     directories:
#       - data:/data

# Configure custom arguments for Traefik
# traefik:
#   args:
#     accesslog: true
#     accesslog.format: json

# Configure a custom healthcheck (default is /up on port 3000)
# healthcheck:
#   path: /healthz
#   port: 4000

# 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 rolling deploys by setting a wait time between batches of restarts.
# boot:
#   limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
#   wait: 2

That's it.

kamal setup
...
...
Finished all in 415.6 seconds
Releasing the deploy lock...
Finished all in 475.5 seconds

You're done :)

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