- nginx basic auth on /drops/ (page and clips); login file and clips live on the server only (docker/auth, docker/drops), never in git or the image - Fails closed: missing login file returns 500; no-store, noindex - Page reads manifest.json from the server, shows "taken down" when empty - Player hides download/cast/PiP, blocks right-click, confidential overlay - DEPLOY.md step 8: how to share a drop and take it down Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.9 KiB
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
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
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:
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):
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
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:
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..
- 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
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. Private shot previews at /drops/
/drops/ is a view-only screening page for vendors and clients. nginx asks for a login before
it serves the page or any clip. The login file and the clips stay on the server only, in
docker/auth/ and docker/drops/, and are never committed. The page reads
docker/drops/manifest.json to know which clips to show.
Share a drop. On your PC, convert the clips to web MP4 without re-encoding, then copy them up:
ffmpeg -i SHOT.mov -map 0:v -map 0:a? -c copy -movflags +faststart -map_metadata -1 SHOT.mp4
scp SHOT.mp4 manifest.json <you>@178.104.56.62:/opt/ttvfx_web/docker/drops/
manifest.json looks like this (src is the file name in docker/drops/):
{ "title": "DH2 shot previews", "note": "For review only.",
"files": [{ "name": "DH2_VFX_027_210_REF", "src": "DH2_VFX_027_210_REF.mp4" }] }
Then set a password on the server. Use a new password for each vendor and drop:
cd /opt/ttvfx_web
mkdir -p docker/auth
printf "vendor:$(openssl passwd -apr1)\n" > docker/auth/drops.htpasswd # prompts for the password
docker compose up -d --force-recreate # first time only, so the folders get mounted
Send https://twotalesvfx.com/drops/, the username vendor and the password through two
different channels (for example, the link by email and the password by WhatsApp).
Take it down. No deploy is needed. Delete the clips and the login, and the page returns "taken down" or 500 straight away:
rm /opt/ttvfx_web/docker/drops/* /opt/ttvfx_web/docker/auth/drops.htpasswd
If the login file is missing, /drops/ returns 500, so it is never left open. Nothing in
/drops/ is cached by browsers or Cloudflare.
Day to day
git push # from your machine. That's it, the runner deploys.
Manual redeploy or logs on the server:
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 |