krz/orgo

Lightning fast org-mode static site generator.

clone: git clone https://gitbay.org/krz/orgo.git

v0.21.0: docs/guide/10-deploying.org · raw

  1#+TITLE: Deploying
  2#+DESCRIPTION: Producing a production build, and putting it somewhere.
  3#+LEDE: The output is a directory of files. Everything after that is your host's problem.
  4
  5* The production build
  6
  7#+BEGIN_SRC sh
  8orgo build content -o _site --strict
  9#+END_SRC
 10
 11Two differences from the build you run while writing:
 12
 13- =--strict= turns broken internal links and parse diagnostics into a non-zero exit, so a
 14  bad build fails rather than shipping.
 15- No =--drafts=, so pages marked =#+DRAFT:= stay out.
 16
 17Everything in =_site= is the site: HTML, the generated =syntax.css=, =theme.css= if the
 18config names a [[file:02-configuration.org][theme]], and every asset copied from the source. There is no runtime, no server requirement and no build step
 19downstream.
 20
 21* Set base_url for production
 22
 23#+BEGIN_SRC toml
 24[site]
 25base_url = "https://example.com"
 26#+END_SRC
 27
 28Relative URLs work anywhere, which is why the default is empty — but two things need
 29absolute ones: *feeds*, because a feed is read away from the site that served it, and
 30*canonical links*. Without a base URL the =absolute= filter is an error rather than a
 31quietly relative link, so a feed template will tell you.
 32
 33No trailing slash.
 34
 35* One thing to exclude
 36
 37The build writes =.orgo-cache.json= into the output directory. It is a dot-file, so
 38most static hosts ignore it, but it is not part of the site — exclude it if your host
 39uploads everything:
 40
 41#+BEGIN_SRC sh
 42rsync -a --delete --exclude '.orgo-cache.json' _site/ user@host:/var/www/site/
 43#+END_SRC
 44
 45Keeping the cache *between* deploys, where the CI runner can see it, is what makes CI
 46builds incremental. Keeping it on the *server* achieves nothing.
 47
 48* Continuous integration
 49
 50#+BEGIN_SRC yaml
 51name: build
 52on: [push]
 53jobs:
 54  build:
 55    runs-on: ubuntu-latest
 56    steps:
 57      - uses: actions/checkout@v4
 58      - uses: dtolnay/rust-toolchain@stable
 59      - run: cargo install --path .
 60      - run: orgo build content -o _site --strict
 61      - uses: actions/upload-artifact@v4
 62        with:
 63          name: site
 64          path: _site
 65#+END_SRC
 66
 67=--strict= is the point of running this in CI at all: it turns a broken link into a
 68failed build.
 69
 70** Caching between runs
 71
 72Cache =_site/.orgo-cache.json= *and* =_site= together, or not at all. The manifest
 73describes files it expects to find; a cache without its outputs simply triggers a full
 74rebuild, which is correct but pointless.
 75
 76Given how fast a full build is — a 179-page site in well under a second — caching CI
 77builds is rarely worth the configuration.
 78
 79* Static hosts
 80
 81Nothing here is orgo-specific; a built site is ordinary static files.
 82
 83- *Netlify, Vercel, Cloudflare Pages*: publish directory =_site=, build command
 84  =cargo install --path . && orgo build content -o _site --strict=.
 85- *GitHub Pages*: upload =_site= as the Pages artifact.
 86- *Any web server*: copy =_site= to the document root.
 87
 88** URLs end in .html
 89
 90orgo writes =blog/post.html= and links to it that way, so the site works with no
 91server configuration at all — including opening it from a filesystem path.
 92
 93If you prefer extensionless URLs, that is a server-side rewrite, and you should also set
 94=base_url= and check that your rewrite rules do not break the relative links in the pages.
 95
 96* Checking a build before shipping
 97
 98#+BEGIN_SRC sh
 99orgo build content -o _site --strict
100orgo serve content -o _site
101#+END_SRC
102
103Serving the production build locally is the last check worth doing: it catches a missing
104asset or a broken relative link in the browser, where you would notice.
105
106* What a clean build looks like
107
108#+BEGIN_EXAMPLE
109built 182 page(s) (182 rendered, 0 cached), copied 3 asset(s) from content -> _site (0 unresolved link(s), 0 diagnostic(s))
110#+END_EXAMPLE
111
112Both zeros matter. Unresolved links are internal links pointing at nothing; diagnostics
113are malformed org that degraded rather than failing. With =--strict= neither can reach
114this line, because either would have failed the build.
115
116* Do not publish the cache
117
118=<output>/.orgo-cache.json= is a build artefact that happens to live in the output
119directory, because it describes exactly that directory. Nothing breaks if it is served —
120it holds hashes and paths, not secrets — but it is not part of your site, so leave it
121behind:
122
123#+BEGIN_SRC sh
124rsync -r --delete-before --exclude '.orgo-cache.json' _site/ server:/var/www/example.com/
125#+END_SRC
126
127Anything that uploads a directory wholesale needs the same exclusion. A deploy that
128*deletes* it on the far side is worse than one that copies it: the next build then has no
129cache to reuse and re-renders everything.
130
131* Telling a search engine where things are
132
133A build with =site.base_url= set writes =sitemap.xml= at the site root, listing every
134page. Point a =robots.txt= at it if you want one:
135
136#+BEGIN_EXAMPLE
137Sitemap: https://example.com/sitemap.xml
138#+END_EXAMPLE
139
140=robots.txt= is an ordinary file — put it beside your org files, or in a directory named
141by =[build] assets=, and it is copied through.
142
143* After an upgrade
144
145The first build on a new version is worth running with =--no-cache=, so you compare the
146new output to the old rather than to a cache written by both. What a version number
147promises — and what it does not — is in [[file:11-versioning.org][Versioning and
148upgrades]].