From 82c74cb2fc7c0b17d54b599072090375cfbe3923 Mon Sep 17 00:00:00 2001 From: itsablabla Date: Wed, 27 May 2026 15:53:11 +0000 Subject: [PATCH 1/2] deploy: replace stub docker-compose with working VPS stack The previous deploy/docker-compose.yml was a one-line stub pointing at file:///tmp/b2_freescout_compose.txt and could not be used to deploy anything. Replace it with a real production-shaped compose file plus an env template and a short README so Nomad can stand up FreeScout on a fresh VPS. - App container uses tiredofit/freescout (the widely used community image) - MariaDB 10.11 sidecar with healthcheck, named volumes for persistence - All secrets/URLs sourced from deploy/.env (template provided) - Bound to APP_PORT for an external reverse proxy to terminate TLS Co-Authored-By: Claude Opus 4.7 (1M context) Co-Authored-By: itsablabla --- deploy/.env.example | 35 +++++++++++++++++ deploy/README.md | 30 +++++++++++++++ deploy/docker-compose.yml | 79 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 deploy/.env.example create mode 100644 deploy/README.md diff --git a/deploy/.env.example b/deploy/.env.example new file mode 100644 index 000000000..82586dcfb --- /dev/null +++ b/deploy/.env.example @@ -0,0 +1,35 @@ +# --- FreeScout VPS deployment --- +# Copy this file to deploy/.env and fill in values before running +# `docker compose --env-file deploy/.env up -d`. + +# Public URL FreeScout will be served from (no trailing slash). +APP_URL=https://help.example.com +# Hostname only (matches APP_URL host) — used by reverse proxies. +APP_HOST=help.example.com +# Host port the app container binds to. Point your reverse proxy here. +APP_PORT=8080 + +# FreeScout Docker image tag. Pin to a release in production. +FREESCOUT_IMAGE_TAG=latest + +# --- Database (MariaDB) --- +DB_NAME=freescout +DB_USER=freescout +DB_PASSWORD=change-me-strong-password +DB_ROOT_PASSWORD=change-me-strong-root-password + +# --- Initial admin user (created on first run) --- +ADMIN_EMAIL=admin@example.com +ADMIN_PASSWORD=change-me-strong-password + +# --- Outbound mail (SMTP) --- +ENABLE_SMTP=TRUE +SMTP_HOST=smtp.example.com +SMTP_PORT=587 +SMTP_USER=postmaster@example.com +SMTP_PASS=change-me +SMTP_FROM_ADDRESS=help@example.com +SMTP_FROM_NAME=Nomad Support + +# IANA timezone, e.g. America/Los_Angeles +TIMEZONE=UTC diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 000000000..6765b7403 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,30 @@ +# FreeScout VPS deployment + +Single-host Docker Compose stack for FreeScout (app + MariaDB). + +## Prerequisites + +- Docker Engine 24+ and the Compose plugin +- A DNS record pointing at the host +- A reverse proxy terminating TLS (Caddy, nginx, Traefik) that forwards to `APP_PORT` + +## Setup + +```bash +cp deploy/.env.example deploy/.env +# Edit deploy/.env — set APP_URL/APP_HOST, DB and admin passwords, SMTP creds. + +docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d +docker compose -f deploy/docker-compose.yml --env-file deploy/.env logs -f app +``` + +Then browse to `APP_URL` and finish the FreeScout web installer (it picks up +the DB credentials and admin user from the container environment). + +## Operations + +- Update the image: bump `FREESCOUT_IMAGE_TAG` in `deploy/.env`, then + `docker compose -f deploy/docker-compose.yml --env-file deploy/.env pull && ... up -d`. +- App data is stored in the `freescout_data`, `freescout_logs`, and + `freescout_db` named volumes. Back these up off-box. +- Container image: [`tiredofit/freescout`](https://github.com/tiredofit/docker-freescout). diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index cccad653b..a8693f4a0 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -1 +1,78 @@ -file:///tmp/b2_freescout_compose.txt \ No newline at end of file +# FreeScout — single-VPS deployment. +# +# Quick start: +# 1. cp deploy/.env.example deploy/.env +# 2. Fill in passwords, APP_URL, mail settings. +# 3. docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d +# 4. Browse to APP_URL and complete the FreeScout web installer. +# +# Reverse proxy (Caddy / nginx / Traefik) is expected to terminate TLS and +# forward to ${APP_PORT:-8080} on the host. + +services: + app: + image: tiredofit/freescout:${FREESCOUT_IMAGE_TAG:-latest} + container_name: freescout-app + restart: unless-stopped + depends_on: + db: + condition: service_healthy + ports: + - "${APP_PORT:-8080}:80" + environment: + VIRTUAL_HOST: ${APP_HOST} + SITE_URL: ${APP_URL} + + DB_HOST: db + DB_PORT: "3306" + DB_NAME: ${DB_NAME:-freescout} + DB_USER: ${DB_USER:-freescout} + DB_PASS: ${DB_PASSWORD} + + ADMIN_EMAIL: ${ADMIN_EMAIL} + ADMIN_PASS: ${ADMIN_PASSWORD} + + DISPLAY_ERRORS: "FALSE" + ENABLE_SMTP: ${ENABLE_SMTP:-TRUE} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASS: ${SMTP_PASS:-} + SMTP_FROM_ADDRESS: ${SMTP_FROM_ADDRESS:-} + SMTP_FROM_NAME: ${SMTP_FROM_NAME:-FreeScout} + + TIMEZONE: ${TIMEZONE:-UTC} + + CONTAINER_ENABLE_MONITORING: "FALSE" + volumes: + - freescout_data:/www/html + - freescout_logs:/www/logs + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost/"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 60s + + db: + image: mariadb:10.11 + container_name: freescout-db + restart: unless-stopped + environment: + MARIADB_DATABASE: ${DB_NAME:-freescout} + MARIADB_USER: ${DB_USER:-freescout} + MARIADB_PASSWORD: ${DB_PASSWORD} + MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + volumes: + - freescout_db:/var/lib/mysql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 15s + timeout: 5s + retries: 10 + start_period: 30s + +volumes: + freescout_data: + freescout_logs: + freescout_db: From 4e6625998b8d4b32b27477e4ac82725a9b1151ae Mon Sep 17 00:00:00 2001 From: "replicas-connector[bot]" Date: Wed, 27 May 2026 17:18:32 +0000 Subject: [PATCH 2/2] fix(deploy): align compose with current nfrastack/freescout image API The previous compose used legacy `tiredofit/freescout` env vars (`SMTP_HOST`, `ENABLE_SMTP`, `DISPLAY_ERRORS`, `CONTAINER_ENABLE_MONITORING`, `SITE_URL`) and mounted `/www/html` for persistence. As of the May 2026 rebrand the canonical image is `nfrastack/freescout`, mail config moved to the `FREESCOUT_MAIL_*` prefix, and persistent state lives at `/data` (sessions, cache, modules, generated config). Without `/data` mounted the container loses state across restarts; without the new mail vars SMTP silently does not get written into FreeScout's `.env`. - switch image to `nfrastack/freescout` - mount `/data` (state) and `/logs` (logs); drop the source-tree mount - use `APP_URL` (canonical) instead of `SITE_URL` (legacy alias) - set `DB_TYPE=mariadb` so the entrypoint writes the right driver - move SMTP to `FREESCOUT_MAIL_*` and expose `SMTP_ENCRYPTION` - swap the curl-based healthcheck for a bash TCP probe (curl is not guaranteed to be present in the alpine base) and lift `start_period` so the first-boot schema migration has room to finish Co-Authored-By: Claude Opus 4.7 (1M context) Co-Authored-By: itsablabla --- deploy/.env.example | 10 +++++----- deploy/README.md | 21 +++++++++++++++------ deploy/docker-compose.yml | 38 +++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/deploy/.env.example b/deploy/.env.example index 82586dcfb..6e59254c0 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -4,12 +4,11 @@ # Public URL FreeScout will be served from (no trailing slash). APP_URL=https://help.example.com -# Hostname only (matches APP_URL host) — used by reverse proxies. -APP_HOST=help.example.com # Host port the app container binds to. Point your reverse proxy here. APP_PORT=8080 -# FreeScout Docker image tag. Pin to a release in production. +# FreeScout Docker image tag. Pin to a release in production +# (see https://hub.docker.com/r/nfrastack/freescout/tags). FREESCOUT_IMAGE_TAG=latest # --- Database (MariaDB) --- @@ -18,16 +17,17 @@ DB_USER=freescout DB_PASSWORD=change-me-strong-password DB_ROOT_PASSWORD=change-me-strong-root-password -# --- Initial admin user (created on first run) --- +# --- Initial admin user (created on first run only) --- ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=change-me-strong-password # --- Outbound mail (SMTP) --- -ENABLE_SMTP=TRUE SMTP_HOST=smtp.example.com SMTP_PORT=587 SMTP_USER=postmaster@example.com SMTP_PASS=change-me +# tls, ssl, or leave blank for none. +SMTP_ENCRYPTION=tls SMTP_FROM_ADDRESS=help@example.com SMTP_FROM_NAME=Nomad Support diff --git a/deploy/README.md b/deploy/README.md index 6765b7403..e81854b6f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -12,19 +12,28 @@ Single-host Docker Compose stack for FreeScout (app + MariaDB). ```bash cp deploy/.env.example deploy/.env -# Edit deploy/.env — set APP_URL/APP_HOST, DB and admin passwords, SMTP creds. +# Edit deploy/.env — set APP_URL, DB and admin passwords, SMTP creds. docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d docker compose -f deploy/docker-compose.yml --env-file deploy/.env logs -f app ``` -Then browse to `APP_URL` and finish the FreeScout web installer (it picks up -the DB credentials and admin user from the container environment). +First boot can take 2–5 minutes while the schema is created and assets are +warmed. Once the `app` container is healthy, FreeScout will be reachable at +`APP_URL` (the bootstrap admin is created automatically from +`ADMIN_EMAIL` / `ADMIN_PASSWORD`). ## Operations - Update the image: bump `FREESCOUT_IMAGE_TAG` in `deploy/.env`, then `docker compose -f deploy/docker-compose.yml --env-file deploy/.env pull && ... up -d`. -- App data is stored in the `freescout_data`, `freescout_logs`, and - `freescout_db` named volumes. Back these up off-box. -- Container image: [`tiredofit/freescout`](https://github.com/tiredofit/docker-freescout). +- App state (sessions, cache, uploaded files, installed Modules, generated + config) lives in `freescout_data` (`/data` inside the container). Logs live + in `freescout_logs`, and the database in `freescout_db`. Back all three up + off-box. +- Container image: + [`nfrastack/freescout`](https://github.com/nfrastack/container-freescout) + (the canonical successor to the legacy `tiredofit/freescout` image). +- Any additional FreeScout `.env` setting can be injected with the + `FREESCOUT_` prefix — e.g. `FREESCOUT_APP_TRUSTED_PROXIES=10.0.0.0/8` is + written into FreeScout's config as `APP_TRUSTED_PROXIES=10.0.0.0/8`. diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index a8693f4a0..7d5b32c31 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -11,7 +11,7 @@ services: app: - image: tiredofit/freescout:${FREESCOUT_IMAGE_TAG:-latest} + image: nfrastack/freescout:${FREESCOUT_IMAGE_TAG:-latest} container_name: freescout-app restart: unless-stopped depends_on: @@ -20,9 +20,12 @@ services: ports: - "${APP_PORT:-8080}:80" environment: - VIRTUAL_HOST: ${APP_HOST} - SITE_URL: ${APP_URL} + CONTAINER_NAME: freescout-app + TIMEZONE: ${TIMEZONE:-UTC} + + APP_URL: ${APP_URL} + DB_TYPE: mariadb DB_HOST: db DB_PORT: "3306" DB_NAME: ${DB_NAME:-freescout} @@ -32,27 +35,24 @@ services: ADMIN_EMAIL: ${ADMIN_EMAIL} ADMIN_PASS: ${ADMIN_PASSWORD} - DISPLAY_ERRORS: "FALSE" - ENABLE_SMTP: ${ENABLE_SMTP:-TRUE} - SMTP_HOST: ${SMTP_HOST:-} - SMTP_PORT: ${SMTP_PORT:-587} - SMTP_USER: ${SMTP_USER:-} - SMTP_PASS: ${SMTP_PASS:-} - SMTP_FROM_ADDRESS: ${SMTP_FROM_ADDRESS:-} - SMTP_FROM_NAME: ${SMTP_FROM_NAME:-FreeScout} - - TIMEZONE: ${TIMEZONE:-UTC} - - CONTAINER_ENABLE_MONITORING: "FALSE" + FREESCOUT_APP_TIMEZONE: ${TIMEZONE:-UTC} + FREESCOUT_MAIL_DRIVER: smtp + FREESCOUT_MAIL_HOST: ${SMTP_HOST:-} + FREESCOUT_MAIL_PORT: ${SMTP_PORT:-587} + FREESCOUT_MAIL_USERNAME: ${SMTP_USER:-} + FREESCOUT_MAIL_PASSWORD: ${SMTP_PASS:-} + FREESCOUT_MAIL_ENCRYPTION: ${SMTP_ENCRYPTION:-tls} + FREESCOUT_MAIL_FROM_ADDRESS: ${SMTP_FROM_ADDRESS:-} + FREESCOUT_MAIL_FROM_NAME: ${SMTP_FROM_NAME:-FreeScout} volumes: - - freescout_data:/www/html - - freescout_logs:/www/logs + - freescout_data:/data + - freescout_logs:/logs healthcheck: - test: ["CMD", "curl", "-fsS", "http://localhost/"] + test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/80"] interval: 30s timeout: 10s retries: 5 - start_period: 60s + start_period: 120s db: image: mariadb:10.11