shinyctl

Install

shinyctl is one binary for Linux and macOS, on amd64 or arm64. Installing it needs no root, and it runs your apps as your own user.

Requirements

  • Linux or macOS, on amd64 or arm64.
  • R with the shiny package, and Rscript on your PATH.
  • systemd, to start at boot on Linux (optional).
  • Go 1.26.10 or newer, only to build it yourself.

The one-line installer

curl -fsSL https://raw.githubusercontent.com/spriyansh/shinyctl/main/install.sh | sh

install.sh is a short shell script you can read first. It:

  • picks the build for your system and downloads it from the latest release;
  • checks it against the release's checksums.txt, and stops if it doesn't match;
  • copies the single shinyctl binary into ~/.local/bin, replacing any older one in one step;
  • says if that folder is not on your PATH yet, or if Rscript is missing.

Run it again to upgrade. Three settings change what it does:

SettingWhat it does
SHINYCTL_VERSIONThe release to install, such as v0.1.0. By default, the latest.
SHINYCTL_INSTALL_DIRWhere the binary goes. By default, ~/.local/bin.
SHINYCTL_RELEASESA mirror of the releases page to download from.
curl -fsSL https://raw.githubusercontent.com/spriyansh/shinyctl/main/install.sh | SHINYCTL_VERSION=v0.1.0 sh

If ~/.local/bin is not on your PATH

On Debian, Ubuntu and Raspberry Pi OS it is added when you next log in. On macOS, add it to your shell's profile and open a new terminal:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zprofile

By hand

Download the archive for your system and checksums.txt from the releases page, check the download, unpack it, and put shinyctl on your PATH. For Linux on arm64 (a Raspberry Pi), version 0.1.0:

curl -LO https://github.com/spriyansh/shinyctl/releases/download/v0.1.0/shinyctl_0.1.0_linux_arm64.tar.gz
curl -LO https://github.com/spriyansh/shinyctl/releases/download/v0.1.0/checksums.txt
sha256sum --ignore-missing -c checksums.txt     # macOS: shasum -a 256 --ignore-missing -c checksums.txt
tar -xzf shinyctl_0.1.0_linux_arm64.tar.gz
mkdir -p ~/.local/bin && cp shinyctl_0.1.0_linux_arm64/shinyctl ~/.local/bin/

The other archives are linux_amd64, darwin_arm64 (Apple silicon) and darwin_amd64. Each unpacks into a folder of its own with shinyctl, the README, the licence and notices, and the example app in examples/hello.

A file downloaded with a browser on macOS is quarantined. curl doesn't do that, and xattr -d com.apple.quarantine shinyctl lifts it.

With Go

go install github.com/spriyansh/shinyctl@v0.1.0

Or, from a clone of the repository, make install.

Check it

shinyctl version

It prints v0.1.0 for a release (and for go install ...@v0.1.0), and dev (abc1234) for a build from a checkout.

Your first app

Write a manifest next to your app, set its entrypoint-file and port, and apply it. The first apply starts shinyctl-api in the background.

shinyctl init                     # writes ./shinyctl.yaml
$EDITOR shinyctl.yaml             # set entrypoint-file and port
shinyctl apply -f shinyctl.yaml   # starts shinyctl-api, then the app
shinyctl status

A few seconds later both copies are ready: one takes visitors, the other is the warm spare.

NAME   COPY  ROLE    PORT  PID    STATUS  READY  MEM  SESSIONS  CRASHES  STARTED
hello  1     active  8765  77713  alive   ready  97M  0         -        2026-10-29T22:05:11+01:00
hello  2     warm    8765  77714  alive   ready  97M  0         -        2026-10-29T22:05:11+01:00

Memory: 195M in 2 R processes (1 warm), plus 37M for the load balancer.

Open the port from your manifest, for example http://127.0.0.1:8080. Every field of the manifest is in the reference.

Try the example

The example app is in the archive and in the repository, in examples/hello. From the unpacked archive folder:

shinyctl apply -f examples/hello/shinyctl.yaml

Open http://127.0.0.1:8765 and click Crash this app. The page moves to the other copy within about a second: it reloads by itself and shows that copy's process ID. The crashed copy restarts a few seconds later and becomes the spare, so the roles in status have swapped. To see what both copies printed, including the crash:

shinyctl logs -f examples/hello/shinyctl.yaml

Remove the app with shinyctl delete -f examples/hello/shinyctl.yaml. If something else already uses port 8765, apply says so and status shows port-in-use: change port in the example's manifest and apply again.