Files
ttvfx/DEPLOY.md
T
twotalesanimation 22bc903041
Deploy / deploy (push) Successful in 1m5s
/previz: password protect, add PDF export of the crowd previz
- nginx basic auth on /previz/ (login file lives on the server, mounted
  from docker/auth/, see DEPLOY.md step 8); private, no-store so
  Cloudflare never caches it
- Print styles for previz pages: dark, A4 landscape, one section a page;
  videos print as poster frames with a link
- scripts/previz-pdf.mjs (npm run previz:pdf) prints the page to
  public/previz/crowd/crowd-previz.pdf via Edge/Chrome DevTools
- "PDF" download link on the page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 06:21:25 +02:00

156 lines
5.9 KiB
Markdown

# Deploying twotalesvfx.com
Same setup as the other apps (vfxreview, xbid):
```
git push main ──► Gitea Actions runner ──► cd /opt/ttvfx_web && git pull
docker compose up -d --build
│
Cloudflare ──► Nginx Proxy Manager ──► ttvfx-web:80 (nginx, static files)
(npm_default network)
```
Files involved:
| File | What it does |
|------|--------------|
| `Dockerfile` | Builds the static export with Node 20, then serves `out/` from `nginx:alpine` |
| `docker/nginx.conf` | nginx config inside the container (routes, 404 page, caching, relative redirects) |
| `docker-compose.yml` | One service, container name `ttvfx-web`, joined to the external `npm_default` network, no host ports |
| `.gitea/workflows/deploy.yml` | On push to `main`: pull in `/opt/ttvfx_web` and rebuild |
There is no `.env` and no database. The site is fully static.
---
## One-time setup on the server
### 1. SSH in
```bash
ssh <you>@178.104.56.62 # git.twotalesvfx.com's IP; use your usual host if different
```
### 2. Check how the existing apps are set up, and copy that
```bash
ls -la /opt # note the owner of /opt/xbid and /opt/vfxreview
git -C /opt/xbid remote -v # note HOW it authenticates (https+token, ssh, ...)
docker network ls | grep npm_default
```
`npm_default` must exist. It's the Nginx Proxy Manager network.
### 3. Clone into /opt/ttvfx_web
Use the same remote style as `/opt/xbid` so the runner's `git pull` can authenticate.
For example, if xbid uses an https remote:
```bash
sudo git clone https://git.twotalesvfx.com/pinto/ttvfx.git /opt/ttvfx_web
```
Then match the ownership of the other app folders (replace `<owner>` with what `ls -la /opt` showed):
```bash
sudo chown -R <owner>:<owner> /opt/ttvfx_web
```
If xbid's remote URL contains a token or uses SSH, clone this one the same way
(e.g. `git clone git@git.twotalesvfx.com:pinto/ttvfx.git /opt/ttvfx_web`).
### 4. First build by hand
```bash
cd /opt/ttvfx_web
docker compose up -d --build
docker ps --filter name=ttvfx-web # should be "Up"
```
The first build takes a minute or two (npm install + Next build). Later builds reuse the cache.
Check that it serves from inside the proxy network:
```bash
docker run --rm --network npm_default curlimages/curl -sI http://ttvfx-web/
# -> HTTP/1.1 200 OK
```
### 5. Nginx Proxy Manager: add the proxy host
In the NPM web UI → **Hosts → Proxy Hosts → Add Proxy Host**:
- **Domain names:** `twotalesvfx.com`, `www.twotalesvfx.com`
- **Scheme:** `http`
- **Forward hostname / IP:** `ttvfx-web`
- **Forward port:** `80`
- Tick **Block common exploits**. Websockets aren't needed.
- **SSL tab:** request a new Let's Encrypt certificate, then tick **Force SSL** and **HTTP/2**.
- Cloudflare is proxying the domain. If the HTTP challenge fails, either grey-cloud the two
records for a minute while the cert is issued, or use **DNS challenge → Cloudflare**
with an API token. Use whichever you did for `review.` / `xbid.`.
### 6. Cloudflare DNS
The apex currently returns **522** (Cloudflare can't reach the origin). Point it at this server:
| Type | Name | Value | Proxy |
|------|-------|------------------|---------|
| A | `@` | `178.104.56.62` | Proxied |
| A | `www` | `178.104.56.62` | Proxied |
(Confirm the server's IP with `curl -4 ifconfig.me` on the box.) Leave `review`, `git`, `xbid` etc. alone.
Set **SSL/TLS → Full (strict)**, the same as the other subdomains.
### 7. Turn on auto-deploy
The workflow is already in the repo (`.gitea/workflows/deploy.yml`). In Gitea, open
**pinto/ttvfx → Settings → Repository → Enable Actions** if it isn't enabled already
(it's on for the other repos). The existing runner picks the job up. It uses the same
`ubuntu-latest` label and `/opt:/opt` mount as xbid.
Test it: push any commit to `main` and watch **Actions** in the repo. The job should run
`git pull` and `docker compose up -d --build`, then the site updates.
### 8. Password for /previz/
Client previz pages under `/previz/` need a login (HTTP basic auth in `docker/nginx.conf`).
The password file stays on the server and is never committed. Create it once:
```bash
cd /opt/ttvfx_web
mkdir -p docker/auth
printf "production:$(openssl passwd -apr1)\n" > docker/auth/previz.htpasswd # prompts for the password
docker compose up -d --force-recreate
```
`production` is the username. To change the password, run the `printf` line again. nginx reads
the file on every request, so no restart is needed. To add a second login, append another line
with `>>`. If the file is missing, `/previz/` returns a 500 error, so it is never left open.
---
## Day to day
```bash
git push # from your machine. That's it, the runner deploys.
```
Manual redeploy or logs on the server:
```bash
cd /opt/ttvfx_web && git pull && docker compose up -d --build
docker logs -f ttvfx-web
```
## Troubleshooting
| Symptom | Fix |
|---------|-----|
| Action fails on `git pull` with *dubious ownership* | `git config --global --add safe.directory /opt/ttvfx_web` (run it however you did for xbid), or fix ownership to match `/opt/xbid` |
| Action fails on `git pull` with *authentication* | The clone's remote URL needs the same credentials as `/opt/xbid` (`git -C /opt/xbid remote -v`) |
| `network npm_default declared as external, but could not be found` | NPM's network has a different name on this box. Check `docker network ls` and update `docker-compose.yml` |
| NPM shows **502 Bad Gateway** | Container not running (`docker ps`) or wrong forward host. It must be `ttvfx-web`, port `80` |
| Cloudflare **522** | DNS `@`/`www` still point at the wrong IP, or ports 80/443 are firewalled |
| Old content after deploy | Purge Cloudflare cache (Caching → Purge Everything). HTML isn't cached long, but video and images are cached for 7 days |