initial install
This commit is contained in:
@@ -1,63 +1,198 @@
|
||||
# Deployment Guide
|
||||
# Deployment Guide — Self-Hosted (Unraid + Gitea)
|
||||
|
||||
## Prerequisites
|
||||
## Overview
|
||||
|
||||
- Git installed on the server
|
||||
- Docker and Docker Compose installed on the server
|
||||
This app runs as two Docker containers:
|
||||
- **app** — Next.js server (port 3000)
|
||||
- **db** — PostgreSQL 16 (port 5432)
|
||||
|
||||
## Step 1: Configure environment
|
||||
---
|
||||
|
||||
Copy the example env file and fill in real values:
|
||||
## 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
|
||||
cp .env.production.example .env.production
|
||||
# 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
|
||||
```
|
||||
|
||||
Edit `.env.production` and set all 11 variables:
|
||||
Create the repo in Gitea first (via the Gitea web UI) before pushing.
|
||||
|
||||
- `DATABASE_URL` — Neon PostgreSQL connection string
|
||||
- `SIGNING_JWT_SECRET` — secret for signing JWT tokens
|
||||
- `AUTH_SECRET` — NextAuth secret
|
||||
- `AGENT_EMAIL` — agent login email
|
||||
- `AGENT_PASSWORD` — agent login password
|
||||
- `CONTACT_EMAIL_USER` — SMTP username
|
||||
- `CONTACT_EMAIL_PASS` — SMTP password
|
||||
- `CONTACT_SMTP_HOST` — SMTP host (e.g. `smtp.gmail.com`)
|
||||
- `CONTACT_SMTP_PORT` — SMTP port (e.g. `465`)
|
||||
- `OPENAI_API_KEY` — OpenAI API key for AI field placement
|
||||
- `APP_BASE_URL` — public URL of the app (e.g. `https://teressacopelandhomes.com`)
|
||||
---
|
||||
|
||||
## Step 2: Run database migration
|
||||
## Part 2: Build and Push Docker Image to Gitea Registry
|
||||
|
||||
Run migrations from the project directory on the host (not inside Docker):
|
||||
Gitea includes a built-in OCI container registry. Replace `YOUR_UNRAID_IP`, `YOUR_GITEA_USERNAME`, and `YOUR_GITEA_PORT` with your values.
|
||||
|
||||
```bash
|
||||
DATABASE_URL=<your-neon-url> npx drizzle-kit migrate
|
||||
# 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
|
||||
```
|
||||
|
||||
This must complete successfully before starting the container. Migrations are never run inside the Docker image.
|
||||
> **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.
|
||||
|
||||
## Step 3: Build and start
|
||||
> **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
|
||||
docker compose up -d --build
|
||||
# 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
|
||||
```
|
||||
|
||||
## Step 4: Verify
|
||||
### Seed agent account + form templates
|
||||
|
||||
```bash
|
||||
curl http://localhost:3000/api/health
|
||||
# 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
|
||||
```
|
||||
|
||||
Expected response: `{"ok":true,"db":"connected"}`
|
||||
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
|
||||
|
||||
To deploy a new version:
|
||||
When you push a new version:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
# If schema changed, re-run migration first:
|
||||
DATABASE_URL=<your-neon-url> npx drizzle-kit migrate
|
||||
docker compose up -d --build
|
||||
# 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.
|
||||
|
||||
Reference in New Issue
Block a user