Skip to the article
3dCMS Knowledge Base
Contact Open the editor
Publishing & Hosting

Host your site on your own domain

Put a 3dCMS site on your own domain, by hand with the zip or kept fresh automatically: your server pulls each publish, or we push it to Netlify, GitHub Pages or S3.

Open in the interactive manual →

The interactive version has full-text search, a table of contents, and light/dark themes.


Want a 3dCMS scene as the homepage of your domain, with your address in the bar and your own host carrying the visitors? There are three ways: by hand, pulled by your server, or pushed by us to a static host.

1. By hand: the zip

Publish, open the share dialog, hit Export site (.zip), and upload the unzipped folder to your web host. That's the whole job; see download your site for what's inside and the limits. The catch: every edit means export, download and upload again.

2. Kept fresh: sync

In the share dialog (right after a publish, or any time from File ▸ Share link…), open Host this site on your own domain (for developers). It has three steps.

  1. Create token. A token that can download this one site and nothing else: not your other sites, not your account, not your editor. It's shown once; copy it then (we keep only a fingerprint of it, so we can't show it again). Replace token makes a new one and kills the old; Revoke kills it outright.
  2. Download the script (3dcms-sync.sh) and put it on your server, outside the public folder. Save the token in a file only you can read (chmod 600 ~/.3dcms-token) so it never lands in your shell history, then run the script with that file and the folder your site lives in:
    THREEDCMS_SYNC_TOKEN_FILE=~/.3dcms-token ./3dcms-sync.sh /var/www/widgets.org
    (Passing the token itself as THREEDCMS_SYNC_TOKEN=… still works.) It asks 3dCMS whether the site changed, and only if it did, downloads the export and moves each file into place. It needs bash, curl and unzip, nothing else.
  3. Choose how it runs. Either from cron every five minutes (an unchanged site costs one tiny request), or from a webhook: paste the https address of a receiver on your server and every publish calls it within seconds. Two ready-made receivers are in the panel, one in PHP for ordinary shared hosting and one in Node. Send test ping checks it, and the panel shows when the last ping went and whether it arrived.
It never touches files it didn't put there The script writes a list of every file it placed (.3dcms-manifest). On the next run it deletes only files from that list that the new export dropped. Your other pages, your .htaccess, anything else in the folder, is left alone. If a file was already there before the first sync and the export has one with the same name (an old index.html, say), the old one is copied to .3dcms-backup/ first.

3. Pushed for you: Netlify, GitHub Pages or Amazon S3

No server of your own? Step 4 of the same panel, Push to a host, makes every publish upload the site to one place you pick. We ask for a key that can reach that one place and nothing else, and we refuse broader ones: if a key ever leaked from us, it could touch that folder only.

  • GitHub Pages. Mint a fine-grained token (GitHub ▸ Settings ▸ Developer settings ▸ Fine-grained tokens) with Only select repositories set to just your site's repo and one permission, Contents: Read and write. Classic tokens (ghp_…) are refused, because they open every repository you can reach. Each publish is one commit to the branch you name (gh-pages by default, created if missing), optionally inside a folder such as docs. Then point GitHub Pages at that branch.
  • Netlify, build hook (best). A build hook can start a build of one Netlify site and do nothing else. Use it when that site builds from a repo whose build runs the sync script above.
  • Netlify, direct deploy. Each publish uploads the whole site as one deploy, and a Netlify deploy replaces everything on that Netlify site, so use a site that holds only this. Netlify tokens can't be limited to one site; keep the site in a Netlify team of its own and set the token to expire.
  • Amazon S3. Create an IAM user whose only policy is the one the panel shows for your bucket and folder: s3:PutObject and s3:DeleteObject on arn:aws:s3:::your-bucket/your-folder/*, nothing more. Test connection fails a key that can list your buckets, because that key is broader than the policy. Bucket names with dots aren't supported.

Test connection makes a harmless check (for S3 it writes one small test file and removes it). Push now sends every file again, handy if something was deleted at the host by hand. Pushes wait their turn behind any export that is building and run one at a time, so a burst of publishes across many sites queues rather than piling up. The panel shows when the last push ran and whether it worked; a push that fails never stops the publish. Remove forgets the key and never deletes anything at the host. The key is stored encrypted, and after you save it the panel only ever shows its last few characters.

The same rule as the script holds: we keep a list of every file we placed, and a push deletes only files from that list that the new site dropped (a Netlify direct deploy is the one exception, by Netlify's design, which is why it wants a site of its own).

Your domain: link previews and search

Step 5 of the panel, Your domain, is the https address where the copy lives, such as https://www.widgets.org/tour/. With it set, every export and every push carries:

  • a canonical link and og:url naming that address, so search engines and link previews credit your domain, not 3dcms.info;
  • the site's share card (the picture taken when you publish) as share-card.jpg in the folder, with og:image pointing at it on your domain, so a link pasted into a chat shows the picture;
  • a sitemap.xml listing the address, and, when the copy sits at the root of the domain, a robots.txt that names it. Crawlers only read robots.txt at the root, so a copy in a subfolder skips it: add Sitemap: https://www.widgets.org/tour/sitemap.xml to your own root robots.txt instead.

The address must be plain https on a public domain name: no login, no ? or # part, no port, no IP address. A missing trailing slash is added. Leave it empty and the export is exactly what it was before. If the copy moves, change the address and export or publish again. A site published before its first share card was taken has no card to include; publish once more.

Good to know

  • We never ask for your server login. No FTP or SFTP password, ever: your server pulls from us with a token that can only read this one site, or we push with a key that can only write one folder.
  • The webhook is signed. Each call carries an X-3dCMS-Signature header, an HMAC-SHA256 of the body keyed on the sha256 of your token; both receivers check it and ignore anything else.
  • The webhook address must be public, on port 80, 443, 8080 or 8443. Addresses on a private network are refused.
  • If your server is down when you publish, the publish still goes through. We try once more after 30 seconds and then record the failure in the panel; the next publish (or the next cron run) catches up.
  • Everything in the static export's limitations applies to the synced copy too: no reactions or view stats, and search engines see the home page's text only, not every page.
  • Sync needs static export, so it follows the same plan. Revoking the token and clearing the webhook always work, whatever your plan.
Spotted something off, or want a topic covered? Tell us, a person reads every message.