2 changed files with 0 additions and 215 deletions
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
services: |
||||
db: |
||||
build: ./db |
||||
volumes: |
||||
- pgdata:/var/lib/postgresql/data |
||||
environment: |
||||
POSTGRES_USER: ${POSTGRES_USER} |
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} |
||||
POSTGRES_DB: ${POSTGRES_DB} |
||||
networks: |
||||
- internal |
||||
restart: unless-stopped |
||||
healthcheck: |
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] |
||||
interval: 5s |
||||
timeout: 5s |
||||
retries: 5 |
||||
|
||||
app: |
||||
build: . |
||||
ports: |
||||
- "${PORT:-4000}:${PORT:-4000}" |
||||
environment: |
||||
DATABASE_URL: "ecto://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB}" |
||||
SECRET_KEY_BASE: ${SECRET_KEY_BASE} |
||||
PHX_HOST: ${PHX_HOST} |
||||
PORT: ${PORT:-4000} |
||||
depends_on: |
||||
db: |
||||
condition: service_healthy |
||||
networks: |
||||
- internal |
||||
restart: unless-stopped |
||||
|
||||
volumes: |
||||
pgdata: |
||||
|
||||
networks: |
||||
internal: |
||||
driver: bridge |
||||
@ -1,175 +0,0 @@
@@ -1,175 +0,0 @@
|
||||
# Deployment Guide |
||||
|
||||
This guide covers deploying GcIndexRelay on a VPS using Docker Compose. |
||||
|
||||
## Architecture |
||||
|
||||
``` |
||||
Host reverse proxy (port 80/443) → localhost:4000 |
||||
↓ |
||||
Phoenix container (app) — published port 4000:4000 |
||||
↓ (internal Docker network only) |
||||
AGE/Postgres container (db) — no published ports, volume: pgdata |
||||
``` |
||||
|
||||
TLS is terminated by the host-level reverse proxy. The Phoenix app runs behind |
||||
it and trusts the `X-Forwarded-Proto` header to enforce HTTPS. |
||||
|
||||
## Prerequisites |
||||
|
||||
- A VPS running Debian/Ubuntu |
||||
- Docker and Docker Compose installed |
||||
- A domain name pointed at your VPS |
||||
|
||||
## 1. Install Docker and Docker Compose |
||||
|
||||
```bash |
||||
curl -fsSL https://get.docker.com | sh |
||||
sudo usermod -aG docker $USER |
||||
# Log out and back in for group membership to take effect |
||||
``` |
||||
|
||||
Verify: `docker compose version` |
||||
|
||||
## 2. Clone the Repository |
||||
|
||||
```bash |
||||
git clone <repo-url> /opt/gc_index_relay |
||||
cd /opt/gc_index_relay |
||||
``` |
||||
|
||||
## 3. Configure Secrets |
||||
|
||||
Copy the example file and fill in your values: |
||||
|
||||
```bash |
||||
cp .env.example .env |
||||
$EDITOR .env |
||||
``` |
||||
|
||||
Required values to set in `.env`: |
||||
|
||||
- **`POSTGRES_PASSWORD`** — use a strong random password |
||||
- **`SECRET_KEY_BASE`** — generate with: |
||||
```bash |
||||
docker run --rm hexpm/elixir:1.17.3-erlang-27.3.4.7-debian-trixie-20260202-slim \ |
||||
mix phx.gen.secret |
||||
# or without Docker: |
||||
openssl rand -base64 64 |
||||
``` |
||||
- **`PHX_HOST`** — your actual domain name (e.g. `relay.example.com`) |
||||
|
||||
## 4. Set Up the Reverse Proxy |
||||
|
||||
The app listens on `localhost:4000`. Configure nginx or Caddy to forward |
||||
traffic and terminate TLS. |
||||
|
||||
### Caddy (recommended) |
||||
|
||||
```caddy |
||||
relay.example.com { |
||||
reverse_proxy localhost:4000 |
||||
} |
||||
``` |
||||
|
||||
### nginx |
||||
|
||||
```nginx |
||||
server { |
||||
listen 443 ssl; |
||||
server_name relay.example.com; |
||||
|
||||
ssl_certificate /etc/letsencrypt/live/relay.example.com/fullchain.pem; |
||||
ssl_certificate_key /etc/letsencrypt/live/relay.example.com/privkey.pem; |
||||
|
||||
location / { |
||||
proxy_pass http://localhost:4000; |
||||
proxy_set_header Host $host; |
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
||||
proxy_set_header X-Forwarded-Proto $scheme; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
## 5. Configure Firewall |
||||
|
||||
Expose only SSH, HTTP, and HTTPS to the public internet: |
||||
|
||||
```bash |
||||
sudo ufw allow 22/tcp |
||||
sudo ufw allow 80/tcp |
||||
sudo ufw allow 443/tcp |
||||
sudo ufw enable |
||||
``` |
||||
|
||||
The database port (5432) must **not** be exposed — it is on an internal Docker |
||||
network only and never published to the host. |
||||
|
||||
## 6. Build and Start the Stack |
||||
|
||||
```bash |
||||
docker compose build |
||||
docker compose up -d |
||||
``` |
||||
|
||||
On first start, the app container will: |
||||
1. Wait for the database to pass its health check |
||||
2. Run any pending Ecto migrations |
||||
3. Start the Phoenix server |
||||
|
||||
## 7. Verify the Deployment |
||||
|
||||
```bash |
||||
# Check container status |
||||
docker compose ps |
||||
|
||||
# Health check endpoint |
||||
curl http://localhost:4000/health |
||||
# Expected: 200 OK, body: "ok" |
||||
|
||||
# API endpoint |
||||
curl http://localhost:4000/api/events |
||||
# Expected: JSON response |
||||
|
||||
# Confirm database port is NOT accessible from host |
||||
curl http://localhost:5432 |
||||
# Expected: connection refused |
||||
``` |
||||
|
||||
## Operations |
||||
|
||||
### View logs |
||||
|
||||
```bash |
||||
docker compose logs -f app |
||||
docker compose logs -f db |
||||
``` |
||||
|
||||
### Restart the app |
||||
|
||||
```bash |
||||
docker compose restart app |
||||
``` |
||||
|
||||
### Stop everything |
||||
|
||||
```bash |
||||
docker compose down |
||||
``` |
||||
|
||||
Database data is persisted in the `pgdata` Docker volume and survives |
||||
`docker compose down`. To also delete the data: |
||||
|
||||
```bash |
||||
docker compose down -v |
||||
``` |
||||
|
||||
### Update to a new version |
||||
|
||||
```bash |
||||
git pull |
||||
docker compose build |
||||
docker compose up -d |
||||
``` |
||||
|
||||
Migrations run automatically on startup. |
||||
Loading…
Reference in new issue