OXYGENHUB

Serve the self-signed certificate at /.well-known/oxyhub-ca.pem; connecting notes on the trust page 8f3d2ccfe6fc

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-27 17:35 UTC
Signature
✔ signed by Andy McCall
Hash
8f3d2ccfe6fcd48c4c910096c94213b4036e09c5e2375316795f9c1607939733
Depends on
93be9ce4653e d23464c0ac60
Depended on by
40a43921ef42 4f40eed0588f 965b950f9b96 076c7a7c86b1 d1727c573f30 d91780ee20de e9bfea8e26db
In bookmarks
api-unknown-fields cancel-landed-runs clear-waiting close-proposal-140 diffusion-pin-bookmark draft-ready image-check job-waits main oh-comment-body-file proposal-list-fast run-one-job wiki-says-so
In tags
v0.1.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.5.0 v0.5.1 v0.5.2 v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
Edits
6 atoms, 0 tree operations, 5 files

Browse the tree at this change

modified crates/hub/src/web/home.rs +17 −0
…
60 unchanged lines
61 61
    )
62 62
        .into_response()
63 63
}
64 +
65 +
/// The hub's TLS certificate (hub spec §15.5), for clients of a
66 +
/// developer edition with a self-signed certificate: save it and point
67 +
/// `oxy` at it with `OXY_CA` or `oxy config remote.<name>.ca`.
68 +
pub async fn hub_ca(State(app): State<Shared>) -> Response {
69 +
    if !app.config.tls.self_signed {
70 +
        return (axum::http::StatusCode::NOT_FOUND, "this hub does not use a self-signed certificate").into_response();
71 +
    }
72 +
    match tokio::fs::read(app.config.tls_cert()).await {
73 +
        Ok(pem) => (
74 +
            [(header::CONTENT_TYPE, "application/x-pem-file"), (header::CONTENT_DISPOSITION, "attachment; filename=\"oxyhub-ca.pem\"")],
75 +
            pem,
76 +
        )
77 +
            .into_response(),
78 +
        Err(_) => (axum::http::StatusCode::NOT_FOUND, "no certificate").into_response(),
79 +
    }
80 +
}
modified crates/hub/src/web/mod.rs +1 −0
…
26 unchanged lines
27 27
        .route("/explore", get(home::explore))
28 28
        .route("/health", get(home::health))
29 29
        .route("/.well-known/oxyhub-key", get(home::hub_key))
30 +
        .route("/.well-known/oxyhub-ca.pem", get(home::hub_ca))
30 31
        .route("/style.css", get(statics::style))
31 32
        .route("/favicon.svg", get(statics::favicon))
32 33
        .route("/favicon.ico", get(statics::favicon))
…
188 unchanged lines
modified crates/hub/tests/browse.rs +1 −0
…
179 unchanged lines
180 180
    assert_eq!(status, StatusCode::OK);
181 181
    assert!(!key.is_empty());
182 182
    assert!(get(&h.app, "/health").await.1.contains("\"ok\":true"));
183 +
    assert_eq!(get(&h.app, "/.well-known/oxyhub-ca.pem").await.0, StatusCode::NOT_FOUND, "no self-signed certificate configured");
183 184
    assert_eq!(get(&h.app, "/style.css").await.0, StatusCode::OK);
184 185
    assert_eq!(get(&h.app, "/static/fonts/Barlow-400.woff2").await.0, StatusCode::OK);
185 186
    assert_eq!(get(&h.app, "/andy/demo/oxy/v1/nothing").await.0, StatusCode::NOT_FOUND);
…
36 unchanged lines
modified docs/deploy.md +1 −1
…
21 unchanged lines
22 22
3. **Build**: `cd ~/src/oxygenhub && cargo build --release`.
23 23
4. **System user and data**: `sudo useradd --system --home /home/oxygenhub --create-home oxygenhub`, `sudo install -o oxygenhub -g oxygenhub -m 0755 target/release/oxygenhub /usr/local/bin/`, `sudo -u oxygenhub oxygenhub init --data /home/oxygenhub/data --admin andymccall` (prints the first admin's one-time password).
24 24
5. **Service**: `/etc/systemd/system/oxygenhub.service` running `oxygenhub serve --data /home/oxygenhub/data` as `oxygenhub`, `Restart=on-failure`, `ProtectSystem=strict`, `ReadWritePaths=/home/oxygenhub/data`, `NoNewPrivileges=yes`; `sudo systemctl enable --now oxygenhub`.
25 -
6. **TLS**: the developer edition generates a self-signed certificate at `init`. Download the CA from `https://earth.andymccall.xyz:7343/trust/ca.pem` and point clients at it with `oxy config remote.<name>.ca <file>` or `OXY_CA`.
25 +
6. **TLS**: the developer edition generates a self-signed certificate at `init`. Download the certificate from `https://earth.andymccall.xyz:7343/.well-known/oxyhub-ca.pem` (or over plain HTTP on port 7300) and point clients at it with `oxy config remote.<name>.ca <file>` or `OXY_CA`.
26 26
7. **First repositories**: on the development machine, `oxy remote add earth https://earth.andymccall.xyz:7343/andymccall/oxygen` in each of `oxygen`, `oxygen-vscode`, `oxygenhub`, then `oxy push earth`.
27 27
8. **Updates**: rsync, build, `sudo install`, `sudo systemctl restart oxygenhub`. A `make deploy` target in the hub wraps steps 2, 3 and 8.
modified templates/trust.html +4 −0
…
31 unchanged lines
32 32
  {% if !t.verification.invalid.is_empty() %}<ul class="plain">{% for (h, why) in t.verification.invalid %}<li><a class="chip" href="{{ repo.url }}/change/{{ h }}">{{ h|short }}</a> {{ why }}</li>{% endfor %}</ul>{% endif %}
33 33
</section>
34 34
<section class="panel">
35 +
  <h2>Connecting</h2>
36 +
  <p class="small">Clone with <code>oxy clone {{ repo.clone_url }}</code>. If this hub uses a self-signed certificate, save <a href="/.well-known/oxyhub-ca.pem">its certificate</a> and point <code>oxy</code> at it with <code>oxy config remote.&lt;name&gt;.ca &lt;file&gt;</code> or <code>OXY_CA</code>.</p>
37 +
</section>
38 +
<section class="panel">
35 39
  <h2>Hub delegate key</h2>
36 40
  <p class="small">Changes the hub makes for you in the browser (later milestones) are signed with this key on your behalf, once you have run <code>oxy identity delegate add hub.identity</code> with the file from <a href="/.well-known/oxyhub-key">/.well-known/oxyhub-key</a>.</p>
37 41
  <p><code class="full">{{ t.hub_key }}</code></p>
…
3 unchanged lines