# Deployment Guide — Self-Hosted (Unraid + Gitea) ## Overview This app runs as two Docker containers: - **app** — Next.js server (port 3000) - **db** — PostgreSQL 16 (port 5432) --- ## Required Secrets All of these must be set in `.env.production` before starting. | Variable | What it is | How to get it | |---|---|---| | `DATABASE_URL` | Internal postgres URL | `postgresql://postgres:POSTGRES_PASSWORD@db:5432/teressa` | | `POSTGRES_PASSWORD` | Postgres superuser password | Generate: `openssl rand -base64 32` | | `SIGNING_JWT_SECRET` | Signs document signing tokens | Generate: `openssl rand -base64 32` | | `AUTH_SECRET` | NextAuth session encryption | Generate: `openssl rand -base64 32` | | `AUTH_TRUST_HOST` | Required for reverse proxy | Set to `true` | | `AGENT_EMAIL` | Your login email for the portal | Your email address | | `AGENT_PASSWORD` | Your login password for the portal | Choose a strong password | | `CONTACT_EMAIL_USER` | SMTP username | See SMTP section below | | `CONTACT_EMAIL_PASS` | SMTP password/API key | See SMTP section below | | `CONTACT_SMTP_HOST` | SMTP server hostname | See SMTP section below | | `CONTACT_SMTP_PORT` | SMTP port | `587` (STARTTLS) or `465` (SSL) | | `OPENAI_API_KEY` | OpenAI API key for AI field placement | platform.openai.com → API keys | | `APP_BASE_URL` | Public URL of the app (no trailing slash) | e.g. `https://teressa.yourdomain.com` | ### SMTP Options - **Resend** (recommended): host=`smtp.resend.com`, port=`465`, user=`resend`, pass=Resend API key - **Gmail**: host=`smtp.gmail.com`, port=`587`, user=your Gmail, pass=App Password (not your regular password) --- ## Part 1: Push Repo to Gitea ### On your local machine ```bash # Add your Gitea instance as a remote git remote add gitea http://YOUR_UNRAID_IP:3000/YOUR_GITEA_USERNAME/teressa-copeland-homes.git # Push git push gitea main ``` Create the repo in Gitea first (via the Gitea web UI) before pushing. --- ## Part 2: Build and Push Docker Image to Gitea Registry Gitea includes a built-in OCI container registry. Replace `YOUR_UNRAID_IP`, `YOUR_GITEA_USERNAME`, and `YOUR_GITEA_PORT` with your values. ```bash # Log in to Gitea's container registry docker login YOUR_UNRAID_IP:YOUR_GITEA_PORT # Build the image (from the project root) docker build -t YOUR_UNRAID_IP:YOUR_GITEA_PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest . # Push to Gitea registry docker push YOUR_UNRAID_IP:YOUR_GITEA_PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest ``` > **Gitea registry port** is usually the same as the Gitea web port (e.g. 3000 or 10880 depending on your setup). Check your Gitea container settings in Unraid. > **HTTP registry**: If Gitea is HTTP (not HTTPS), add the registry to Docker's insecure registries. On Unraid, go to **Settings → Docker → Insecure Registries** and add `YOUR_UNRAID_IP:PORT`. --- ## Part 3: Deploy on Unraid ### Option A: Docker Compose (recommended) Unraid supports docker-compose via the **Compose Manager** community app. 1. Install **Compose Manager** from Community Apps if not already installed 2. SSH into Unraid and create the app directory: ```bash mkdir -p /mnt/user/appdata/teressa-copeland-homes cd /mnt/user/appdata/teressa-copeland-homes ``` 3. Copy `docker-compose.yml` and `.env.production.example` to this directory: ```bash cp docker-compose.yml .env.production.example /mnt/user/appdata/teressa-copeland-homes/ ``` 4. Create `.env.production` from the example and fill in all values: ```bash cp .env.production.example .env.production nano .env.production ``` 5. Set `APP_IMAGE` to your Gitea registry URL in `.env.production`: ``` APP_IMAGE=YOUR_UNRAID_IP:YOUR_GITEA_PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest ``` 6. In Compose Manager, add the compose file and start it ### Option B: Unraid Docker UI (manual containers) Add two containers via **Docker → Add Container**: **Container 1 — postgres** - Repository: `postgres:16-alpine` - Name: `teressa-db` - Port: `5432:5432` - Environment variables: - `POSTGRES_USER=postgres` - `POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD` - `POSTGRES_DB=teressa` - Path: `/mnt/user/appdata/teressa-db` → `/var/lib/postgresql/data` **Container 2 — app** - Repository: `YOUR_UNRAID_IP:YOUR_GITEA_PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest` - Name: `teressa-app` - Port: `3000:3000` - Network: Same as teressa-db (so it can reach `teressa-db` by name, or use Unraid IP) - Environment variables: All 13 from the table above - Note: `DATABASE_URL` should use the Unraid host IP or container name instead of `db` - Path: `/mnt/user/appdata/teressa-uploads` → `/app/uploads` --- ## Part 4: Run Migrations and Seed These must run **after** the database container is healthy, **before** the app is usable. ### Run migrations ```bash # From your local machine (requires node + npx) DATABASE_URL="postgresql://postgres:YOUR_PASSWORD@YOUR_UNRAID_IP:5432/teressa" npx drizzle-kit migrate # Or SSH into Unraid and run from the project directory docker exec -it teressa-app npx drizzle-kit migrate ``` ### Seed agent account + form templates ```bash # SSH into Unraid docker exec \ -e DATABASE_URL="postgresql://postgres:YOUR_PASSWORD@db:5432/teressa" \ -e AGENT_EMAIL="your@email.com" \ -e AGENT_PASSWORD="your-password" \ teressa-app npx tsx scripts/seed.ts # Seed the 140 real estate form templates docker exec \ -e DATABASE_URL="postgresql://postgres:YOUR_PASSWORD@db:5432/teressa" \ teressa-app npx tsx scripts/seed-forms.ts ``` Both seed scripts are idempotent — safe to re-run. --- ## Part 5: Verify ```bash curl http://YOUR_UNRAID_IP:3000/api/health # Expected: {"ok":true,"db":"connected"} ``` Then open `http://YOUR_UNRAID_IP:3000` in a browser and log in with `AGENT_EMAIL` / `AGENT_PASSWORD`. --- ## Updating When you push a new version: ```bash # On local machine — rebuild and push image docker build -t YOUR_UNRAID_IP:PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest . docker push YOUR_UNRAID_IP:PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest # On Unraid — pull new image and restart docker pull YOUR_UNRAID_IP:PORT/YOUR_GITEA_USERNAME/teressa-copeland-homes:latest docker restart teressa-app # If schema changed, run migrations first: DATABASE_URL="postgresql://postgres:YOUR_PASSWORD@YOUR_UNRAID_IP:5432/teressa" npx drizzle-kit migrate ``` --- ## Reverse Proxy (optional) If you want HTTPS via a domain name, put a reverse proxy in front on port 443: - **Nginx Proxy Manager** (available in Unraid Community Apps) — easiest GUI option - **Caddy** — automatic HTTPS with Let's Encrypt - **Traefik** — label-based routing Point the proxy at `http://YOUR_UNRAID_IP:3000`. Make sure `APP_BASE_URL` in `.env.production` matches the public HTTPS URL, and ensure `AUTH_TRUST_HOST=true` is set.