Skip to content

Commit e04bf83

Browse files
committed
Add docker file
1 parent f06ffa3 commit e04bf83

File tree

6 files changed

+204
-23
lines changed

6 files changed

+204
-23
lines changed

.env.server.example

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# EasyRelocate — server (Option B: self-hosted backend + Postgres + Caddy)
2+
#
3+
# Copy to `.env.server` on your server and fill in values:
4+
# cp .env.server.example .env.server
5+
#
6+
# Then deploy:
7+
# docker compose -f docker-compose.server.yml --env-file .env.server up -d --build
8+
#
9+
# Never commit `.env.server` (it contains secrets).
10+
11+
###############################################################################
12+
# Postgres (Docker)
13+
###############################################################################
14+
POSTGRES_DB="easyrelocate"
15+
POSTGRES_USER="easyrelocate"
16+
POSTGRES_PASSWORD="CHANGE_ME_STRONG_PASSWORD"
17+
18+
# Backend uses this DSN to connect to the Postgres container.
19+
DATABASE_URL="postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}"
20+
21+
###############################################################################
22+
# Backend (FastAPI)
23+
###############################################################################
24+
# CORS allowlist for your Vercel app and/or custom frontend domain.
25+
# Example:
26+
# CORS_ALLOW_ORIGINS="https://easyrelocate.vercel.app,https://easyrelocate.net"
27+
CORS_ALLOW_ORIGINS="https://YOUR_VERCEL_APP_DOMAIN"
28+
29+
# Enable self-serve tokens (onboarding token issuance)
30+
ENABLE_PUBLIC_WORKSPACE_ISSUE="1"
31+
PUBLIC_WORKSPACE_TTL_DAYS="30"
32+
33+
# Optional: Google Maps server-side geocoding
34+
# GOOGLE_MAPS_API_KEY="YOUR_SERVER_KEY"
35+
# GEOCODING_PROVIDER="google"
36+
# ENABLE_GEOCODING="1"
37+
38+
# Optional: OpenRouter LLM extraction for selected posts
39+
# OPENROUTER_API_KEY="YOUR_OPENROUTER_KEY"
40+
# OPENROUTER_MODEL="z-ai/glm-4.5-air:free"
41+

backend/Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM python:3.11-slim
2+
3+
ENV PYTHONDONTWRITEBYTECODE=1 \
4+
PYTHONUNBUFFERED=1
5+
6+
WORKDIR /app
7+
8+
COPY requirements.txt /app/requirements.txt
9+
RUN pip install --no-cache-dir -r /app/requirements.txt
10+
11+
COPY app /app/app
12+
COPY scripts /app/scripts
13+
14+
EXPOSE 8000
15+
16+
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
17+

deploy/Caddyfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
api.easyrelocate.net {
2+
encode gzip
3+
reverse_proxy backend:8000
4+
}
5+

deploy/server-deploy.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
5+
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env.server}"
6+
7+
if [[ ! -f "$ENV_FILE" ]]; then
8+
echo "Missing env file: $ENV_FILE" >&2
9+
echo "Create it first, e.g.: cp .env.server.example .env.server" >&2
10+
exit 2
11+
fi
12+
13+
cd "$ROOT_DIR"
14+
15+
docker compose -f docker-compose.server.yml --env-file "$ENV_FILE" up -d --build
16+
17+
echo "Up. Services:"
18+
docker compose -f docker-compose.server.yml --env-file "$ENV_FILE" ps
19+

docker-compose.server.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
services:
2+
postgres:
3+
image: postgres:16-alpine
4+
environment:
5+
POSTGRES_DB: ${POSTGRES_DB:-easyrelocate}
6+
POSTGRES_USER: ${POSTGRES_USER:-easyrelocate}
7+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env.server}
8+
volumes:
9+
- easyrelocate_postgres:/var/lib/postgresql/data
10+
restart: unless-stopped
11+
12+
backend:
13+
build:
14+
context: ./backend
15+
environment:
16+
DATABASE_URL: ${DATABASE_URL:?Set DATABASE_URL in .env.server}
17+
CORS_ALLOW_ORIGINS: ${CORS_ALLOW_ORIGINS:?Set CORS_ALLOW_ORIGINS in .env.server}
18+
ENABLE_PUBLIC_WORKSPACE_ISSUE: ${ENABLE_PUBLIC_WORKSPACE_ISSUE:-1}
19+
PUBLIC_WORKSPACE_TTL_DAYS: ${PUBLIC_WORKSPACE_TTL_DAYS:-30}
20+
GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY:-}
21+
GEOCODING_PROVIDER: ${GEOCODING_PROVIDER:-}
22+
ENABLE_GEOCODING: ${ENABLE_GEOCODING:-1}
23+
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
24+
OPENROUTER_MODEL: ${OPENROUTER_MODEL:-}
25+
depends_on:
26+
- postgres
27+
restart: unless-stopped
28+
29+
caddy:
30+
image: caddy:2-alpine
31+
ports:
32+
- "80:80"
33+
- "443:443"
34+
volumes:
35+
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
36+
- caddy_data:/data
37+
- caddy_config:/config
38+
depends_on:
39+
- backend
40+
restart: unless-stopped
41+
42+
volumes:
43+
easyrelocate_postgres:
44+
caddy_data:
45+
caddy_config:
46+

docs/DEPLOYMENT.md

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -138,49 +138,102 @@ Security note:
138138
This is the lowest “monthly bill” option if you already have hardware, but you must handle:
139139
patching, backups, and uptime.
140140

141-
### B1) Run Postgres + backend on the server
141+
### B0) Your chosen domain + FRP ports
142142

143-
Recommended:
144-
- Use Docker Compose.
145-
- Keep Postgres private (not exposed to the internet).
146-
- Expose only the reverse proxy (80/443).
143+
You chose:
144+
- Backend domain: `api.easyrelocate.net`
145+
- Tunnel: `frp` (you can forward any port)
146+
- Tokens: self-serve tokens enabled (`ENABLE_PUBLIC_WORKSPACE_ISSUE=1`)
147147

148-
Minimum you need:
149-
- A public backend URL (e.g. `https://api.example.com`)
150-
- `DATABASE_URL` pointing at the Postgres container
148+
For Caddy automatic HTTPS, you should forward:
149+
- **remote 80 → server 80** (for ACME HTTP-01 challenge)
150+
- **remote 443 → server 443** (for HTTPS traffic)
151151

152-
Example `DATABASE_URL` (Compose network):
153-
```text
154-
postgresql+psycopg://easyrelocate_user:DB_PASSWORD@postgres:5432/easyrelocate
152+
### B1) Prepare the server (Ubuntu miniPC)
153+
154+
1. Install Docker + Docker Compose plugin on the server.
155+
2. Clone the repo:
156+
```bash
157+
git clone https://github.com/YuWei-CH/EasyRelocate.git
158+
cd EasyRelocate
155159
```
156160

157-
### B2) Reverse proxy + HTTPS
161+
### B2) Create server env file
158162

159-
Use Caddy or Nginx to terminate HTTPS and proxy to the backend container.
163+
Create `.env.server` (do not commit it):
164+
```bash
165+
cp .env.server.example .env.server
166+
```
160167

161-
If you use FRP:
162-
- Prefer mapping FRP to 443 with TLS termination at the server (Caddy/Nginx).
163-
- If FRP terminates TLS upstream, ensure the backend sees correct headers and set a strict CORS allowlist.
168+
Edit `.env.server`:
169+
- Set `POSTGRES_PASSWORD` (strong password)
170+
- Set `CORS_ALLOW_ORIGINS` to include your Vercel domain(s)
171+
- Keep `ENABLE_PUBLIC_WORKSPACE_ISSUE=1` if you want onboarding to auto-issue tokens
164172

165-
### B3) Vercel config
173+
### B3) Start Postgres + backend + HTTPS proxy (Docker Compose)
166174

167-
Set:
168-
```text
169-
VITE_API_BASE_URL=https://api.example.com
175+
On the server:
176+
```bash
177+
docker compose -f docker-compose.server.yml --env-file .env.server up -d --build
170178
```
171179

172-
And on the backend:
180+
Or use the helper script:
181+
```bash
182+
ENV_FILE=.env.server bash deploy/server-deploy.sh
183+
```
184+
185+
Check:
186+
```bash
187+
docker compose -f docker-compose.server.yml --env-file .env.server ps
188+
```
189+
190+
### B4) Configure FRP
191+
192+
On your **FRP server** (public machine), ensure ports 80/443 are open.
193+
194+
On your **miniPC**, configure `frpc` to forward:
195+
- `api.easyrelocate.net:80``miniPC:80`
196+
- `api.easyrelocate.net:443``miniPC:443`
197+
198+
Once the DNS for `api.easyrelocate.net` points to your FRP server and the tunnel is active,
199+
visit:
200+
- `https://api.easyrelocate.net/api/health`
201+
202+
You should see:
203+
```json
204+
{"status":"ok"}
205+
```
206+
207+
### B5) Deploy frontend to Vercel
208+
209+
Set Vercel env vars:
173210
```text
174-
CORS_ALLOW_ORIGINS=https://your-vercel-domain.vercel.app,https://your-custom-domain.com
211+
VITE_API_BASE_URL=https://api.easyrelocate.net
212+
VITE_GOOGLE_MAPS_API_KEY=YOUR_BROWSER_KEY
175213
```
176214

177-
### B4) Backups (required)
215+
After deploy, open the web app and go through onboarding.
216+
217+
### B6) Postgres backups (required)
178218

179219
At minimum:
180220
- daily `pg_dump`
181221
- keep 7–30 days of backups
182222
- periodically test restore
183223

224+
### B7) Security notes
225+
226+
- Do **not** expose Postgres to the public internet (Compose keeps it internal by default).
227+
- Keep a strict `CORS_ALLOW_ORIGINS` allowlist (your Vercel domain + any custom domain).
228+
- Treat workspace tokens as passwords.
229+
230+
### Files in this repo (Option B)
231+
232+
- `docker-compose.server.yml` — Postgres + backend + Caddy
233+
- `deploy/Caddyfile` — HTTPS reverse proxy for `api.easyrelocate.net`
234+
- `.env.server.example` — server env template
235+
- `deploy/server-deploy.sh` — helper to start the stack
236+
184237
## Troubleshooting
185238

186239
### Frontend loads but API calls hang / abort

0 commit comments

Comments
 (0)