Self-hosted web application for remote server management via SSH terminal and SFTP file browser
Project description
webgate
Self-hosted web app for remote server management โ SSH terminal, SFTP file browser, server registry, all in your browser. A modern Python replacement that combines the best of webssh and filebrowser into a single tool with a FileZilla-inspired interface.
๐ฎ Try it live: webgate-demo.fly.dev โ login
demo/demo(read-only sandbox, resets hourly)๐ Docs: kalexnolasco.github.io/webgate
Quick start
export WEBGATE_SECRET_KEY=$(openssl rand -hex 32)
docker compose up -d
# open http://localhost:8443/ โ login: admin / admin
That's it. The first login forces a password change. Add servers from the Site Manager, click SSH or SFTP to connect.
For a richer dev environment with a sandboxed SSH target pre-baked: docker compose -f compose.dev.yml up --build.
Why webgate?
Managing remote servers means juggling SSH clients, SFTP tools, credentials and VPN configs across your team. In many real-world setups direct SSH access to every server isn't possible โ only HTTP(S) reaches the gateway.
The problem
flowchart TB
subgraph internet ["Internet"]
YOU["Your Team"]
end
subgraph firewall ["Client Firewall"]
GW["Gateway Server<br/>(HTTP only)"]
subgraph internal ["Internal Network"]
DB1[(PostgreSQL<br/>10.0.1.10)]
DB2[(MySQL<br/>10.0.1.11)]
APP1["App Server<br/>10.0.1.20"]
APP2["App Server<br/>10.0.1.21"]
WORKER["Worker<br/>10.0.1.30"]
REDIS["Redis<br/>10.0.1.40"]
end
end
YOU -- "HTTPS :443" --> GW
GW -. "SSH :22" .-> DB1
GW -. "SSH :22" .-> DB2
GW -. "SSH :22" .-> APP1
GW -. "SSH :22" .-> APP2
GW -. "SSH :22" .-> WORKER
GW -. "SSH :22" .-> REDIS
style internet fill:#e8f0fe,stroke:#4a90d9
style firewall fill:#fff3e0,stroke:#ff9800
style internal fill:#f0f9e8,stroke:#5cb85c
style GW fill:#ffcc02,stroke:#e6a800,color:#333
style YOU fill:#4a90d9,stroke:#2a6cb5,color:#fff
The solution
Deploy webgate on the gateway. Everyone gets browser-based SSH and SFTP to every internal server โ no VPN, no scattered SSH keys, full audit trail.
flowchart TB
subgraph internet ["Internet"]
ENG1["Engineer 1<br/>(Browser)"]
ENG2["Engineer 2<br/>(Browser)"]
ENG3["Engineer 3<br/>(Browser)"]
end
subgraph firewall ["Client Firewall"]
WG["webgate<br/>Gateway Server :443"]
subgraph internal ["Internal Network"]
DB1[(PostgreSQL)]
APP1["App Server"]
WORKER["Worker"]
REDIS["Redis"]
end
end
ENG1 -- "HTTPS" --> WG
ENG2 -- "HTTPS" --> WG
ENG3 -- "HTTPS" --> WG
WG -- "SSH/SFTP" --> DB1
WG -- "SSH/SFTP" --> APP1
WG -- "SSH/SFTP" --> WORKER
WG -- "SSH/SFTP" --> REDIS
style internet fill:#e8f0fe,stroke:#4a90d9
style firewall fill:#fff3e0,stroke:#ff9800
style internal fill:#f0f9e8,stroke:#5cb85c
style WG fill:#5cb85c,stroke:#449d44,color:#fff
style ENG1 fill:#4a90d9,stroke:#2a6cb5,color:#fff
style ENG2 fill:#4a90d9,stroke:#2a6cb5,color:#fff
style ENG3 fill:#4a90d9,stroke:#2a6cb5,color:#fff
Use cases
| Scenario | How webgate helps |
|---|---|
| Restricted client networks | Only the gateway is HTTP-reachable; webgate proxies SSH/SFTP from there |
| On-call / incident response | Open a browser anywhere, no laptop with keys needed; share the live session for pair-debugging |
| Team onboarding | Admin creates a user, assigns groups; new engineer has access in seconds |
| Audit & compliance | Centralized access point, structured audit log, optional asciinema session recording |
| Multi-client / agency | One webgate per client, isolated server registries; run lots of them cheaply |
Features
| Category | Capabilities |
|---|---|
| Terminal | xterm.js + asyncssh, multi-tab, resize, copy/paste, shared sessions with one-click URL, command snippets library |
| SFTP | Full file ops + drag & drop upload, ZIP folder download, in-browser editor (CodeMirror 6), PDF/image preview |
| Server Registry | Groups, tags, password/key auth, encrypted at rest (Fernet), import/export JSON, jump host / bastion chaining |
| Access Control | Admin/user roles, per-server SSH/SFTP toggles, SFTP path restrictions, read-only SFTP mode, group-based visibility |
| Auth | JWT + bcrypt locally, 2FA TOTP, API keys for automation, LDAP / Active Directory with groupโrole mapping |
| Compliance | Session recording to asciinema cast files with browser replay, structured audit log, webhooks (HMAC-signed) on key events |
| Monitoring | Background SSH connectivity probes, online/offline indicator |
| Deployment | Multi-stage Docker image, SQLite default or PostgreSQL, runs behind any reverse proxy at any sub-path, demo mode for public read-only deployments |
| UX | Dark/light theme, responsive, keyboard shortcuts, vanilla JS + Alpine.js (no npm needed), session persistence across reloads |
Screenshots
Core (Site Manager, terminal, SFTP, editor)
Access control & admin
Operations Pack โ jump host, snippets, webhooks
Shared terminal & session recording
| Owner sees | Joiner sees |
|---|---|
| Recordings list | Browser replay |
|---|---|
Architecture
Project layout
src/webgate/
โโโ __main__.py uvicorn launcher
โโโ app.py FastAPI factory, lifespan, middleware
โโโ config.py Pydantic Settings
โโโ auth/ JWT + bcrypt, 2FA TOTP, API keys, LDAP, user mgmt
โโโ audit/ Immutable action log
โโโ servers/ Registry CRUD, jump-host resolution, Fernet crypto
โโโ terminal/
โ โโโ ssh_session.py asyncssh wrapper (with optional jump tunnel)
โ โโโ shared.py SharedSession registry: 1 PTY โ N WebSockets
โ โโโ ws_handler.py WS bridge: input multiplex / output broadcast
โ โโโ routes.py WS endpoints + share-token mint/revoke
โโโ files/ SFTP service + connection pool (5 min TTL)
โโโ snippets/ Per-user command library
โโโ webhooks/ HMAC-signed event dispatcher
โโโ recordings/ asciinema cast v2 writer + browser replay
โโโ db/ SQLAlchemy async engine + dialect-aware migrations
โโโ static/index.html Single-file frontend (Alpine.js + xterm.js + CodeMirror)
Request lifecycle
flowchart LR
Browser["Browser<br/>(Alpine + xterm.js + CodeMirror)"]
subgraph webgate ["webgate (FastAPI)"]
AUTH["JWT / API key / LDAP"]
REST["REST routes"]
WS["WebSocket handler"]
POOL["SFTP pool<br/>(5 min TTL)"]
SHARED["SharedSession<br/>registry"]
REC["CastRecorder"]
DB[("DB<br/>SQLite / PostgreSQL")]
end
SSH(["asyncssh"])
REMOTE["Remote server"]
Browser <-- "HTTPS / WSS" --> AUTH
AUTH --> REST
AUTH --> WS
REST --> POOL
REST --> DB
WS --> SHARED
SHARED -. write .-> REC
SHARED --> SSH
POOL --> SSH
SSH --> REMOTE
style Browser fill:#e8f0fe,stroke:#4a90d9
style webgate fill:#f0f9e8,stroke:#5cb85c
style REMOTE fill:#fff3e0,stroke:#ff9800
Jump host (bastion) chaining
When a server has jump_via_id set, webgate opens the SSH connection to the bastion first and tunnels the target connection through it. Same chain is used for the SFTP browser. No VPN required, only outbound SSH from the gateway to the bastion.
flowchart LR
B["Browser"]
WG["webgate"]
BAST["bastion<br/>10.0.0.1"]
INT["internal-app<br/>10.0.1.50"]
B -- "HTTPS / WSS" --> WG
WG -- "SSH" --> BAST
BAST -- "SSH (tunneled)" --> INT
style B fill:#4a90d9,stroke:#2a6cb5,color:#fff
style WG fill:#5cb85c,stroke:#449d44,color:#fff
style BAST fill:#ffcc02,stroke:#e6a800,color:#333
style INT fill:#fff3e0,stroke:#ff9800
Shared terminal session
The owner's terminal is registered with a SharedSession. When the owner clicks ๐ Share, a token is minted and any joiner with the URL attaches a second WebSocket. There's still one SSH PTY โ output is broadcast to all clients, input from any RW client is multiplexed into the same stdin.
flowchart LR
O["Owner WS"]
J1["Joiner WS (rw)"]
J2["Joiner WS (ro)"]
SS["SharedSession"]
PTY["asyncssh PTY"]
REMOTE["Remote SSH server"]
REC["CastRecorder<br/>(if recording on)"]
O -- "input" --> SS
J1 -- "input" --> SS
J2 -. "no input" .-> SS
SS -- "write stdin" --> PTY
PTY -- "stdout" --> SS
SS -- "broadcast" --> O
SS -- "broadcast" --> J1
SS -- "broadcast" --> J2
SS -. "tee" .-> REC
PTY <--> REMOTE
style SS fill:#5cb85c,stroke:#449d44,color:#fff
style PTY fill:#ffcc02,stroke:#e6a800,color:#333
style REC fill:#a78bfa,stroke:#7c3aed,color:#fff
Access model โ groups, tags, LDAP
Three concepts, easy to mix up. Here's how they fit together:
| Concept | Type | Defined by | What it does |
|---|---|---|---|
Server.group |
single string per server (e.g. production) |
admin, in the Add Server form | gates visibility: a non-admin user only sees servers whose group is in their allowed_groups |
Server.tags |
list of strings (e.g. ["nginx","eu-west-1"]) |
admin, in the Add Server form | cosmetic / search only โ does not affect access |
User.allowed_groups |
list of strings | admin (Users panel) or LDAP mapping | the set of Server.group values a non-admin user is allowed to see |
User.is_admin |
bool | admin (Users panel) or LDAP WEBGATE_LDAP_ADMIN_GROUPS |
admins see everything regardless of allowed_groups |
With LDAP, the admin still controls which group names exist by typing them when registering each server. LDAP only populates the user side of the equation:
flowchart LR
subgraph LDAP
L1["alice โ cn=devs"]
L2["alice โ cn=admins"]
end
subgraph "WEBGATE_LDAP_GROUP_MAP<br/>(env var)"
M["{<br/> "devs": "production",<br/> "sre": "all"<br/>}"]
end
subgraph User
U["alice.allowed_groups<br/>= ["production"]"]
end
subgraph Servers
S1["app-1<br/>group=production โ
"]
S2["app-2<br/>group=staging โ"]
S3["db-1<br/>group=production โ
"]
end
L1 -- mapped --> M
L2 -. ignored<br/>(not in map) .-> M
M --> U
U --> S1
U --> S3
Key rules:
- LDAP does not create groups on the webgate side. The right-hand value of
WEBGATE_LDAP_GROUP_MAPmust match exactly what you typed inServer.group. - An LDAP group that isn't in the map is silently ignored.
WEBGATE_LDAP_ADMIN_GROUPSis independent of the map: any membership in those groups grants admin (and admins see all servers).- Tags are never used for access control, only for filtering / search in the UI.
LDAP authentication
Search-then-bind: webgate binds as the service account, finds the user DN, re-binds as the user with their password to verify credentials, then enumerates LDAP groups and maps them to webgate groups (and admin status).
sequenceDiagram
participant Browser
participant webgate
participant LDAP
Browser->>webgate: POST /api/auth/login (alice, ****)
webgate->>webgate: try local password (miss)
webgate->>LDAP: bind(svc-DN, svc-password)
LDAP-->>webgate: ok
webgate->>LDAP: search(uid=alice) under user_base
LDAP-->>webgate: dn=uid=alice,ou=people,...
webgate->>LDAP: re-bind(user-DN, user-password)
LDAP-->>webgate: ok โ
webgate->>LDAP: search(member=user-DN) under group_base
LDAP-->>webgate: [devs, admins]
webgate->>webgate: map โ allowed_groups, is_admin
webgate->>webgate: upsert local User row
webgate-->>Browser: JWT
Configuration
All settings are environment variables prefixed with WEBGATE_.
Core
| Variable | Default | Description |
|---|---|---|
WEBGATE_SECRET_KEY |
change-me-in-production |
JWT signing + Fernet credential encryption (set this!) |
WEBGATE_HOST |
0.0.0.0 |
Bind address |
WEBGATE_PORT |
8443 |
Bind port |
WEBGATE_LOG_LEVEL |
info |
uvicorn log level |
WEBGATE_FIRST_RUN |
true |
Allow first-user auto-creation as admin |
Database
| Variable | Default | Description |
|---|---|---|
WEBGATE_DB_URL |
sqlite+aiosqlite:///./webgate.db |
SQLAlchemy async URL. Use postgresql+asyncpg://user:pass@host:5432/webgate for Postgres |
Sessions, JWT, monitoring
| Variable | Default | Description |
|---|---|---|
WEBGATE_SESSION_TIMEOUT |
3600 |
SSH session idle timeout (seconds) |
WEBGATE_MAX_UPLOAD_SIZE |
104857600 |
Max upload size (100 MB) |
WEBGATE_JWT_ALGORITHM |
HS256 |
JWT algorithm |
WEBGATE_JWT_EXPIRE_MINUTES |
1440 |
Token expiry (24 h) |
WEBGATE_MONITOR_INTERVAL |
60 |
Server status check interval (s) |
WEBGATE_MONITOR_TIMEOUT |
5 |
SSH connect timeout for status checks (s) |
WEBGATE_MONITOR_CONCURRENCY |
10 |
Max parallel status checks |
WEBGATE_ALLOWED_ORIGINS |
* |
CORS origins (comma-separated) |
Reverse proxy & demo mode
| Variable | Default | Description |
|---|---|---|
WEBGATE_ROOT_PATH |
`` (empty) | URL prefix when served behind a sub-path (e.g. /webgate). The proxy must forward the prefix unchanged |
WEBGATE_DEMO_MODE |
false |
Read-only public demo: blocks writes, hides admin UI, seeds demo/demo user, shows top banner |
Session recording (asciinema)
| Variable | Default | Description |
|---|---|---|
WEBGATE_RECORD_SESSIONS |
false |
Capture every terminal session to a cast v2 file |
WEBGATE_RECORDINGS_DIR |
./recordings |
Storage directory for .cast files |
LDAP / Active Directory
| Variable | Default | Description |
|---|---|---|
WEBGATE_LDAP_ENABLED |
false |
Enable LDAP fallback after local credential check |
WEBGATE_LDAP_URL |
`` | ldap://host:389 or ldaps://host:636 |
WEBGATE_LDAP_BIND_DN |
`` | Service account DN, e.g. cn=admin,dc=example,dc=com |
WEBGATE_LDAP_BIND_PASSWORD |
`` | Service account password |
WEBGATE_LDAP_USER_BASE |
`` | e.g. ou=people,dc=example,dc=com |
WEBGATE_LDAP_USER_FILTER |
(uid={username}) |
AD: (sAMAccountName={username}) |
WEBGATE_LDAP_GROUP_BASE |
`` | e.g. ou=groups,dc=example,dc=com (empty = no group lookup) |
WEBGATE_LDAP_GROUP_FILTER |
(member={dn}) |
AD nested: (member:1.2.840.113556.1.4.1941:={dn}) |
WEBGATE_LDAP_GROUP_MAP |
{} |
JSON {"ldap-cn":"webgate-group"} |
WEBGATE_LDAP_ADMIN_GROUPS |
[] |
JSON list of LDAP CNs that grant admin |
Deployment
Production with Docker
export WEBGATE_SECRET_KEY=$(openssl rand -hex 32)
docker compose up -d
The default compose.yml pulls kalexnolasco/webgate:latest, persists state in a named volume, and lists the optional features as commented env vars you can opt into.
Behind a reverse proxy with TLS
Caddy (simplest)
# add to compose.yml
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports: ["443:443", "80:80"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
# Caddyfile
webgate.example.com {
reverse_proxy webgate:8443
}
nginx (sub-path /webgate/)
Set WEBGATE_ROOT_PATH=/webgate on the container, then:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# WebSocket โ must come before the generic location
location /webgate/api/ws/ {
proxy_pass http://127.0.0.1:8443;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
location /webgate/ {
proxy_pass http://127.0.0.1:8443;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Prefix /webgate;
client_max_body_size 100m;
}
}
Apache 2.4 (sub-path /webgate/)
# Required modules: proxy proxy_http proxy_wstunnel headers rewrite ssl
RewriteEngine On
RewriteRule ^/webgate$ /webgate/ [R=301,L]
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Prefix "/webgate"
ProxyPass /webgate/api/ws/ ws://127.0.0.1:8443/webgate/api/ws/
ProxyPassReverse /webgate/api/ws/ ws://127.0.0.1:8443/webgate/api/ws/
ProxyPass /webgate/ http://127.0.0.1:8443/webgate/
ProxyPassReverse /webgate/ http://127.0.0.1:8443/webgate/
โ ๏ธ The proxy must forward the prefix unchanged โ webgate handles
/webgate/api/...natively, do not strip it.
Traefik (Docker labels)
labels:
- "traefik.enable=true"
- "traefik.http.routers.webgate.rule=Host(`example.com`) && PathPrefix(`/webgate`)"
- "traefik.http.routers.webgate.entrypoints=websecure"
- "traefik.http.routers.webgate.tls=true"
- "traefik.http.services.webgate.loadbalancer.server.port=8443"
Public read-only demo (Fly.io)
The repo includes Dockerfile.demo (webgate + sandboxed sshd via supervisord) and fly.toml. Deploy:
flyctl launch --no-deploy --copy-config
flyctl secrets set WEBGATE_SECRET_KEY=$(openssl rand -hex 32)
flyctl volumes create webgate_demo_data --size 1 --region cdg
flyctl deploy
The demo middleware blocks all writes on /api/* (login, terminal share and totp/verify whitelisted), so anyone hitting the URL can browse the seeded bastion + internal-app pair without poking holes in your infra. The official live demo at https://webgate-demo.fly.dev runs exactly this.
API reference
| Group | Methods (summary) |
|---|---|
| Auth | POST /api/auth/login, GET /api/auth/me, POST/PUT /api/auth/users/..., POST /api/auth/totp/setup, GET/POST/DELETE /api/auth/api-keys, GET /api/auth/audit |
| Servers | GET/POST/PUT/DELETE /api/servers, POST /api/servers/{id}/test, GET /api/servers/groups, POST /api/servers/import, GET /api/servers/export, GET /api/servers/status |
| Terminal | WS /api/ws/terminal/{server_id} (owner), WS /api/ws/terminal/quick (one-off), WS /api/ws/terminal/join/{token}?mode=rw|ro (joiner), POST/DELETE /api/terminal/share/{session_id} |
| Files (SFTP) | GET /ls, GET /read, GET /download, GET /download-zip, POST /upload, PUT /write, POST /mkdir, POST /rename, DELETE /delete, POST /chmod, GET /stat (all under /api/files/{server_id}/) |
| Snippets | GET/POST /api/snippets, DELETE /api/snippets/{id} |
| Webhooks | GET/POST /api/webhooks, PUT/DELETE /api/webhooks/{id}, POST /api/webhooks/{id}/test, GET /api/webhooks/events |
| Recordings | GET /api/recordings, GET /api/recordings/{id}/download, GET /api/recordings/{id}/play, GET /api/recordings/{id}/cast, DELETE /api/recordings/{id} |
| Health / Config | GET /api/health, GET /api/config (public โ exposes demo_mode to the frontend) |
Full OpenAPI is auto-generated at /docs (Swagger UI) and /redoc.
Development
uv sync --all-extras --dev # install
uv run python -m webgate # run
uv run uvicorn webgate.app:create_app --factory --reload --host 0.0.0.0 --port 8443
# tests
uv run pytest tests/ -v
uv run pytest tests/ -v --cov=webgate
# lint + types
uv run ruff check src/ tests/
uv run ruff format src/ tests/
uv run pyright src/
# build wheel
uv build
Or use the dev compose with a sandboxed SSH target ready to register:
docker compose -f compose.dev.yml up --build
# Inside the UI register: hostname=ssh-demo user=demo password=demo
Tech stack
- Backend: Python 3.11+, FastAPI, uvicorn, asyncssh, SQLAlchemy 2 async, aiosqlite/asyncpg, Pydantic v2, slowapi, ldap3, pyotp, httpx
- Frontend: Alpine.js, xterm.js, CodeMirror 6, vanilla CSS (no build step)
- Storage: SQLite by default, PostgreSQL via
WEBGATE_DB_URL. Credentials encrypted at rest with Fernet - Recording: asciinema cast v2 (JSON Lines), replay via embedded asciinema-player from CDN
- Build/Dev: uv, ruff, pyright, pytest, Docker (multi-stage)
Security
- All SSH passwords and private keys are encrypted at rest with Fernet (key derived from
WEBGATE_SECRET_KEY) - Passwords use bcrypt; sessions use JWT (HS256)
- 2FA TOTP available per user
- API keys for non-interactive auth (
Authorization: Bearer wg_โฆ) - Rate limiting on auth endpoints (slowapi)
- Path traversal validation on every SFTP operation
- Per-server access control โ admins can disable SSH or SFTP independently, restrict SFTP to allow-listed paths, mark SFTP read-only
- Group-based visibility โ non-admin users only see servers in their assigned groups
- HMAC-signed webhooks so receivers can verify the payload came from your webgate
- Recommended: put webgate behind a TLS-terminating reverse proxy (Caddy/nginx/Traefik) in production
Requirements
- Python 3.11+ (or just Docker)
- 256 MB RAM minimum (512 MB recommended)
- ~100 MB disk for the image plus your data (DB + uploaded SSH keys + recordings)
Roadmap
See ROADMAP.md for the full plan and what's shipped per release.
License
MIT โ see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file webgate-0.4.2.tar.gz.
File metadata
- Download URL: webgate-0.4.2.tar.gz
- Upload date:
- Size: 2.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1bbad6084ed7da964e6d75b5642335885b70f2f0497a1adee5181a592c25938
|
|
| MD5 |
12d489ded3c48f15b676eb7453e1d9c1
|
|
| BLAKE2b-256 |
11eb4704a266dd9851e67de816afed4ede43c144adb2391e447b141a8fe398f7
|
File details
Details for the file webgate-0.4.2-py3-none-any.whl.
File metadata
- Download URL: webgate-0.4.2-py3-none-any.whl
- Upload date:
- Size: 80.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bb876a901f3113b1fdebf45f14d43956d4be7fdfde44e43d6e0603f4c8ce132
|
|
| MD5 |
dc07442e48140cea92cb75d1cb2d94e3
|
|
| BLAKE2b-256 |
8f1650f9a7834a54449beb005117394f0c7cc16d6f0c7952709e7786e86f4f27
|