diff --git a/.env.example b/.env.example index 63cb25f3..36b277fc 100644 --- a/.env.example +++ b/.env.example @@ -39,6 +39,13 @@ SELF_HOSTING_ENABLED=false # `localhost` (or unset) is used for local development and testing HOSTING_PLATFORM=localhost +# Secret key used to encrypt credentials (https://api.rubyonrails.org/v7.1.3.2/classes/Rails/Application.html#method-i-secret_key_base) +# Has to be a random string, generated eg. by running `openssl rand -hex 64` +SECRET_KEY_BASE=secret-value + +# Disable enforcing SSL connections +# DISABLE_SSL=true + # ====================================================================================================== # Upgrades Module - responsible for triggering upgrade alerts, prompts, and auto-upgrade functionality # ====================================================================================================== diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..c9c2d5a6 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,107 @@ +name: Publish Docker image + +on: + push: + tags: + - 'v*' + branches: + - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +permissions: + contents: read + +jobs: + + test: + name: Test + runs-on: ubuntu-latest + timeout-minutes: 10 + + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - name: Install packages + run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable curl libvips postgresql-client libpq-dev + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Run tests and smoke test seed + env: + RAILS_ENV: test + DATABASE_URL: postgres://postgres:postgres@localhost:5432 + run: | + bin/rails db:create + bin/rails db:schema:load + bin/rails test:all + bin/rails db:seed + + - name: Keep screenshots from failed system tests + uses: actions/upload-artifact@v4 + if: failure() + with: + name: screenshots + path: ${{ github.workspace }}/tmp/screenshots + if-no-files-found: ignore + + build: + name: Build docker image + runs-on: ubuntu-latest + needs: [test] + permissions: + packages: write + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Set up Docker Context for Buildx + run: docker context create builders + shell: bash + + - name: Log in to the container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + flavor: latest=auto + tags: | + # Explicit commit sha and version tags + type=sha + type=semver,pattern={{version}} + # Aliases + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=stable,enable=${{ startsWith(github.ref, 'refs/tags/v') }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + id: build + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/README.md b/README.md index 2d782ff9..06a8a994 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ You can find [detailed setup guides for self hosting here](docs/self-hosting.md) 1. Click the button above 2. Follow the instructions in the [Render self-hosting guide](docs/self-hosting/render.md) +### Docker + +To host Maybe with Docker Compose, please follow our [Docker self-hosting guide](docs/self-hosting/docker.md). + ## Local Development Setup ### Requirements diff --git a/config/environments/production.rb b/config/environments/production.rb index 221263dd..ea7cd99d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -38,12 +38,12 @@ Rails.application.configure do # config.action_cable.url = "wss://example.com/cable" # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = ActiveModel::Type::Boolean.new.cast(ENV.fetch("RAILS_FORCE_SSL", true)) + # Assume all access to the app is happening through a SSL-terminating reverse proxy. # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. - # config.assume_ssl = true - - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = true + config.assume_ssl = ActiveModel::Type::Boolean.new.cast(ENV.fetch("RAILS_ASSUME_SSL", true)) # Log to STDOUT by default config.logger = ActiveSupport::Logger.new(STDOUT) diff --git a/docker-compose.example.yml b/docker-compose.example.yml new file mode 100644 index 00000000..dc9940aa --- /dev/null +++ b/docker-compose.example.yml @@ -0,0 +1,35 @@ +services: + + app: + image: ghcr.io/maybe-finance/maybe:latest + ports: + - 127.0.0.1:3000:3000 + restart: unless-stopped + env_file: + - .env + environment: + DB_HOST: "postgres" + RAILS_ENV: "production" + RAILS_FORCE_SSL: false + RAILS_ASSUME_SSL: false + depends_on: + postgres: + condition: service_healthy + + postgres: + image: postgres:16 + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_USER: ${POSTGRES_USER:?} + POSTGRES_DB: ${POSTGRES_DB:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?} + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U $$POSTGRES_USER" ] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + postgres-data: diff --git a/docs/self-hosting.md b/docs/self-hosting.md index d3943205..1527faeb 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -15,8 +15,11 @@ The fastest way to get your own version of Maybe running is a "one-click deploy" **Estimated cost:** $5-15 per month -_Docker is not yet supported, but will be soon._ +Please see the [Docker self-hosting guide](self-hosting/docker.md) for detailed setup instructions. ## Self hosting disclaimer -While we attempt to provide cost-effective deployment options, please remember, **self-hosting _may_ incur monthly charges on your hosting platform of choice**. While we provide cost estimates for each deployment option, it is your responsibility to manage these costs. +While we attempt to provide cost-effective deployment options, please remember, +**self-hosting _may_ incur monthly charges on your hosting platform of +choice**. While we provide cost estimates for each deployment option, it is +your responsibility to manage these costs. diff --git a/docs/self-hosting/docker.md b/docs/self-hosting/docker.md new file mode 100644 index 00000000..68d2bd8b --- /dev/null +++ b/docs/self-hosting/docker.md @@ -0,0 +1,75 @@ +# Self Hosting Maybe with Docker + +## Quick Start + +To quickly get the Maybe app up and running, follow these steps: + +* clone the maybe repository to your local machine. +* navigate to the repository's root directory. +* copy the `.env.example` file to `.env` and configure the necessary +environment variables. Edit the `SELF_HOSTING_ENABLED` and `SECRET_KEY_BASE` +variables. You might want to edit the `DB_HOST`, `DB_PORT`, +`POSTGRES_PASSWORD`, `POSTGRES_USER` variables as well. +* run `docker-compose up -d` to start the maybe app in detached mode. +* access the maybe app by navigating to http://localhost:3000 in your web browser. + +## Prerequisites and Setup + +Install Docker on your machine by following the appropriate guide for your +operating system. If you need a GUI, install [Docker +Desktop](https://docs.docker.com/desktop/), otherwise innstall [Docker +Engine](https://docs.docker.com/engine/install/) (recommended for production). + +Next, follow these steps (shared between docker-compose and standalone): + +* clone the maybe repository to your local machine. +* navigate to the repository's root directory. +* copy the `.env.example` file to `.env` and configure the necessary +environment variables. Edit the `SELF_HOSTING_ENABLED` and `SECRET_KEY_BASE` +variables. You might want to edit the `DB_HOST`, `DB_PORT`, +`POSTGRES_PASSWORD`, `POSTGRES_USER` variables as well. + +### Running the app with docker compose + +* run `docker-compose up -d` to start the maybe app in detached mode. +* access the maybe app by navigating to http://localhost:3000 in your web browser. + +### Running the standalone container + +* run the `maybe` docker container + +```bash +docker run -d \ + --name app \ + -p 3000:3000 \ + --restart unless-stopped \ + --env-file .env \ + -e RAILS_ENV=production \ + -e RAILS_FORCE_SSL=false \ + -e RAILS_ASSUME_SSL=false \ + ghcr.io/maybe-finance/maybe:latest +``` + +## Updating the App + +To update the Maybe app to the latest version, follow these steps: + +* Pull the latest changes from the Maybe repository if running the container in +standalone mode. +* If using Docker Compose, update the image field in the docker-compose.yml +file to point to the new Docker image version (not needed if running on the +`latest` tag, docker will automatically pull the latest image). +* Run `docker-compose pull` to pull the latest Docker image. +* Restart the Maybe app container using `docker-compose up -d`. + +## Where should I host? + +### Commercial VPS +### One-Click VPS +### Standalone Image + +## Troubleshooting + +This section will provide troubleshooting tips and solutions for common issues +encountered during deployment. Check back later for updates! +