This covers running AnimCSS on your own server, for any reverse proxy or tunnel setup.
- Node.js 20 or newer, or Bun 1.1+
- A Linux server (or macOS/Windows) you can run a long-lived process on
- Optionally, a Supabase project for the community
catalog — see
SUPABASE_SETUP.md. The editor itself works without it.
AnimCSS builds to a plain Node server (not a static site) because the
community catalog's pages need server-side rendering for their metadata.
The build target is already set correctly in vite.config.ts — you don't
need to change anything for this.
git clone <your-fork-or-repo-url> animcss
cd animcssIf you're not using git, copying the extracted project folder over (scp/sftp/rsync) works exactly the same — the steps below don't care how the files got there.
npm install
# or: bun installcp .env.example .envEdit .env:
VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEY— leave blank to run without the catalog, or fill in fromSUPABASE_SETUP.md.PORT— which port the server listens on (defaults to3000if unset).
These are read at build time, so re-run the build after changing them.
npm run build
# or: bun run buildThis produces .output/server/index.mjs (the app) and .output/public/
(static assets). Both are required at runtime — don't delete either.
npm run start
# equivalent to: node .output/server/index.mjsBy default it binds to all interfaces on the port from your .env (or
3000). Visit http://<server-ip>:<port>/ to confirm it's up before
wiring a reverse proxy or tunnel in front of it.
Stop it with Ctrl+C. For anything beyond a quick test, run it under a process supervisor so it survives reboots and crashes — see the next section.
PM2 is the simplest way to keep a Node app alive across crashes and reboots.
npm install -g pm2
pm2 start deploy/ecosystem.config.cjs
pm2 save
pm2 startup # follow the printed command once, so PM2 survives rebootspm2 status
pm2 logs animcssdeploy/ecosystem.config.cjs also defines an animcss-webhook process —
that one's optional, only needed if you set up the
GitHub Webhook autoupdate method; PM2 won't start it
unless you tell it to (pm2 start deploy/ecosystem.config.cjs --only animcss starts just the app).
Prefer systemd instead?
A unit file template:
[Unit]
Description=AnimCSS
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/opt/animcss
ExecStart=/usr/bin/node .output/server/index.mjs
EnvironmentFile=-/opt/animcss/.env
Environment=NODE_ENV=production
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.targetSave as /etc/systemd/system/animcss.service, fix User= and
WorkingDirectory=, then:
sudo systemctl daemon-reload
sudo systemctl enable --now animcss
journalctl -u animcss -fThe app only speaks plain HTTP on one port — anything that can proxy to
http://127.0.0.1:<port> works. A few common options:
Cloudflare Tunnel
No public inbound ports needed — cloudflared makes an outbound connection from your server to Cloudflare.
- Install
cloudflaredon the server (see Cloudflare's install docs for your distro). - In the Zero Trust dashboard →
Networks → Tunnels → Create a tunnel → Cloudflared → name it → copy
the
cloudflared service install <token>command it gives you and run it on the server. - Back in the dashboard, Public Hostname → Add a public hostname:
pick your subdomain/domain, Service Type
HTTP, URLlocalhost:<port>. - If your domain isn't already using Cloudflare's nameservers, it won't
appear in the domain dropdown — either point the domain's nameservers
at Cloudflare (unlocks the dropdown), or add a CNAME record yourself,
wherever that domain's DNS actually lives, pointing at
<tunnel-id>.cfargotunnel.com(shown on the tunnel's overview page).
Caddy
your-domain.com {
reverse_proxy 127.0.0.1:3004
}
Caddy handles HTTPS certificates automatically.
nginx
server {
listen 443 ssl;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}(Add your own TLS cert config/certbot block — omitted here since it's
identical to any other nginx site.)
git pull
npm install
npm run build
pm2 restart animcssIf you'd rather this happen automatically whenever you push a commit,
see AUTOUPDATE.md — a GitHub Webhook listener that runs
exactly these steps for you.
- Blank page / 404 on every route: usually means
.output/publicis missing or the build failed silently — checknpm run buildoutput for errors before it exits0. - Catalog pages say "not configured":
VITE_SUPABASE_URL/VITE_SUPABASE_ANON_KEYweren't set at build time, or the build wasn't re-run after setting them. - Port already in use: something else is already listening on that
port — change
PORTin.envand rebuild, or free up the port.