Deploy it
Unzip the export first, so the commands below run from inside the folder that contains index.html.
rsync -avz --delete ./ user@your-server:/var/www/your-site/
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
sudo systemctl reload nginxThe /etc/nginx/sites-available/your-site you need
Serve the export with extensionless URLs, gzip, and a real 404.
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/your-site;
index index.html;
location / {
try_files $uri $uri.html $uri/ /404.html;
}
error_page 404 /404.html;
gzip on;
gzip_types text/css application/javascript image/svg+xml;
}Custom domain
An A record at the server's IP. Certificates come from certbot, renewed by a systemd timer.
What it costs
None, but a small instance costs a few currency units a month and will serve a static marketing site without noticing.
Before you move the domain
- 1. Deploy to the host's own subdomain and open every page from the nav.
- 2. Visit a URL that does not exist and confirm you get a real 404, not a 200.
- 3. Submit any form on the site — exported forms post nowhere until you rewire them.
- 4. Only then move DNS, and keep the Framer plan active for one more cycle as a rollback.
Questions
›Can I host a Framer site on your own VPS (nginx) for free?
None, but a small instance costs a few currency units a month and will serve a static marketing site without noticing.
›Do I need a build step to deploy a Framer export to your own VPS (nginx)?
No. A Framer export is already built output, so the build command stays empty. your own VPS (nginx) serves the files as they are.
›How do I point my own domain at your own VPS (nginx)?
An A record at the server's IP. Certificates come from certbot, renewed by a systemd timer.
›What usually goes wrong when deploying a Framer export to your own VPS (nginx)?
try_files $uri $uri/ /index.html is the SPA recipe copied from every tutorial and it is wrong here — it swallows genuine 404s and serves the homepage instead, which Google reads as soft-404 across the whole site. Use $uri.html and a real error page.