CI Report:
https://ci-tests.linuxserver.io/linuxserver/sealskin/0.4.0-ls64/index.html
LinuxServer Changes:
Full Changelog: 0.3.2-ls63...0.4.0-ls64
Remote Changes:
SealSkin 0.4.0
SealSkin works from any browser now. The server serves the web app at /,
users sign in with an identity provider or the reverse proxy in front of it,
sessions open under the web app's own name and install as apps of their own,
and several servers can run as one cluster over an object store. Everything
the extension and the mobile app did still works: they sign in with an
application key made on the web, or, on a single server, with their key files
as before.
Highlights
- The web app.
https://<server>:8443/is the launcher, the file manager,
and the admin pages, with nothing installed. A launch takes the tab, shows
its progress, and opens the session when it is ready; a checkbox opens it
in a new tab instead. The app installs as a PWA, and every application has a
pinned address,/app/<app id>/, that attaches to its running session or
launches one, with its options in the query, so a bookmark or a home-screen
icon lands straight in a desktop. - Sign in with what you have. OpenID Connect, SAML, or a reverse proxy
that signs users in through its forward-auth (Authelia, Authentik, Keycloak,
oauth2-proxy, Pocket ID, Tinyauth, and the guides for Caddy, Traefik, SWAG,
and Nginx Proxy Manager). The provider's groups make administrators and set
limits; a new user in no group is held until an administrator approves them
into groups. The sign-in page can send the browser straight to the
provider, with#rootas the way to the server's own page. - The built-in administrator. The first start writes two files for one
account,admin:/config/admin.json, the key file of the companion apps,
and/config/root_key, the root key that signs the web app in. Its
desktops, files, and keys are one set whichever way in you take, and
SEALSKIN_ROOT_SIGN_IN=falseswitches the root key off once the provider's
administrators are in. - Application keys. The extension and the mobile app are companions of the
web app: a user makes a key per device on the web, shown as text and as a
QR code, pastes or scans it into the app, and an administrator sets how long
keys live, which apps may hold one, when a key goes dormant, and revokes any
of them. - Sessions on one origin. SealSkin serves the Selkies web client itself,
taken out of each image at pull time, and the container answers only its
API, so sessions live at/<session id>/under the web app's name: one
certificate, permissions granted once, audio that plays, no wildcard DNS.
SEALSKIN_SESSION_ISOLATIONkeeps every session on a name of its own for
images you do not trust. - Kubernetes. One manifest installs the server in any namespace you
administer, with no cluster-scoped objects; every session is a pod beside
it, with GPUs, pod templates, resource quotas, and pull secrets honored. - Clusters. Servers share users, groups, applications, and settings
through an object store, an S3 bucket or the built-in file store, with
pools of nodes, placement of sessions, GPU slots, home directories pinned to
a node and moved between them, shared files kept in the store and encrypted
underSEALSKIN_STORE_KEY, limits that hold across nodes, and an
append-only audit log. - VPN exits. Administrators import WireGuard and OpenVPN profiles; a user
picks one at launch and the session leaves through that tunnel and nothing
else, with a gateway per endpoint on Docker and a hub per endpoint on
Kubernetes, and a cap on tunnels per profile. - Registries and proxies. Private registries sign in through a Docker
config.jsonon each node (SEALSKIN_REGISTRY_AUTH_PATH), and on
Kubernetes through the session template's pull secrets as well; internal
hosts that serve stores, logos, and catalogs through a netrc file
(SEALSKIN_NETRC_PATH);SEALSKIN_IMAGE_MIRRORSsends every pull to a
mirror per upstream registry while the records keep the upstream names; and
the server's own fetches followHTTPS_PROXYand trustSSL_CERT_FILE. A
deployment without internet access runs on these alone. - Branding. A name, logo, accent, wallpaper, home links, and the store
links of the companion apps, set from the dashboard with a live preview. - PRoot Apps catalogs. Catalogs of portable applications assigned to users
and groups, fetched on every node and mounted into sessions, from GitHub
repositories or any host and registry built the same way. - Templates. The template editor carries Selkies' current encoders, start
policies, and session variables, among them the connection indicator, the
audio and webcam devices, 10-bit video, the GPU id, the print spool, the
window buttons, and the Computer-Use token beside its bind. A user with
Allow Editing App Templates edits templates short of theDOCKER_*
settings and the reserved identity variables, which stay an
administrator's. - A new logo.
assets/logo.svgis the source of every icon. - The home page. Sessions show live screenshots, applications are
favorites or hidden per user, and the sidebar folds away. - Collaboration rooms. A room opens each participant's session with its
token in the URL fragment, where no server log or Referer sees it; a
participant may hold one gamepad slot per controller; and a viewer reaches
the container on a view-only login of its own. This needs a Selkies
release after 2.0.0 in the images you launch.
Server
- The web sign-in is a cookie on the web app's origin; every route it
authenticates asks the browser where the request came from, the cookie is
dropped before a request reaches a session container, and a session's pages
may be framed by the web app alone. /companion/is the lane of the companion apps, which a reverse proxy that
signs users in leaves unguarded;/internal/*answers the proxy's own
sub-requests alone, wherever the API port is reachable.- A plain HTTP listener (
SEALSKIN_HTTP_PORT) for a proxy that terminates
TLS, answering the addresses inSEALSKIN_TRUSTED_PROXIESalone, with HTTP/3
advertised only where browsers reach the session port directly. - A node's identity is its name:
SEALSKIN_NODE_NAME, else the container's
name in Docker, else the host name. A node started again with the same name
and storage is the same node. - Nodes call each other with signed requests over a peer listener on 8444,
trusting the approved nodes' certificates alone; a bucket's credentials
make a node a member, a file store asks an administrator to approve it or
takes a join code. - Per-user launch leases keep a user with a session limit from racing it.
- Every picture a page shows comes from the server: application, PRoot, and
home-link logos are fetched once and served from/api/logos/<name>;
nothing loads from a third party. - A user in no group is in
default, a built-in group the Groups table shows
read-only: the server's defaults, which a user's own record overrides.
Applications, VPN profiles, and pools may namedefaultto reach exactly
those users, whereallreaches everyone; no group may be nameddefault,
all, ornone. Approve on a held user opens the groups to place them
in, with the groups the provider named beside; turning
SEALSKIN_SSO_HOLD_NEW_USERSoff lets new users in at once and leaves the
held ones held. - Groups now restrict: where a user and their groups disagree, the stricter
switch and the smaller limit win. - The security audits' fixes: a key-file client's token names the crypto
session it is sent with, and the server refuses it with any other; a
room's viewer reaches the container as a view-only login, never the
controller's; a handshake reads at most 16 KiB and the crypto sessions it
leaves are capped; the file manager, uploads, shares, and launches act
through descriptors checked inside the home, so a symlink swapped in by the
session cannot lead them out of it; every record file of the cluster is
named through one checked join, and deleting a pool refuses a name with a
path in it; a room tells each viewer its own token and an alias for the
others and swaps only to apps open to the session's owner; a store's
docker_overridesstay inside the container; a user's uploads are bounded;
deleting a user ends their sessions, uploads, and shares; an app's icon goes
only to whom the app is listed for; a share's password form closes for a
minute after five wrong passwords and its download token dies with the
share; every session and collaboration token is compared in constant time;
and the session port serves other origins uncredentialed reads alone. - NVIDIA sessions want the NVIDIA Container Toolkit v1.20.1 or higher, whose
refresh service creates the modeset device; the server mounts it itself only
as the fallback for a runtime that injects none.
Client
- The web app, the extension, and the mobile app share one served UI; the
shells frame the same pages and add their privileged pieces. - The connect page offers an application key first and a key file second; a
key carries the server's address, so the page fills it in, and the mobile
app reads it from the QR code the web app shows. - The extension no longer frames a server over plain HTTP once it has
answered over HTTPS, unless the user says so, and a page framed over plain
HTTP says so above it. A served page can no longer read the connect page's
draft or have the shell fetch an address on its behalf. - In-page modals replace every browser alert; stopping a session asks
nothing, since the home directory stays. - The mobile app's pages fit a phone in portrait, and its APKs carry the
icons. - Translations for every page in all seventeen other languages.
Upgrading from 0.3
On the linuxserver/sealskin container nothing on disk needs changing:
users, groups, installed_apps.yml, templates, and sessions load as
before, and key files keep signing in while SEALSKIN_LEGACY_AUTH stays on
(its default). What is new:
- The first start writes
/config/root_key, an application key of the
administratoradminwhose key file is/config/admin.json. Open
https://<server>:8443/, sign in with it, then copy it somewhere safe and
delete the file. - The server's identity in its own records is the container's name. Give the
container a stable name (sealskin, which the server needs anyway) or set
SEALSKIN_NODE_NAME; a server recreated under another name is another node. /config/.config/sealskin/node/holds the node's own peer certificate and
/config/.config/sealskin/cluster/the shared records. Port 8444 is the peer
listener; publish it only to join a cluster.- To put the server behind a reverse proxy, set
SEALSKIN_PUBLIC_URL,
SEALSKIN_TRUSTED_PROXIES, and, for a proxy that terminates TLS,
SEALSKIN_HTTP_PORT; the reverse proxy pages show each proxy. - Collaboration rooms need a Selkies release after 2.0.0 in the images you
launch; older images open a room's session without its token, and a session
launched before the upgrade has no view-only login for a room's viewers. - VPN profiles need the
ghcr.io/selkies-project/sealskin-vpnimage to be
pullable by every node; pin its version withSEALSKIN_VPN_IMAGE. - NVIDIA hosts need the NVIDIA Container Toolkit v1.20.1 or higher.
- A group that set a limit of
-1to lift a user's own limit no longer does:
the stricter of the two holds. A group file nameddefault,all, or
noneis refused. - A user in no group gets the server's defaults, shown as the
defaultgroup.
Nothing changes for them; what they get is now in plain view.
The extension and the mobile app from 0.3 keep working against this server
with their key files over HTTPS; their tokens are refused on the plain HTTP
API port on 8000, which the 0.4.0 shells sign for the session they use. The
store releases of 0.4.0 add the application-key sign-in, the QR scanner, and
the HTTPS hold.
Documentation
- Laid out as the Selkies documentation is, with pages for signing in,
clusters, the object store, Kubernetes, VPN profiles, registries and
proxies, and one per reverse proxy; the Server Reference is rendered from
the docstrings. - The site is published per release with a version switcher, and every page
is served as Markdown as well, withllms.txtand copy and open-in actions
for language models. .oss-scanner/threat_model.mdstates what SealSkin does, its principals,
its entry points, and the rules the code is held to; the scanner, CodeQL,
and the other checkers' findings are fixed in code, never dismissed.