diff --git a/README.md b/README.md index 8a7877326..613e17ecc 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,95 @@ This is the source code of [Fizzy](https://fizzy.do/), the Kanban tracking tool for issues and ideas by [37signals](https://37signals.com). + +## Deploying Fizzy + +If you'd like to run Fizzy on your own server, we recommend deploying it with [Kamal](https://kamal-deploy.org/). +Kamal makes it easier to set up a bare server, copy the application to it, and manage the configuration settings that it uses. + +(Kamal is also what we use to deploy Fizzy at 37signals. If you're curious about what our deployment configuration looks like, you can find it inside [`fizzy-saas`](https://github.com/basecamp/fizzy-saas).) + +This repo contains a starter deployment file that you can modify for your own specific use. That file lives at [config/deploy.yml](config/deploy.yml), which is the default place where Kamal will look for it. + +The steps to configure your very own Fizzy are: + +1. Fork the repo +2. Edit few things in config/deploy.yml, .kamal/secrets, and config/environments/production.rb +3. Run `kamal setup` to do your first deploy. + +We'll go through each of these in turn. + +### Fork the repo + +To make it easy to customise Fizzy's settings for your own instance, you should start by creating your own GitHub fork of the repo. +That allows you to commit your changes, and track them over time. +You can always re-sync your fork to pick up new changes from the main repo over time. + +Once you've got your fork ready, run `bin/setup` from within it, to make sure everything is installed. + +### Editing the configuration + +The config/deploy.yml has been mostly set up for you, but you'll need to fill out some sections that are specific to your instance. +To get started, the parts you need to change are all in the "About your deployment" section. +We've added comments to that file to highlight what each setting needs to be, but the main ones are: + +- `servers/web`: Enter the hostname of the server you're deploying to here. This should be an address that you can access via `ssh`. +- `ssh/user`: If you access your server a `root` you can leave this alone; if you use a different user, set it here. +- `proxy/ssl` and `proxy/host`: Kamal can set up SSL certificates for you automatically. To enable that, set the hostname again as `host`. If you don't want SSL for some reason, you can set `ssl: false` to turn it off. +- `env/clear/MAILER_FROM_ADDRESS`: This is the email address that Fizzy will send emails from. It should usually be an address from the same domain where you're running Fizzy. + +Fizzy also requires a few environment variables to be set up, some of which contain secrets. +The simplest way to do this is to put them in a file called `.kamal/secrets`. +Because this file will contain secret credentials, it's important that you DON'T CHECK THIS FILE INTO YOUR REPO! You can add the filename to `.gitignore` to ensure you don't commit this file accidentally. + +If you use a password manager like 1Password, you can also opt to keep your secrets there instead. +Refer to the [Kamal documentation](https://kamal-deploy.org/docs/configuration/environment-variables/#secrets) for more information about how to do that. + +To store your secrets, create the file `.kamal/secrets` and enter something like the following: + +``` +SECRET_KEY_BASE=12345 +VAPID_PUBLIC_KEY=something +VAPID_PRIVATE_KEY=somethingelse +SMTP_USERNAME=email-provider-username +SMTP_PASSWORD=email-provider-password +``` + +The values you enter here will be specific to you, and you can get or create them as follows: + +- `SECRET_KEY_BASE` should be a long, random secret. You can run `bin/rails secret` to create a suitable value for this. +- `VAPID_PUBLIC_KEY` & `VAPID_PRIVATE_KEY` are a pair of credentials that are used for sending notifications. You can create your own keys by starting a development console with: + + bin/rails c + + And then run the following to create a new pair of keys: + + ```ruby + vapid_key = WebPush.generate_key + + puts "VAPID_PRIVATE_KEY=#{vapid_key.private_key}" + puts "VAPID_PUBLIC_KEY=#{vapid_key.public_key}" + ``` + +- `SMTP_USERNAME`/`SMTP_PASSWORD` are credentials you should get from your email provider. + +Lastly, you'll need to set up the rest of your email configuration in `config/environments/production.rb`. There is an example configuration in comments at the top of that file. The actual settings you use here will depend on your email provider, but in most cases will look similar to that section, so you can uncomment it and edit to suit. Note that it will use the `SMTP_USERNAME` and `SMTP_PASSWORD` values you entered in your secrets. + +Once you've made all those changes, commit them to your fork so they're saved. + +### Deploy Fizzy! + +You can now do your first deploy by running: + + bin/kamal setup + +This will set up Docker (if needed), build your Fizzy app container, configure it, and start it running. + +After the first deploy is done, any subsequent steps won't need to do that initial setup. So for future deploys you can just run: + + bin/kamal deploy + + ## Development ### Setting up @@ -23,6 +112,22 @@ You'll be able to access the app in development at http://fizzy.localhost:3006. To login, enter `david@example.com` and grab the verification code from the browser console to sign in. +### Web Push Notifications + +Fizzy uses VAPID (Voluntary Application Server Identification) keys to send browser push notifications. For notifications to work in development you'll need to generate a key pair and set these environment variables: + +- `VAPID_PRIVATE_KEY` +- `VAPID_PUBLIC_KEY` + +Generate them with the `web-push` gem: + +```ruby +vapid_key = WebPush.generate_key + +puts "VAPID_PRIVATE_KEY=#{vapid_key.private_key}" +puts "VAPID_PUBLIC_KEY=#{vapid_key.public_key}" +``` + ### Running tests For fast feedback loops, unit tests can be run with: @@ -54,25 +159,6 @@ You can enable or disable [`letter_opener`](https://github.com/ryanb/letter_open Under the hood, this will create or remove `tmp/email-dev.txt`. -## Deployment - -We recommend [Kamal](https://kamal-deploy.org/) for deploying Fizzy. This project comes with a vanilla Rails template. You can find our production setup in [`fizzy-saas`](https://github.com/basecamp/fizzy-saas). - -### Web Push Notifications - -Fizzy uses VAPID (Voluntary Application Server Identification) keys to send browser push notifications. You'll need to generate a key pair and set these environment variables: - -- `VAPID_PRIVATE_KEY` -- `VAPID_PUBLIC_KEY` - -Generate them with the `web-push` gem: - -```ruby -vapid_key = WebPush.generate_key - -puts "VAPID_PRIVATE_KEY=#{vapid_key.private_key}" -puts "VAPID_PUBLIC_KEY=#{vapid_key.public_key}" -``` ## SaaS gem @@ -85,6 +171,7 @@ This gem depends on some private git repositories and it is not meant to be used We welcome contributions! Please read our [style guide](STYLE.md) before submitting code. + ## License Fizzy is released under the [O'Saasy License](LICENSE.md). diff --git a/config/deploy.yml b/config/deploy.yml index be1e3c21e..0e855727d 100644 --- a/config/deploy.yml +++ b/config/deploy.yml @@ -1,65 +1,45 @@ -# Name of your application. Used to uniquely configure containers. +# Name of this app service: fizzy - -# Name of the container image (use your-user/app-name on external registries). image: fizzy -# Deploy to these servers. + +#-- About your deployment --# + +# Where to deploy fizzy servers: web: - - 192.168.0.1 - # job: - # hosts: - # - 192.168.0.1 - # cmd: bin/jobs + - fizzy.example.com # Set your server name here -# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server. -# If used with Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption. -# -# Using an SSL proxy like this requires turning on config.assume_ssl and config.force_ssl in production.rb! -# -# Don't use this when deploying to multiple web servers (then you have to terminate SSL at your load balancer). -# -# proxy: -# ssl: true -# host: app.example.com +# How you connect to your server +ssh: + user: root # If you use a different username to SSH to your server, specify it here -# Where you keep your container images. -registry: - # Alternatives: hub.docker.com / registry.digitalocean.com / ghcr.io / ... - server: localhost:5555 +# Automatic SSL +proxy: + ssl: true # Set this to false if you *don't* want SSL + host: fizzy.example.com # Set your server name here to use automatic SSL - # Needed for authenticated registries. - # 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). +# Your application configuration (secrets come from .kamal/secrets). env: secret: - - RAILS_MASTER_KEY + - SECRET_KEY_BASE + - VAPID_PUBLIC_KEY + - VAPID_PRIVATE_KEY + - SMTP_USERNAME + - SMTP_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 + MAILER_FROM_ADDRESS: support@example.com # The email address that Fizzy sends email from + SOLID_QUEUE_IN_PUMA: true # Run background jobs in the app container - # 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 +#-- General configuration --# - # Match this to any external database server to configure Active Record correctly - # Use fizzy-db for a db accessory server on same machine via local kamal docker network. - # DB_HOST: 192.168.0.2 +# Use a local registry to deploy +registry: + server: localhost:5555 - # Log everything from Rails - # RAILS_LOG_LEVEL: debug - -# Aliases are triggered with "bin/kamal ". You can overwrite arguments on invocation: -# "bin/kamal logs -r job" will tail logs from the first server in the job section. +# Handy aliases for interacting with your deployment. For eaxmple: `bin/kamal console` will connect to a +# Rails console in production. aliases: console: app exec --interactive --reuse "bin/rails console" shell: app exec --interactive --reuse "bash" @@ -76,45 +56,6 @@ volumes: # 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.7 - # secrets: - # - GITHUB_TOKEN - # - RAILS_MASTER_KEY - -# Use a different ssh user than root -# ssh: -# user: app - -# Use accessory services (secrets come from .kamal/secrets). -# accessories: -# db: -# image: mysql:8.0 -# host: 192.168.0.2 -# # Change to 3306 to expose port to the world instead of just local network. -# port: "127.0.0.1:3306:3306" -# env: -# clear: -# MYSQL_ROOT_HOST: '%' -# secret: -# - MYSQL_ROOT_PASSWORD -# files: -# - config/mysql/production.cnf:/etc/mysql/my.cnf -# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql -# directories: -# - data:/var/lib/mysql -# redis: -# image: valkey/valkey:8 -# host: 192.168.0.2 -# port: 6379 -# directories: -# - data:/data diff --git a/config/environments/production.rb b/config/environments/production.rb index bdb274efb..7b29a00d1 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -3,6 +3,21 @@ require "active_support/core_ext/integer/time" Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. + # Email provider Settings + # + # Configure these according to whichever email provider you use. An example setup + # using SMTP looks like the following: + # + # config.action_mailer.smtp_settings = { + # address: 'smtp.example.com', # The address of your email provider's SMTP server + # port: 2525, + # domain: 'example.com', # Your domain, which Fizzy will send email from + # user_name: ENV["SMTP_USERNAME"], + # password: ENV["SMTP_PASSWORD"], + # authentication: :plain, + # enable_starttls_auto: true + # } + # Code is not reloaded between requests. config.enable_reloading = false