config

package
v0.10.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultDockerSocket = "/var/run/docker.sock"
	DefaultPythonImage  = "ghcr.io/astral-sh/uv:python3.12-bookworm-slim"
	DefaultRImage       = "rocker/r-base"
	DefaultNetworkMode  = "bridge"
)

Docker runtime defaults, shared between the control-plane config loader and the standalone worker command so both agree on the same baseline images, socket, and network mode without duplicating the literals.

Variables

This section is empty.

Functions

func ValidateWorkerSettings added in v0.9.2

func ValidateWorkerSettings(w WorkerSettings, clustered bool, effectiveMemMB, hostBudgetMB int) error

func WorkerBudgetWarning added in v0.10.1

func WorkerBudgetWarning(w WorkerSettings, effectiveMemMB, hostBudgetMB, minAvailableMB int) string

WorkerBudgetWarning returns a human-readable warning when elastic isolation (grouped/per_session) is configured with NO memory guard active: the static worst-case check is inert (it needs both host_budget_mb and a per-worker memory limit) and the runtime available-memory floor is off. Because the floor is on by default, this state is only reachable when the operator explicitly disabled it (min_available_memory_mb: 0) without arming the static guard - the warning reminds them the kernel OOM killer is then the only backstop, and it takes out a live worker with every session on it. Empty when guarded or when isolation is multiplex.

Types

type AuthConfig

type AuthConfig struct {
	Secret string `yaml:"secret"`
	// OAuthDefaultRole is the role assigned to users created via just-in-time
	// provisioning during OAuth/OIDC sign-in (i.e. first-time login). Allowed
	// values: "viewer" (default), "developer", "operator". "admin" is
	// intentionally not permitted -- admin must be granted explicitly, never
	// auto-provisioned from an external IdP.
	OAuthDefaultRole string `yaml:"oauth_default_role"`

	// GroupRoleMappings maps IdP groups to global roles. Applied by both OIDC and
	// forward-auth. Highest-rank match wins. admin_groups merges in as role=admin.
	GroupRoleMappings []GroupRoleMapping `yaml:"group_role_mappings"`

	// DeployToken is a pre-shared bearer token sourced from
	// SHINYHUB_DEPLOY_TOKEN. When non-empty it authenticates as the synthetic
	// system user `__deploy__` with role DeployTokenRole. Not persisted; rotation
	// is "change the env var, restart the service."
	DeployToken string `yaml:"-"`

	// DeployTokenRole is the role granted to the synthetic system user when the
	// env-token is active. Sourced from SHINYHUB_DEPLOY_TOKEN_ROLE; default
	// "developer". Must be one of viewer, developer, operator, admin.
	DeployTokenRole string `yaml:"-"`

	// DeployTokenApps, when non-empty, restricts the deploy token to the listed
	// app slugs across every app surface (view, manage, deploy, create, list),
	// regardless of DeployTokenRole. Sourced from SHINYHUB_DEPLOY_TOKEN_APPS
	// (comma-separated) or auth.deploy_token_apps. Slugs may name apps that do
	// not exist yet (the token is allowed to create them).
	DeployTokenApps []string `yaml:"deploy_token_apps"`

	// OperatorAuditAccess lets operator-role users read the audit log
	// (GET /api/audit and the dashboard pages behind it). Default false: audit
	// stays admin-only unless the operator opts in. Env:
	// SHINYHUB_OPERATOR_AUDIT_ACCESS.
	OperatorAuditAccess bool `yaml:"operator_audit_access"`

	ForwardAuth ForwardAuthConfig `yaml:"forward_auth"`

	// IdentityHeaders globally enables forwarding the authenticated user's
	// identity (X-Shinyhub-* headers + signed identity token) to app
	// processes. nil/absent = enabled (the default). Setting false is a hard
	// operator kill switch: per-app manifest opt-ins cannot override it.
	// Per-app `[app] identity_headers = false` opts a single app out.
	IdentityHeaders *bool `yaml:"identity_headers"`

	// LocalLogin enables the built-in username/password login: the sign-in form
	// and the /api/auth/login and /api/auth/session endpoints. nil/absent =
	// enabled (the default). Set false for an SSO-only deployment: the login
	// screen hides the password form AND the password endpoints reject with 403,
	// so a user cannot bypass the IdP by POSTing credentials. Startup fails when
	// this is false and no SSO login path is configured (see HasSSOLoginPath), to
	// avoid locking out every user. Note: this also disables the break-glass
	// admin's password login, so keep at least one SSO admin path.
	LocalLogin *bool `yaml:"local_login"`
}

func (*AuthConfig) IdentityHeadersEnabled added in v0.8.6

func (a *AuthConfig) IdentityHeadersEnabled() bool

IdentityHeadersEnabled reports whether identity headers (X-Shinyhub-* and the signed identity token) are globally permitted to be forwarded to app processes. Returns true when the field is absent (the default).

func (*AuthConfig) LocalLoginEnabled added in v0.9.5

func (a *AuthConfig) LocalLoginEnabled() bool

LocalLoginEnabled reports whether the built-in username/password login is permitted. Returns true when the field is absent (the default).

type AutoscaleConfig added in v0.7.0

type AutoscaleConfig struct {
	// Enabled is the global kill switch. When false the controller never runs,
	// regardless of any per-app opt-in. Default false.
	Enabled bool
	// ScanInterval is how often the controller evaluates opted-in apps.
	ScanInterval time.Duration
	// Cooldown is the minimum time between successive scale actions on the same
	// app, damping oscillation.
	Cooldown time.Duration
	// DefaultTarget is the target average active sessions per replica as a
	// fraction (0,1] of the per-replica session cap, used when an app's own
	// autoscale_target is 0.
	DefaultTarget float64
}

AutoscaleConfig holds the global settings for the replica autoscale controller. Autoscaling is opt-in per app; with no app opted in these values have no effect.

type BrandingConfig added in v0.5.4

type BrandingConfig struct {
	SiteTitle   string `yaml:"site_title"`
	AssetsDir   string `yaml:"assets_dir"`
	Favicon     string `yaml:"favicon"`
	LandingPage string `yaml:"landing_page"`
	// RootBehavior controls who sees the landing page at GET /:
	//   "" / "auto" - anonymous visitors see the landing page; a signed-in
	//                 ShinyHub user is sent to the SPA home (Overview/Launchpad).
	//   "landing"   - GET / always serves the landing page, even for signed-in
	//                 users (a pure portal). The SPA home stays reachable at /home.
	// Only meaningful when LandingPage is set.
	RootBehavior string       `yaml:"root_behavior"`
	Theme        ThemeConfig  `yaml:"theme"`
	FooterLinks  []FooterLink `yaml:"footer_links"`
	// contains filtered or unexported fields
}

BrandingConfig customises the ShinyHub front door. Every field is optional; the zero value behaves as if no branding is configured.

func (BrandingConfig) EffectiveRootBehavior added in v0.9.0

func (b BrandingConfig) EffectiveRootBehavior() string

EffectiveRootBehavior normalizes RootBehavior to one of the two supported modes, defaulting the empty value to "auto".

func (BrandingConfig) IsActive added in v0.5.4

func (b BrandingConfig) IsActive() bool

IsActive reports whether any branding field is set. When false the server keeps the existing zero-branding serve path untouched.

func (BrandingConfig) LandingFile added in v0.5.4

func (b BrandingConfig) LandingFile() string

LandingFile returns the resolved absolute path of the operator landing page, or "" when none is configured.

func (BrandingConfig) ResolvedAssets added in v0.5.4

func (b BrandingConfig) ResolvedAssets() map[string]string

ResolvedAssets returns the basename->absolute-path allow-list used by the /branding/ asset handler. The returned map is a copy; mutations do not affect the config.

type Config

type Config struct {
	Database         DatabaseConfig
	Server           ServerConfig
	Auth             AuthConfig
	Storage          StorageConfig
	Lifecycle        LifecycleConfig
	Runtime          RuntimeConfig
	Scheduler        SchedulerConfig
	Defaults         DefaultsConfig
	Tracing          TracingConfig
	Metrics          MetricsConfig
	Maintenance      MaintenanceConfig
	Branding         BrandingConfig
	Worker           WorkerConfig
	OAuth            OAuthConfig  `yaml:"-"`
	TrustedProxyNets []*net.IPNet `yaml:"-"` // parsed from Server.TrustedProxies
}

Config holds all parsed, ready-to-use configuration for ShinyHub.

func Load

func Load(path string) (*Config, error)

Load parses and validates the full server configuration from path (or environment variables when path is empty or the file does not exist). auth.secret is required and must not be the placeholder value or shorter than 32 characters. Use LoadForMaintenance for commands that do not perform cryptography (backup, restore).

func LoadForMaintenance added in v0.8.8

func LoadForMaintenance(path string) (*Config, error)

LoadForMaintenance loads the config the same way Load does but skips the auth.secret validation. Backup and restore operate only on files and the SQLite database; they perform no cryptography and therefore do not need a valid secret. Callers must not use cfg.Auth.Secret for any purpose.

func (*Config) ActiveSSOLoginPaths added in v0.9.5

func (c *Config) ActiveSSOLoginPaths() []string

ActiveSSOLoginPaths returns the names of the SSO login paths that are configured well enough to attempt a login. GitHub/Google require BOTH a client_id and a client_secret (a missing secret fails at the token exchange, so a client_id alone is not a login path); OIDC requires an issuer_url (its discovery is verified at startup); forward-auth counts when enabled. The order is stable so it can be logged. See HasSSOLoginPath for the important caveat that "configured" is not "verified working".

func (*Config) HasSSOLoginPath added in v0.9.5

func (c *Config) HasSSOLoginPath() bool

HasSSOLoginPath reports whether at least one non-password browser login path is configured (see ActiveSSOLoginPaths). This is the SSO-only lockout guard's check. IMPORTANT: "configured" is not "verified working" - forward-auth still depends on trusted_proxies including the edge proxy AND the proxy sending the user header, and OAuth requires a reachable callback URL. Only OIDC is verified at startup (discovery). Operators must test SSO end to end before disabling local login; the boot log names the paths that were counted.

func (*Config) HostBudgetMB added in v0.9.2

func (c *Config) HostBudgetMB() int

HostBudgetMB returns the total RAM budget (in MiB) for app worker processes. 0 means the host-capacity guard is disabled.

func (*Config) MinAvailableMemoryMB added in v0.10.1

func (c *Config) MinAvailableMemoryMB() int

MinAvailableMemoryMB returns the runtime host-memory floor (in MiB) below which no new elastic worker is allocated. Unset applies the safe default (an elastic OOM kills a worker plus every session on it); an explicit 0 or a negative value disables the floor. 0 from this accessor means disabled.

type DatabaseConfig

type DatabaseConfig struct {
	Driver string `yaml:"driver"`
	DSN    string `yaml:"dsn"`
}

type DefaultsConfig added in v0.3.2

type DefaultsConfig struct {
	// AppVisibility is the access level assigned to newly created apps when
	// no explicit access is provided in the request. Allowed: "private" (default),
	// "shared", "public".
	AppVisibility string
}

DefaultsConfig holds default values applied to new resources at creation time.

type DockerImages

type DockerImages struct {
	Python string
	R      string
}

DockerImages holds the base image names for each app type.

type DockerRuntimeConfig

type DockerRuntimeConfig struct {
	Socket            string
	Images            DockerImages
	DefaultMemoryMB   int // 0 = no limit
	DefaultCPUPercent int // 0 = no limit; 100 = 1 full core
	// NetworkMode controls the Docker network mode applied to app containers.
	// "bridge" (default) puts each app on the default Docker bridge with an
	// explicit 127.0.0.1:port mapping for the proxy — this preserves the
	// "only the proxy can reach the app" boundary that native mode enforces
	// via 127.0.0.1 binding. "host" disables network isolation; the container
	// shares the host network stack. Allowed: "bridge" (default), "host".
	NetworkMode string
}

DockerRuntimeConfig holds Docker-specific runtime settings.

type FargateRuntimeConfig added in v0.7.0

type FargateRuntimeConfig struct {
	// Cluster is the ECS cluster short name or full ARN tasks run on.
	Cluster string
	// TaskDefinition is the family, family:revision, or full ARN of the task
	// definition to run. It must declare a container named ContainerName.
	TaskDefinition string
	// ContainerName is the container within TaskDefinition that per-replica
	// command/env/limit overrides target.
	ContainerName string
	// Subnets are the awsvpc subnet IDs tasks attach to (at least one required).
	Subnets []string
	// SecurityGroups are the awsvpc security group IDs applied to each task ENI.
	SecurityGroups []string
	// AssignPublicIP maps to the awsvpc assignPublicIp setting. Set it for tasks
	// in public subnets without a NAT gateway.
	AssignPublicIP bool
	// PlatformVersion pins the Fargate platform version (e.g. "1.4.0"). Empty
	// uses the ECS default.
	PlatformVersion string
	// Region is the AWS region the ECS client targets. Empty falls back to the
	// SDK's default chain (AWS_REGION, profile, instance metadata).
	Region string
	// RouteViaPublicIP routes to each task's public IP instead of its private IP,
	// for a control plane running outside the task VPC (development/testing only).
	// Requires AssignPublicIP. Production runs the control plane in-VPC and routes
	// over private IPs (default false).
	RouteViaPublicIP bool

	// TaskCPUUnits is the ECS task-level CPU allocation in CPU units (1 vCPU =
	// 1024 units). Must be one of the Fargate-supported values: 256, 512, 1024,
	// 2048, 4096, 8192, 16384. Required when any tier uses runtime "fargate".
	TaskCPUUnits int

	// TaskMemoryMB is the ECS task-level memory allocation in MiB. Must satisfy
	// the Fargate CPU/memory matrix (see validateFargate). Required when any
	// tier uses runtime "fargate".
	TaskMemoryMB int

	// DefaultMemoryMB is the per-container memory limit applied when an app has
	// no explicit memory_limit_mb. 0 means no override (the task definition's
	// container limit applies). Mirrors DockerRuntimeConfig.DefaultMemoryMB.
	DefaultMemoryMB int

	// DefaultCPUPercent is the per-container CPU quota applied when an app has
	// no explicit cpu_quota_percent. 0 means no override. Mirrors
	// DockerRuntimeConfig.DefaultCPUPercent.
	DefaultCPUPercent int

	// ControlPlaneURL is the URL tasks use to fetch their bundle from the control
	// plane. It must be reachable from inside the task's VPC (or subnet, for
	// public-IP mode). Required when any tier uses runtime "fargate".
	// When RouteViaPublicIP is true this must use https:// to prevent the
	// bearer bundle token from travelling in plaintext over the public internet.
	ControlPlaneURL string

	// BundleTokenTTL is how long a minted bundle capability token remains valid.
	// Default 10 minutes. Tasks that take longer than this to start will fail
	// to fetch the bundle; increase if your task cold-start (including image
	// pull) regularly exceeds 10 minutes.
	BundleTokenTTL time.Duration

	// DurableData asserts that this Fargate tier has durable, replica-shared
	// app-data storage (S3 Files, or a volume the operator attached to the base
	// task definition, e.g. EFS). It suppresses the durable-data guard, which
	// otherwise blocks deploying a data-using app onto a Fargate tier whose task
	// storage is ephemeral scratch. Default false. buildFargateRuntime treats the
	// tier as durable if DurableData is true OR an S3 Files backend is configured.
	DurableData bool

	// S3Files, when configured, is the managed durable-data backend: an Amazon S3
	// Files file system mounted into every app's task at MountPath, with each
	// app's data isolated to a per-app subdirectory of RootDirectory. When set,
	// the tier is durable and the control plane injects the volume + mount point
	// into each app's per-app task-definition revision.
	S3Files FargateS3FilesConfig

	// SecretsNamePrefix, when non-empty, enables routing apps' secret env vars
	// through AWS Secrets Manager (referenced by ARN from a per-app task-def
	// secrets block) instead of plaintext task overrides, so they never appear
	// in ecs:DescribeTasks. It namespaces the secret store names and per-app
	// task-definition families; make it unique per ShinyHub installation.
	SecretsNamePrefix string

	// SecretsKMSKeyID optionally encrypts the secrets with a customer-managed KMS
	// key (id, ARN, or alias) instead of the default aws/secretsmanager key. Only
	// meaningful when SecretsNamePrefix is set.
	SecretsKMSKeyID string
}

FargateRuntimeConfig holds the AWS ECS/Fargate runtime settings shared by every tier whose runtime is "fargate". Each replica on such a tier runs as one Fargate task launched from TaskDefinition, with the app command, env, and resource limits applied as container overrides. The proxy routes to the task's awsvpc private IP, so the control plane must run inside or peered with the task's VPC.

type FargateS3FilesConfig added in v0.9.5

type FargateS3FilesConfig struct {
	// FileSystemArn is the ARN of the S3 Files file system to mount
	// (arn:aws:s3files:<region>:<account>:file-system/fs-...). Setting it enables
	// the backend and makes the tier durable.
	FileSystemArn string

	// RootDirectory is the file-system directory under which each app gets its
	// own subdirectory (RootDirectory/<slug>), isolating apps from each other.
	// Default "/". Ignored when AccessPointArn is set (the access point fixes the
	// root and the operator owns isolation).
	RootDirectory string

	// AccessPointArn optionally pins the mount to an S3 Files access point, which
	// enforces its own root directory and identity. When set, per-app RootDirectory
	// isolation does not apply; the operator is responsible for isolation.
	AccessPointArn string

	// TransitEncryptionPort is the port for encrypted data between the ECS host
	// and the file system. 0 lets ECS choose. Transit encryption is always on.
	TransitEncryptionPort int

	// MountPath is the absolute container path the volume is mounted at. It must
	// equal the app's working directory + "/data" so the {data_dir} placeholder
	// ("data", relative to the app cwd) resolves onto the mount. Default
	// "/app/bundle/data" (the reference runner's bundle working directory).
	MountPath string
}

FargateS3FilesConfig configures the managed Amazon S3 Files durable-data backend for a Fargate tier. When FileSystemArn is set, the control plane mounts the file system into every app's task and gives each app an isolated per-app subdirectory of RootDirectory.

func (FargateS3FilesConfig) Configured added in v0.9.5

func (c FargateS3FilesConfig) Configured() bool

Configured reports whether the S3 Files backend is enabled for this tier.

type FooterLink struct {
	Label string `yaml:"label" json:"label"`
	URL   string `yaml:"url" json:"url"`
}

FooterLink is one operator-supplied footer link.

type ForwardAuthConfig added in v0.7.4

type ForwardAuthConfig struct {
	Enabled    bool   `yaml:"enabled"`
	UserHeader string `yaml:"user_header"`
	// EmailHeader is the proxy header carrying the user's email (e.g. Authelia's
	// Remote-Email). When set, the middleware captures it request-scoped and
	// forwards it to apps as X-Shinyhub-Email and the identity token's email
	// claim. Not persisted (the users table has no email column). Empty disables
	// email capture.
	EmailHeader string `yaml:"email_header"`
	// NameHeader is the proxy header carrying the user's friendly name (e.g.
	// Authelia's Remote-Name). When set, the middleware captures it as the
	// forward-auth user's display name. Empty (default) disables name capture.
	NameHeader   string   `yaml:"name_header"`
	GroupsHeader string   `yaml:"groups_header"`
	AdminGroups  []string `yaml:"admin_groups"`
	DefaultRole  string   `yaml:"default_role"`
	// RequireGroupsHeader, when true and groups_header is configured, causes a
	// forward-auth request that is missing the groups header to be refused (403)
	// instead of being treated as no groups. Default false keeps the revoke
	// behavior. Forces a misconfigured proxy to fail loudly.
	RequireGroupsHeader bool `yaml:"require_groups_header"`
}

ForwardAuthConfig configures trust of an upstream reverse proxy that has already authenticated the user. When Enabled is true, the forward-auth middleware trusts UserHeader (and optional EmailHeader / GroupsHeader) on requests whose direct peer IP is in Config.TrustedProxyNets.

type GitHubOAuthConfig

type GitHubOAuthConfig struct {
	ClientID     string
	ClientSecret string
	CallbackURL  string
}

GitHubOAuthConfig holds GitHub OAuth2 application credentials.

type GoogleOAuthConfig

type GoogleOAuthConfig struct {
	ClientID     string
	ClientSecret string
	CallbackURL  string
}

GoogleOAuthConfig holds Google OAuth2 application credentials.

type GroupRoleMapping added in v0.8.2

type GroupRoleMapping struct {
	Group string `yaml:"group"`
	Role  string `yaml:"role"`
}

GroupRoleMapping maps an IdP group name to a global role. Shared by the OIDC and forward-auth feeders; mirrored as auth.GroupRoleMapping at the boundary (the auth package must not import config).

type LifecycleConfig

type LifecycleConfig struct {
	WatchInterval      time.Duration
	RestartMaxAttempts int
	HibernateTimeout   time.Duration
	// WakeHold is how long the proxy holds a request for a not-yet-routable app
	// while its wake completes, so a warm resume serves inline instead of via the
	// loading page. 0 disables the hold (the loading page is served immediately).
	WakeHold time.Duration
}

LifecycleConfig holds parsed lifecycle settings with ready-to-use durations.

type MaintenanceConfig added in v0.8.26

type MaintenanceConfig struct {
	// AuditRetentionDays deletes audit_events older than this many days. 0 (the
	// default) keeps them forever.
	AuditRetentionDays int `yaml:"audit_retention_days"`
	// ScheduleRunRetentionCount keeps this many newest runs per schedule and
	// deletes older ones. 0 (the default) keeps all runs.
	ScheduleRunRetentionCount int `yaml:"schedule_run_retention_count"`
	// Interval is how often the maintenance loop runs. Defaults to 1h.
	Interval time.Duration `yaml:"interval"`
}

MaintenanceConfig controls periodic database housekeeping run on the owner instance only. Retention values default to "keep everything" so no history is ever deleted unless the operator opts in - the safe default for an audit trail and run history.

type MetricsConfig added in v0.6.0

type MetricsConfig struct {
	Enabled bool
	// Addr is the listen address for the dedicated metrics listener in
	// "host:port" form. Defaults to "127.0.0.1:9090" when enabled and unset.
	Addr string
	// HistoryWindow is the retention window for the in-memory app-metrics history
	// (CPU/RAM/sessions/instances) shown on the dashboard Trends card. 0 disables
	// collection. Default 12h; a non-zero value must be within [1m, 48h].
	HistoryWindow time.Duration
	// HistoryInterval is the sampling cadence for the history collector.
	// Default 15s; must be within [1s, 10m].
	HistoryInterval time.Duration
}

MetricsConfig controls the Prometheus scrape endpoint for the ShinyHub server process itself (HTTP request counters/latency, Go runtime + process metrics, build/version, uptime). It is distinct from the per-app CPU/RAM sampling.

When Enabled is false the feature is a no-op: no /metrics handler and no scrape listener are created. When enabled the endpoint is served on its own listener at Addr, defaulting to loopback so server internals are never exposed on a routable interface by accident; operators who scrape from another host set Addr to a private interface behind their own network controls (the conventional Prometheus pattern).

type NativeRuntimeConfig added in v0.9.1

type NativeRuntimeConfig struct {
	// Isolation is the process-isolation dial for native app processes: "off"
	// (default) or "standard" (Landlock filesystem confinement + NO_NEW_PRIVS,
	// Linux-only, best-effort). Validated at load against sandbox.ParseLevel.
	Isolation string
}

NativeRuntimeConfig holds settings for the native (non-container) runtime.

type OAuthConfig

type OAuthConfig struct {
	GitHub GitHubOAuthConfig
	Google GoogleOAuthConfig
	OIDC   OIDCConfig
}

OAuthConfig holds OAuth2 provider credentials.

type OIDCConfig

type OIDCConfig struct {
	IssuerURL          string
	ClientID           string
	ClientSecret       string
	CallbackURL        string
	DisplayName        string // e.g. "Sign in with Okta"
	GroupsClaim        string // ID-token claim holding group names (default "groups")
	GroupsScope        string // optional extra scope to request (e.g. "groups")
	RequireValidGroups bool   // when true, a malformed groups claim fails the login instead of being skipped
}

OIDCConfig holds generic OpenID Connect provider credentials and metadata.

type RuntimeConfig

type RuntimeConfig struct {
	Mode            string // "native" (default) or "docker"
	Docker          DockerRuntimeConfig
	Native          NativeRuntimeConfig
	DefaultReplicas int
	MaxReplicas     int
	// DefaultMaxSessionsPerReplica is the fallback session cap enforced by the
	// proxy when an app's own max_sessions_per_replica is 0. Once every replica
	// reaches this many active connections, new cookie-less requests are shed
	// with 503. 0 here disables the cap entirely (unlimited).
	DefaultMaxSessionsPerReplica int
	// DefaultWorkerIsolation is the fleet default isolation mode applied when an
	// app's worker_isolation is empty. Almost always "multiplex".
	DefaultWorkerIsolation string
	// Tiers is the ordered list of runtime tiers. The first entry is the
	// default tier (used when a replica has no explicit tier). When the config
	// omits tiers, Load synthesizes a single tier named "local" whose runtime
	// equals Mode, so single-node behavior is unchanged.
	Tiers []TierConfig
	// Autoscale holds the global replica-autoscale controller settings. The
	// controller only ever acts on apps that have opted in (per-app
	// autoscale_enabled); these values govern how it behaves for those apps.
	Autoscale AutoscaleConfig
	// Fargate holds the AWS ECS/Fargate runtime settings. They are required when
	// any tier declares runtime "fargate"; otherwise the zero value is unused.
	Fargate FargateRuntimeConfig
	// Snapshot controls warm-wake (freeze + cgroup reclaim), shared by the
	// native and docker runtimes.
	Snapshot SnapshotConfig
}

RuntimeConfig controls how app processes are started and isolated.

func (RuntimeConfig) DefaultResourcesForApp added in v0.7.0

func (r RuntimeConfig) DefaultResourcesForApp(app *db.App) (memMB, cpuPct int)

DefaultResourcesForApp returns the platform-default memory limit and CPU quota appropriate for the given app's placement.

When the app is placed on exactly one tier (len(PlacementMap) == 1), that tier's defaults are used - this ensures an app placed exclusively on a fargate tier receives fargate defaults, not the global default tier's defaults. When the app has no recorded placement or is spread across multiple tiers, DefaultTierName() is used (first declared tier), preserving the existing behaviour for no-placement and multi-tier cases. Multi-tier apps retain the documented limitation that a single set of defaults cannot serve divergent per-tier requirements.

func (RuntimeConfig) DefaultResourcesForTier added in v0.7.0

func (r RuntimeConfig) DefaultResourcesForTier(tier string) (memMB, cpuPct int)

DefaultResourcesForTier returns the platform-default memory limit and CPU quota for a replica placed on the named tier. For a "fargate" tier it returns the Fargate-specific defaults (runtime.fargate.default_memory_mb / default_cpu_percent). For any other runtime it returns the Docker defaults (runtime.docker.default_memory_mb / default_cpu_percent), preserving existing behaviour for native and docker tiers. A zero value for either field means "no limit" as documented.

func (RuntimeConfig) DefaultTierName added in v0.6.1

func (r RuntimeConfig) DefaultTierName() string

DefaultTierName returns the first declared tier's name (the default tier).

func (RuntimeConfig) RuntimeForTier added in v0.6.1

func (r RuntimeConfig) RuntimeForTier(name string) (string, bool)

RuntimeForTier returns the runtime mode backing the named tier.

func (RuntimeConfig) TierOrder added in v0.6.1

func (r RuntimeConfig) TierOrder() []string

TierOrder returns the tier names in declaration order.

type SchedulerConfig added in v0.5.3

type SchedulerConfig struct {
	// DefaultTimezone is the IANA timezone applied to schedules that do not
	// specify their own timezone. Defaults to "UTC". Set via
	// scheduler.timezone in YAML or SHINYHUB_SCHEDULER_TIMEZONE env var.
	DefaultTimezone string
	// Location is the parsed *time.Location derived from DefaultTimezone. It
	// is populated by Load and is the authoritative value used at runtime.
	Location *time.Location `yaml:"-"`
}

SchedulerConfig holds scheduler-level settings.

type ServerConfig

type ServerConfig struct {
	Host           string   `yaml:"host"`
	Port           int      `yaml:"port"`
	BaseURL        string   `yaml:"base_url"`
	TrustedProxies []string `yaml:"trusted_proxies"`

	// ShutdownApps controls what happens to running app subprocesses /
	// containers when the server receives a shutdown signal:
	//   "adopt" (default) — leave them running; on restart the server
	//                        re-adopts them (zero-downtime upgrades).
	//   "stop"            — gracefully stop every app before exiting
	//                        (clean host state; apps cold-start next boot).
	ShutdownApps string `yaml:"shutdown_apps"`

	// InstanceID uniquely identifies this control-plane process among several
	// running against one database (zero-downtime upgrades / failover). Defaults
	// to "<hostname>-<pid>" when unset.
	InstanceID string `yaml:"instance_id"`

	// LeaseTTL is how long this instance's control-plane ownership lease stays
	// valid without a renewal; LeaseRenewEvery is the renewal cadence. LeaseTTL
	// should be at least 2x LeaseRenewEvery; the elector enforces that floor at
	// startup (config stores the raw values).
	LeaseTTL        time.Duration `yaml:"lease_ttl"`
	LeaseRenewEvery time.Duration `yaml:"lease_renew_every"`

	// DrainTimeout bounds how long a graceful shutdown waits for live WebSocket
	// (hijacked) app sessions to close before force-closing them. Sites with
	// long-lived sessions should raise it. Defaults to 60s.
	DrainTimeout time.Duration `yaml:"drain_timeout"`

	// UpgradeTimeout bounds how long the old process waits for a new one to
	// signal Ready during a zero-downtime upgrade (SIGHUP) before aborting the
	// upgrade and continuing to serve. Defaults to 60s.
	UpgradeTimeout time.Duration `yaml:"upgrade_timeout"`

	// StopGrace is the SIGTERM-to-SIGKILL window when stopping a single app
	// replica (hibernation, stop, restart, shutdown). Raise it for apps that
	// need longer to flush session state on shutdown. Defaults to 10s.
	StopGrace time.Duration `yaml:"stop_grace"`

	// PIDFile, when set, receives the ready process's PID on startup and after
	// each zero-downtime handoff. Required for the systemd path (MAINPID
	// tracking via PIDFile=). Empty (default) writes no PID file.
	PIDFile string `yaml:"pid_file"`

	// HostBudgetMB is the total RAM (in MiB) the host can allocate to app
	// worker processes. Used by the host-capacity guard to reject deploys that
	// would exceed available memory. 0 disables the guard.
	HostBudgetMB int `yaml:"host_budget_mb"`

	// MinAvailableMemoryMB is the runtime companion to HostBudgetMB's static
	// worst-case check: while the host's available memory (MemAvailable) is
	// below this floor, NO new elastic worker (grouped/per_session isolation)
	// is allocated; fresh sessions get 503 while established sessions keep
	// routing. Shedding one new session beats the kernel OOM-killing a live
	// worker with every session on it.
	//
	// A pointer so an explicit 0 (disable the floor) is distinguishable from
	// the key being absent: unset applies the safe default (see the
	// MinAvailableMemoryMB accessor) because an elastic OOM takes out a whole
	// worker plus every session bound to it. Negative values disable too.
	MinAvailableMemoryMB *int `yaml:"min_available_memory_mb"`
}

type SnapshotConfig added in v0.8.12

type SnapshotConfig struct {
	Enabled bool
	// MaxSuspended caps concurrently suspended replicas (GC evicts the oldest
	// beyond it). Defaults to 16; a value <= 0 falls back to the default.
	MaxSuspended int
	// ReclaimMinFraction is the minimum fraction of a replica's pre-suspend RSS
	// that must be reclaimed for the freeze to count as "freed"; below it the
	// replica falls back to Stop. Must be in (0, 1]; defaults to 0.8.
	ReclaimMinFraction float64
	// RestoreOnStartup re-boots and re-freezes apps that were hibernated before a
	// server restart, so their next access is a warm resume instead of a cold
	// boot (a frozen process does not survive a service restart). Defaults to
	// true when warm-wake is enabled. No effect when Enabled is false.
	RestoreOnStartup bool
}

SnapshotConfig controls warm-wake, shared by the native and docker runtimes: on hibernate a replica is frozen (SIGSTOP for native, docker pause for docker) and its RAM reclaimed to swap via cgroup v2 memory.reclaim instead of being stopped, so wake resumes it warm. Disabled by default; when off, apps hibernate via Stop exactly as before.

type StorageConfig

type StorageConfig struct {
	AppsDir          string `yaml:"apps_dir"`
	AppDataDir       string `yaml:"app_data_dir"`
	VersionRetention int    `yaml:"version_retention"`
	// AppQuotaMB caps the total on-disk footprint (bundles + extracted
	// versions + persistent data dir, excluding .shinyhub-upload-tmp/) of a
	// single app, in mebibytes. 0 disables the limit.
	AppQuotaMB int `yaml:"app_quota_mb"`
	// MaxBundleMB caps a single deploy bundle's multipart upload size, in
	// mebibytes. Must stay aligned with the UI's DEPLOY_MAX_BYTES (asserted
	// by a test). 0 means "no cap"; default 128 matches the existing UI.
	MaxBundleMB int `yaml:"max_bundle_mb"`
}

type ThemeConfig added in v0.5.4

type ThemeConfig struct {
	PrimaryColor string `yaml:"primary_color"`
}

ThemeConfig holds theme tokens applied to the stock catalog/login.

type TierConfig added in v0.6.1

type TierConfig struct {
	Name       string
	Runtime    string
	LaunchType string // "FARGATE" (default) or "EC2"; only meaningful for fargate tiers
}

TierConfig names a runtime tier and the runtime that backs it. Runtime is one of "native" or "docker" in this phase ("remote_docker" arrives with the remote provider).

type TracingConfig added in v0.4.1

type TracingConfig struct {
	Enabled bool
	// OTLPEndpoint is the OTLP receiver URL passed to apps as
	// OTEL_EXPORTER_OTLP_ENDPOINT. Apps export their spans here directly;
	// ShinyHub does not proxy or store them.
	OTLPEndpoint string
	// OTLPProtocol is the wire protocol hint, passed as
	// OTEL_EXPORTER_OTLP_PROTOCOL. Default "http/protobuf" matches the Shiny
	// Python docs. Allowed: "http/protobuf", "grpc".
	OTLPProtocol string
	// OTLPHeaders is an optional comma-separated list of "key=value" pairs
	// passed as OTEL_EXPORTER_OTLP_HEADERS — used by backends like Honeycomb
	// or Grafana Cloud for auth.
	OTLPHeaders string
	// SampleRatio is the head-based sampling probability (0.0–1.0) applied to
	// the proxy's own spans AND propagated to apps via OTEL_TRACES_SAMPLER_ARG.
	// 0 disables sampling (no spans recorded); 1 samples everything.
	SampleRatio float64
	// SlowRequestMS is the latency threshold (in milliseconds) at which a proxy
	// span is retained in the ring buffer regardless of sampling decision. Error
	// spans are always retained. 0 means "retain only error spans".
	SlowRequestMS int
	// RingBufferSize is the maximum number of recent (slow or error) spans
	// retained in-memory per app. Older entries are evicted FIFO. 0 disables
	// the ring buffer entirely.
	RingBufferSize int
	// TraceLinkTemplate is an optional URL template used to deep-link a trace_id
	// to the operator's tracing backend. The substring "{trace_id}" is
	// replaced. Example: "https://grafana.example.com/explore?traceId={trace_id}".
	TraceLinkTemplate string
	// AutoInstrumentApps, when true, launches Python apps under
	// opentelemetry-instrument with the OTEL SDK and transport-layer
	// instrumentors layered into the app's environment via uv's --with
	// overlay. Apps get inbound ASGI and outbound HTTP spans with no bundle
	// changes; the app's own venv and lockfile are never modified. Per-app
	// shinyhub.toml `[tracing] auto` overrides this default in both
	// directions. Requires Enabled; R apps and custom-command apps are
	// never wrapped.
	AutoInstrumentApps bool
}

TracingConfig controls OpenTelemetry trace propagation to app processes and the in-memory ring buffer of recent proxy spans surfaced in the UI.

When Enabled is false the entire feature is a no-op: no env vars are injected into app processes, the proxy does not propagate traceparent, and the ring buffer is empty. When enabled, ShinyHub injects OTEL_* defaults into each app process (overridable by user env vars) and retains slow/error proxy spans per-app for surfacing in the UI.

type WorkerConfig added in v0.6.1

type WorkerConfig struct {
	Enabled       bool   `yaml:"enabled"`
	JoinTokenFile string `yaml:"join_token_file"`
	CADir         string `yaml:"ca_dir"`
	// ListenAddr is the TCP address the worker-facing mTLS listener binds to.
	// The effective default when this is empty is 0.0.0.0:8443 (applied by
	// workerListenAddr in cmd/shinyhub/worker.go).
	ListenAddr string `yaml:"listen_addr"`
	// AdvertiseHosts lists the hostnames and IP addresses that remote workers
	// use to reach the control plane. They are placed as SANs in the
	// worker-API server certificate so workers can verify the TLS connection.
	// When empty the certificate defaults to loopback addresses only, which
	// is sufficient for local testing but will fail remote worker connections.
	AdvertiseHosts []string `yaml:"advertise_hosts"`
}

WorkerConfig holds the control-plane settings for hosting remote workers. The worker role (shinyhub worker) takes no yaml; it is configured by CLI flags.

type WorkerIsolationMode added in v0.9.2

type WorkerIsolationMode string
const (
	IsolationMultiplex  WorkerIsolationMode = "multiplex"
	IsolationGrouped    WorkerIsolationMode = "grouped"
	IsolationPerSession WorkerIsolationMode = "per_session"
)

type WorkerSettings added in v0.9.2

type WorkerSettings struct {
	Isolation          WorkerIsolationMode
	GroupedSize        int
	MaxWorkers         int
	MaxSessionLifetime int
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL