Skip to content

Container image

Andy Gayton edited this page Nov 11, 2024 · 7 revisions

You can use docker to serve an instance of xs like this:

docker run -e XS_START="xs serve ./store --expose 0.0.0.0:8080" -p 8080:8080 ghcr.io/cablehead/xs:latest

xs should now be available on localhost:8080

curl localhost:8080  # will pull the event stream

# the `xs` cli doubles as a HTTP client
xs cat :8080

# append to the stream
echo "foo" | xs append :8080 a-topic  # or echo "foo" | curl -d @- localhost:8080/a-topic

deploying on SidePro

You can deploy xs as an app on SidePro. Note SidePro apps are ephemeral, so this is only suitable for adhoc streams you want to make available on a public PoP temporarily.

Since this will be publicly accessible, we'll protect access to the PoP with SidePro's convenient basicAuth.

# generate a random password and put it on our clipboard
$ pwgen 15 1 | bp
$ bp
eichajauxeiGu3a

# encode for basicAuth
$ bp | htpasswd -ni xs | bp
$ bp
xs:$apr1$hnvIIgGG$wsQ5oFD/z14kU3e8K2NiK/

Create a folder: my-quick-xs in a convenient location, and then add a sidepro.yml to this folder. Replace the basicAuthHtpasswd with the one generated above.

name: my-quick-xs
configuration:
    environment:
        XS_START: "xs serve ./store --expose 0.0.0.0:8080"
    appchart: standard
    settings:
        basicAuth: "true"
        basicAuthHtpasswd: "xs:$apr1$hnvIIgGG$wsQ5oFD/z14kU3e8K2NiK/"
origin:
    container: ghcr.io/cablehead/xs@sha256:c40adeb3db8dd4e8569f474258ce6012b94d9d513fdd025c5719b041cbb1db48

πŸ₯

$ sidepro push
Namespace: andy-beta
> Using manifest file: sidepro.yml
Check if application exists on the server... failed
Application Deployment Manifest:

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ Name            β”‚ my-quick-xs                                                                                  β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Namespace       β”‚ andy-beta                                                                                    β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ App Chart       β”‚ standard                                                                                     β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Environment     β”‚ - XS_START: xs serve ./store --expose 0.0.0.0:8080                                           β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Settings        β”‚ - basicAuth: true                                                                            β”‚
  β”‚                 β”‚ - basicAuthHtpasswd: xs:$apr1$hnvIIgGG$wsQ5oFD/z14kU3e8K2NiK/                                β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Container Image β”‚ ghcr.io/cablehead/xs@sha256:c40adeb3db8dd4e8569f474258ce6012b94d9d513fdd025c5719b041cbb1db48 β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

? Ready to deploy? (will deploy automatically in 5 seconds...) yes
Creating application... done
Validating application chart values... done
Deploying application... done

Application my-quick-xs successfully deployed!

Routes:
- https://my-quick-xs-andy-beta.platform.beta.sidepro.app
? Open the route my-quick-xs-andy-beta.platform.beta.sidepro.app in the browser? no
? Save changes to the manifest file to sidepro.yml? no

You now have your own temporary, personal event stream you can access from anywhere!

Note again we use our randomly generated password:

$ curl https://xs:eichajauxeiGu3a@my-quick-xs-andy-beta.platform.beta.sidepro.app
{"topic":"xs.start","id":"03ctgep5ikz4jv1jkrziv8pno","hash":null,"meta":{"expose":"0.0.0.0:8080"},"ttl":null}

You'll want to use the xs Nushell module wrapper though:

$ use xs.nu *

# point to our remote store
$ $env.XSPWD = "https://xs:eichajauxeiGu3a@my-quick-xs-andy-beta.platform.beta.sidepro.app"

$ "what will we stream, today?" | .append lets-go
───────┬─────────────────────────────────────────────────────
 topic β”‚ lets-go
 id    β”‚ 03ctggxtybig2h89w79h44vd1
 hash  β”‚ sha256-GBKOv7PSvq2ushqMV5bud/3Z41CmE6aEliWuBpfEgB0=
 meta  β”‚
 ttl   β”‚ forever
───────┴─────────────────────────────────────────────────────

$ .cat
─#─┬──topic───┬────────────id─────────────┬────────────────────────hash─────────────────────────┬──────────meta───────────┬───ttl───
 0 β”‚ xs.start β”‚ 03ctgep5ikz4jv1jkrziv8pno β”‚                                                     β”‚ ────────┬────────────── β”‚
   β”‚          β”‚                           β”‚                                                     β”‚  expose β”‚ 0.0.0.0:8080  β”‚
   β”‚          β”‚                           β”‚                                                     β”‚ ────────┴────────────── β”‚
 1 β”‚ lets-go  β”‚ 03ctggxtybig2h89w79h44vd1 β”‚ sha256-GBKOv7PSvq2ushqMV5bud/3Z41CmE6aEliWuBpfEgB0= β”‚                         β”‚ forever
───┴──────────┴───────────────────────────┴─────────────────────────────────────────────────────┴─────────────────────────┴─────────

$ .cat | last
───────┬─────────────────────────────────────────────────────
 topic β”‚ lets-go
 id    β”‚ 03ctggxtybig2h89w79h44vd1
 hash  β”‚ sha256-GBKOv7PSvq2ushqMV5bud/3Z41CmE6aEliWuBpfEgB0=
 meta  β”‚
 ttl   β”‚ forever
───────┴─────────────────────────────────────────────────────

$ .cat | last | .cas
what will we stream, today?
Clone this wiki locally