diff --git a/README.md b/README.md index 959135b7..eeda3254 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ There are 3 primary ways to use the Maybe app: ## Local Development Setup +**If you are trying to _self-host_ the Maybe app, stop here. You +should [read this guide to get started](docs/hosting/docker.md).** + +The instructions below are for developers to get started with contributing to the app. + ### Requirements - Ruby 3.3.1 diff --git a/app/controllers/settings/hostings_controller.rb b/app/controllers/settings/hostings_controller.rb index 36b9a0ee..89a42946 100644 --- a/app/controllers/settings/hostings_controller.rb +++ b/app/controllers/settings/hostings_controller.rb @@ -47,7 +47,7 @@ class Settings::HostingsController < SettingsController end end - if hosting_params[:upgrades_mode] != "manual" && hosting_params[:render_deploy_hook].blank? + if hosting_params[:upgrades_mode] == "auto" && hosting_params[:render_deploy_hook].blank? @errors.add(:render_deploy_hook, t("settings.hostings.update.render_deploy_hook_error")) end diff --git a/app/views/settings/hostings/show.html.erb b/app/views/settings/hostings/show.html.erb index 2e8dd0ae..37c1f3f6 100644 --- a/app/views/settings/hostings/show.html.erb +++ b/app/views/settings/hostings/show.html.erb @@ -5,47 +5,52 @@

<%= t(".page_title") %>

<%= settings_section title: t(".general_settings_title") do %> <%= form_with model: Setting.new, url: settings_hosting_path, method: :patch, local: true, html: { class: "space-y-6", data: { controller: "auto-submit-form", "auto-submit-form-trigger-event-value" => "blur" } } do |form| %> -
-

<%= t(".upgrades.title") %>

-

<%= t(".upgrades.description") %>

-
-
- <%= form.radio_button :upgrades_mode, "manual", checked: Setting.upgrades_mode == "manual", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> - <%= form.label :upgrades_mode_manual, t(".upgrades.manual.title"), class: "text-gray-900 text-sm" do %> - <%= t(".upgrades.manual.title") %> -
- + + <% if ENV["HOSTING_PLATFORM"] == "render" %> +
+

<%= t(".upgrades.title") %>

+

<%= t(".upgrades.description") %>

+
+
+ <%= form.radio_button :upgrades_mode, "manual", checked: Setting.upgrades_mode == "manual", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> + <%= form.label :upgrades_mode_manual, t(".upgrades.manual.title"), class: "text-gray-900 text-sm" do %> + <%= t(".upgrades.manual.title") %> +
+ <%= t(".upgrades.manual.description") %> - <% end %> -
-
- <%= form.radio_button :upgrades_mode, "release", checked: Setting.upgrades_mode == "auto" && Setting.upgrades_target == "release", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> - <%= form.label :upgrades_mode_release, t(".upgrades.latest_release.title"), class: "text-gray-900 text-sm" do %> - <%= t(".upgrades.latest_release.title") %> -
- + <% end %> +
+
+ <%= form.radio_button :upgrades_mode, "release", checked: Setting.upgrades_mode == "auto" && Setting.upgrades_target == "release", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> + <%= form.label :upgrades_mode_release, t(".upgrades.latest_release.title"), class: "text-gray-900 text-sm" do %> + <%= t(".upgrades.latest_release.title") %> +
+ <%= t(".upgrades.latest_release.description") %> - <% end %> -
-
- <%= form.radio_button :upgrades_mode, "commit", checked: Setting.upgrades_mode == "auto" && Setting.upgrades_target == "commit", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> - <%= form.label :upgrades_mode_commit, t(".upgrades.latest_commit.title"), class: "text-gray-900 text-sm" do %> - <%= t(".upgrades.latest_commit.title") %> -
- + <% end %> +
+
+ <%= form.radio_button :upgrades_mode, "commit", checked: Setting.upgrades_mode == "auto" && Setting.upgrades_target == "commit", data: { "auto-submit-form-target" => "auto", "autosubmit-trigger-event": "input" } %> + <%= form.label :upgrades_mode_commit, t(".upgrades.latest_commit.title"), class: "text-gray-900 text-sm" do %> + <%= t(".upgrades.latest_commit.title") %> +
+ <%= t(".upgrades.latest_commit.description") %> - <% end %> + <% end %> +
-
-
-

<%= t(".provider_settings.title") %>

-

<%= t(".render_deploy_hook_description") %>

- <%= form.url_field :render_deploy_hook, label: t(".render_deploy_hook_label"), placeholder: t(".render_deploy_hook_placeholder"), value: Setting.render_deploy_hook, data: { "auto-submit-form-target" => "auto" } %> -
+ +
+

<%= t(".provider_settings.title") %>

+

<%= t(".render_deploy_hook_description") %>

+ <%= form.url_field :render_deploy_hook, label: t(".render_deploy_hook_label"), placeholder: t(".render_deploy_hook_placeholder"), value: Setting.render_deploy_hook, data: { "auto-submit-form-target" => "auto" } %> +
+ <% end %> +

<%= t(".smtp_settings.title") %>

<%= t(".smtp_settings.description") %>

@@ -69,13 +74,14 @@
- <%= link_to t(".smtp_settings.send_test_email_button"), send_test_email_settings_hosting_path, data: { turbo_method: :post }, class:"bg-gray-50 text-gray-900 text-sm font-medium rounded-lg px-3 py-2" %> + <%= link_to t(".smtp_settings.send_test_email_button"), send_test_email_settings_hosting_path, data: { turbo_method: :post }, class: "bg-gray-50 text-gray-900 text-sm font-medium rounded-lg px-3 py-2" %>
<% end %> <% end %> +
<%= previous_setting("Billing", settings_billing_path) %> <%= next_setting("Accounts", accounts_path) %> diff --git a/docker-compose.example.yml b/docker-compose.example.yml index f7f1a3c1..cbd5232a 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -1,21 +1,55 @@ +# =========================================================================== +# Example Docker Compose file +# =========================================================================== +# +# Purpose: +# -------- +# +# This file is an example Docker Compose configuration for self hosting +# Maybe on your local machine or on a cloud VPS. +# +# The configuration below is a "standard" setup, but may require modification +# for your specific environment. +# +# Setup: +# ------ +# +# To run this, you should read the setup guide: +# +# https://github.com/maybe-finance/maybe/blob/main/docs/hosting/docker.md +# +# Troubleshooting: +# ---------------- +# +# If you run into problems, you should open a Discussion here: +# +# https://github.com/maybe-finance/maybe/discussions/categories/general +# + services: app: image: ghcr.io/maybe-finance/maybe:latest + volumes: - ./storage:/rails/storage + ports: - - 127.0.0.1:3000:3000 + - 3000:3000 + restart: unless-stopped - env_file: - - .env + environment: - SELF_HOSTING_ENABLED: true - DB_HOST: postgres - RAILS_FORCE_SSL: false - RAILS_ASSUME_SSL: false - POSTGRES_USER: postgres + SELF_HOSTING_ENABLED: "true" + RAILS_FORCE_SSL: "false" + RAILS_ASSUME_SSL: "false" GOOD_JOB_EXECUTION_MODE: async + SECRET_KEY_BASE: ${SECRET_KEY_BASE:?} + DB_HOST: postgres + POSTGRES_DB: ${POSTGRES_DB:-maybe_production} + POSTGRES_USER: ${POSTGRES_USER:-maybe_user} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?} + depends_on: postgres: condition: service_healthy @@ -26,11 +60,11 @@ services: volumes: - postgres-data:/var/lib/postgresql/data environment: - POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_USER: ${POSTGRES_USER:-maybe_user} POSTGRES_DB: ${POSTGRES_DB:-maybe_production} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?} healthcheck: - test: [ "CMD-SHELL", "pg_isready -U $$POSTGRES_USER" ] + test: [ "CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB" ] interval: 5s timeout: 5s retries: 5 diff --git a/docs/hosting/docker.md b/docs/hosting/docker.md index b16b4ffa..425a4c75 100644 --- a/docs/hosting/docker.md +++ b/docs/hosting/docker.md @@ -1,102 +1,177 @@ # Self Hosting Maybe with Docker -## Quick Start +This guide will help you setup, update, and maintain your self-hosted Maybe application with Docker Compose. Docker Compose is the most popular and recommended way to self-host the Maybe app. -_The below quickstart assumes you're running on Mac or Linux. Windows will -be different._ +If you want a _less +technical_ way to host the Maybe app, you can [host on Render](/docs/hosting/one-click-deploy.md) as an +_**alternative** to Docker Compose_. -Make sure [Docker is installed](https://docs.docker.com/engine/install/) and -setup your local environment: +## Setup Guide + +Follow the guide below to get your app running. + +### Step 1: Install Docker + +Complete the following steps: + +1. Install Docker Engine by following [the official guide](https://docs.docker.com/engine/install/) +2. Start the Docker service on your machine +3. Verify that Docker is installed correctly and is running by opening up a terminal and running the following command: + +```bash +# If Docker is setup correctly, this command will succeed +docker run hello-world +``` + +### Step 2: Configure your Docker Compose file and environnment + +#### Create a directory for your app to run + +Open your terminal and create a directory where your app will run. Below is an example command with a recommended directory: ```bash # Create a directory on your computer for Docker files mkdir -p ~/docker-apps/maybe + +# Once created, navigate your current working directory to the new folder cd ~/docker-apps/maybe - -# Download the sample docker-compose.yml file from the Maybe Github repository -curl -o docker-compose.yml https://raw.githubusercontent.com/maybe-finance/maybe/main/docker-compose.example.yml - -# Create an .env file (make sure to fill in empty variables manually) -cat << EOF > .env -# Use "openssl rand -hex 64" to generate this -SECRET_KEY_BASE= - -# Can be any value, set to what you'd like -POSTGRES_PASSWORD= -EOF ``` -Make sure to generate your `SECRET_KEY_BASE` value and save the `.env` file. -Then you're ready to run the app, which will be available at -`http://localhost:3000` in your browser: +#### Copy our sample Docker Compose file + +Make sure you are in the directory you just created and run the following command: ```bash -docker-compose up -d +# Download the sample docker-compose.yml file from the Maybe Github repository +curl -o compose.yml https://raw.githubusercontent.com/maybe-finance/maybe/main/docker-compose.example.yml ``` -Lastly, go to `http://localhost:3000` in your browser, **create a new -account**, and you're ready to start tracking your finances! +This command will do the following: -## Detailed Setup Guide +1. Fetch the sample docker compose file from our public Github repository +2. Creates a file in your current directory called `compose.yml` with the contents of the example file -### Prerequisites +At this point, the only file in your current working directory should be `compose.yml`. -- Install Docker Engine by - following [the official guide](https://docs.docker.com/engine/install/) -- Start the Docker service on your machine +#### Create your environment file -### App Setup +In order to configure the app, you will need to create a file called `.env`, which is where Docker will read environment variables from. -1. Create a new directory on your machine (we suggest something like - `$HOME/docker-apps/maybe`) -2. Create a `docker-compose.yml` file (we suggest - using [our example](/docker-compose.example.yml) - if - you're new to self-hosting and Docker) -3. Create a `.env` file and add the required variables. Currently, - `SECRET_KEY_BASE` is the only required variable, but you can take a look - at our [.env.example](/.env.example) file to see all available options. +To do this, run the following command: -### Run app with Docker Compose +```bash +touch .env +``` -1. Run `docker-compose up -d` to start the maybe app in detached mode. -2. Access the Maybe app by navigating to http://localhost:3000 in your web - browser. +#### Generate the app secret key -### Updating the App +The app requires an environment variable called `SECRET_KEY_BASE` to run. -The mechanism that updates your self-hosted Maybe app is the GHCR (Github -Container Registry) Docker image that you see in the `docker-compose.yml` file: +We will first need to generate this in the terminal. If you have `openssl` installed on your computer, you can generate it with the following command: + +```bash +openssl rand -hex 64 +``` + +_Alternatively_, you can generate a key without openssl or any external dependencies by pasting the following bash command in your terminal and running it: + +```bash +head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' && echo +``` + +Once you have generated a key, save it and move on to the next step. + +#### Fill in your environment file + +Open the file named `.env` that we created in a prior step using your favorite text editor. + +Fill in this file with the following variables: + +```txt +SECRET_KEY_BASE="replacemewiththegeneratedstringfromthepriorstep" +POSTGRES_PASSWORD="replacemewithyourdesireddatabasepassword" +``` + +### Step 3: Test your app + +You are now ready to run the app. Start with the following command to make sure everything is working: + +```bash +docker compose up +``` + +This will pull our official Docker image and start the app. You will see logs in your terminal. + +Open your browser, and navigate to `http://localhost:3000`. + +If everything is working, you will see the Maybe login screen. + +### Step 4: Create your account + +The first time you run the app, you will need to register a new account by hitting "register" on the login page. + +1. Enter your email +2. Enter a password + +### Step 5: Run the app in the background + +Most self-hosting users will want the Maybe app to run in the background on their computer so they can access it at all times. To do this, hit `Ctrl+C` to stop the running process, and then run the following command: + +```bash +docker compose up -d +``` + +The `-d` flag will run Docker Compose in "detached" mode. To verify it is running, you can run the following command: + +``` +docker compose ls +``` + +### Step 6: Enjoy! + +Your app is now set up. You can visit it at `http://localhost:3000` in your browser. + +If you find bugs or have a feature request, be sure to read through our [contributing guide here](https://github.com/maybe-finance/maybe/wiki/How-to-Contribute-Effectively-to-this-Project). + +## How to update your app + +The mechanism that updates your self-hosted Maybe app is the GHCR (Github Container Registry) Docker image that you see in the `docker-compose.yml` file: ```yml image: ghcr.io/maybe-finance/maybe:latest ``` -We recommend using one of the following images, but you can pin your app to -whatever version you'd like ( -see [packages](https://github.com/maybe-finance/maybe/pkgs/container/maybe)): +We recommend using one of the following images, but you can pin your app to whatever version you'd like (see [packages](https://github.com/maybe-finance/maybe/pkgs/container/maybe)): - `ghcr.io/maybe-finance/maybe:latest` (latest commit) - `ghcr.io/maybe-finance/maybe:stable` (latest release) -By default, your app _will NOT_ automatically update. To update your -self-hosted app, you must run the following commands: +By default, your app _will +NOT_ automatically update. To update your self-hosted app, run the following commands in your terminal: ```bash -docker-compose pull # This pulls the "latest" published image from GHCR - -docker-compose up -d # Restarts the app +cd ~/docker-apps/maybe # Navigate to whatever directory you configured the app in +docker compose pull # This pulls the "latest" published image from GHCR +docker compose build app # This rebuilds the app with updates +docker compose up --no-deps -d app # This restarts the app using the newest version ``` -#### Changing the image +## How to change which updates your app receives -If you'd like to pin the app to a specific version or tag, all you need to do is -edit the `docker-compose.yml` file: +If you'd like to pin the app to a specific version or tag, all you need to do is edit the `docker-compose.yml` file: ```yml image: ghcr.io/maybe-finance/maybe:stable ``` +After doing this, make sure and restart the app: + +```bash +docker compose pull # This pulls the "latest" published image from GHCR +docker compose build app # This rebuilds the app with updates +docker compose up --no-deps -d app # This restarts the app using the newest version +``` + ## Troubleshooting This section will provide troubleshooting tips and solutions for common issues