Skip to main content

Self-hosted web application for remote server management via SSH terminal and SFTP file browser

Project description

webgate

PyPI Python License FastAPI Docker Status Tests Docs

Self-hosted web application for remote server management via SSH terminal and SFTP file browser. A modern Python replacement combining the best of webssh and filebrowser into a single unified tool with a FileZilla-inspired interface.

Documentation: kalexnolasco.github.io/webgate

๐ŸŽฎ Live demo: webgate-demo.fly.dev โ€” login demo / demo (read-only, resets hourly)


Why webgate?

Managing remote servers often means juggling SSH clients, SFTP tools, credentials, and VPN configs across your team. In many real-world scenarios, direct SSH access to every server isn't possible -- you only have HTTP/HTTPS access to a single entry point.

The problem

A typical client infrastructure looks like this: a network of internal servers (databases, application servers, workers, etc.) behind a firewall, with only one server exposed via HTTP. Your team needs to manage all of them, but each engineer would need VPN access, local SSH clients, and credential management.

flowchart TB
    subgraph internet ["Internet"]
        YOU["Your Team"]
    end

    subgraph firewall ["Client Firewall"]
        GW["Gateway Server
        (HTTP only)"]

        subgraph internal ["Internal Network"]
            DB1[(PostgreSQL
            10.0.1.10)]
            DB2[(MySQL
            10.0.1.11)]
            APP1["App Server
            10.0.1.20"]
            APP2["App Server
            10.0.1.21"]
            WORKER["Worker
            10.0.1.30"]
            REDIS["Redis
            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 server. Your entire team gets browser-based SSH and SFTP access to every internal server -- no VPN, no local SSH clients, no credential files scattered across laptops.

flowchart TB
    subgraph internet ["Internet"]
        ENG1["Engineer 1
        (Browser)"]
        ENG2["Engineer 2
        (Browser)"]
        ENG3["Engineer 3
        (Browser)"]
    end

    subgraph firewall ["Client Firewall"]
        WG["webgate
        Gateway Server
        :443"]

        subgraph internal ["Internal Network"]
            DB1[(PostgreSQL
            10.0.1.10)]
            DB2[(MySQL
            10.0.1.11)]
            APP1["App Server
            10.0.1.20"]
            APP2["App Server
            10.0.1.21"]
            WORKER["Worker
            10.0.1.30"]
            REDIS["Redis
            10.0.1.40"]
        end
    end

    ENG1 -- "HTTPS" --> WG
    ENG2 -- "HTTPS" --> WG
    ENG3 -- "HTTPS" --> WG
    WG -- "SSH" --> DB1
    WG -- "SSH" --> DB2
    WG -- "SSH" --> APP1
    WG -- "SSH" --> APP2
    WG -- "SSH" --> WORKER
    WG -- "SSH" --> 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
Client with restricted access Deploy on the only HTTP-accessible server, reach all internal machines via SSH/SFTP
On-call / incident response Open a browser from any device, connect instantly -- no laptop with SSH keys needed
Team onboarding Admin creates a user, assigns groups -- new engineer has access in seconds
Audit & compliance Centralized access point, all connections go through one managed gateway
Air-gapped environments Only needs outbound HTTP from the gateway, no inbound ports on internal servers
Multi-client management Run separate webgate instances per client, each with its own server registry

Features

Category Capabilities
SSH Web Terminal Browser-based terminal via xterm.js + asyncssh, resize handling, copy/paste, multi-tab sessions
SFTP File Browser Directory listing, upload/download, drag & drop, rename, delete, mkdir, chmod, breadcrumb navigation
File Editor In-browser text editor powered by CodeMirror 6 with syntax highlighting (oneDark theme)
File Preview PDF viewer, image preview (PNG, JPG, GIF, SVG, WebP) directly in the browser
Server Registry Add/edit/delete servers, groups, tags, password & key auth, test connectivity, import/export, per-server SSH/SFTP toggles
Quick Connect One-off SSH/SFTP connections without saving server config (FileZilla-style toolbar)
Access Control Admin creates users, assigns server groups, enables/disables SSH or SFTP per server, restricts SFTP to specific paths, read-only SFTP mode
Server Monitoring Background SSH connectivity checks every 60s, green/red status dot on server dashboard
Dark/Light Theme Toggle between dark and light themes, saved in localStorage, terminal adapts
Credential Security SSH passwords and private keys encrypted at rest with Fernet (derived from app secret)
Connection Pool SFTP connections are reused per server (5 min TTL), not opened/closed on every request
Upload Progress Visual progress bar with percentage during file uploads
ZIP Download Download entire directories as ZIP archives from the SFTP browser
Keyboard Shortcuts Escape closes modals, Ctrl+1 Site Manager, Ctrl+N New Server
Docker Ready Multi-stage Dockerfile, single-command deployment, health checks, persistent volumes
Responsive Adapts to tablet and mobile screen sizes
Zero Frontend Build Vanilla JS + Alpine.js, no npm/node required, all assets from CDN

Screenshots

Login

Login

Site Manager

Site Manager

SSH Terminal

SSH Terminal

SFTP File Browser

SFTP Browser

File Editor (CodeMirror 6)

Editor

Split View (Terminal + SFTP)

Split View

Access Control (per-server SSH/SFTP toggles + path restrictions)

Access Control

SSH Disabled (button greyed out)

SSH Disabled

SFTP Path Restriction in Action

SFTP Restricted

User Management

Users

Audit Log

Audit

Light Theme

Light Theme

v0.4.0 โ€” Shared Terminal Sessions

Pair-debugging or onboarding from anywhere: the owner clicks ๐Ÿ”— Share in the terminal toolbar, copies the URL, and any colleague who opens it joins the same live session. Output is broadcast to every participant; any RW participant can type.

Owner Joiner
Owner view Joiner view

The ?join=<token> URL parameter is recognized after login -- a joiner can be sent the URL directly even if they aren't logged in yet.

v0.3.x โ€” Operations Pack

These screenshots come from the live demo at https://webgate-demo.fly.dev (login demo / demo).

Demo banner on login

Demo banner

Site Manager with jump-host indicator

The โ†บ next to internal-app means it tunnels through bastion.

Dashboard with jump host

Terminal with snippets toolbar

Click a snippet button to send command + Enter to the active session. Right-click to delete, + to create.

Terminal snippets

Snippet executed

Clicking ls -lah sent the command and the output appears in the terminal.

Snippet executed

SFTP via jump host

Browsing the internal-app filesystem โ€” the SFTP connection is also tunneled through the bastion.

SFTP via jump

Webhooks management (admin)

Per-event subscription, optional HMAC signing, last delivery status.

Webhooks modal

Add Server form with Jump Via dropdown

Pick any other registered server as the bastion.

Add Server with Jump Via

Quick Start

Docker (recommended)

# Clone and run
git clone https://gitlab.wdna.com/wdna/webgate.git
cd webgate
docker compose up -d

# Open http://localhost:8443
# Login with admin / admin (you'll be asked to change the password)

Important: On first launch, webgate creates a default admin / admin account. You will be forced to change the password on first login. Set a strong secret key in production:

WEBGATE_SECRET_KEY=$(openssl rand -hex 32) docker compose up -d

Development with SSH demo server

A compose.dev.yml is included with a demo SSH container for testing:

docker compose -f compose.dev.yml up -d
# webgate at :8443 + SSH demo server (user: demo, password: demo)

Local Development

# Install dependencies
uv sync

# Run dev server with auto-reload
uv run uvicorn webgate.app:create_app --factory --reload --host 0.0.0.0 --port 8443

# Or simply
uv run python -m webgate

User Management

webgate uses a role-based access model with two roles: admin and user.

How it works

flowchart LR
    ADMIN["Admin"] -->|creates| SERVERS["Servers
    (grouped)"]
    ADMIN -->|creates| USERS["Users"]
    ADMIN -->|assigns groups to| USERS

    USERS -->|can access| ALLOWED["Servers in
    allowed groups"]

    style ADMIN fill:#5cb85c,stroke:#449d44,color:#fff
    style SERVERS fill:#e8f0fe,stroke:#4a90d9
    style USERS fill:#fff3e0,stroke:#ff9800
    style ALLOWED fill:#f0f9e8,stroke:#5cb85c
Admin User
Add/edit/delete servers Yes No
Enable/disable SSH or SFTP per server Yes No
Restrict SFTP to specific paths Yes No
Create/delete users Yes No
Assign groups to users Yes No
See all servers Yes Only servers in assigned groups
SSH terminal (if enabled on server) Yes Yes (allowed servers only)
SFTP file browser (if enabled, within allowed paths) Yes Yes (allowed servers only)
Quick Connect Yes Yes

Example workflow

  1. Admin logs in (default admin/admin, forced to change password)
  2. Admin adds servers and organizes them into groups (production, staging, dev)
  3. Admin creates users and assigns groups:
    • alice -> production, staging (senior engineer)
    • bob -> staging, dev (junior, no prod access)
    • charlie -> production (read-only ops, only prod)
  4. Each user logs in and sees only the servers in their assigned groups

Architecture

webgate/
โ”œโ”€โ”€ src/webgate/
โ”‚   โ”œโ”€โ”€ __main__.py          # Entry point: uvicorn launcher
โ”‚   โ”œโ”€โ”€ app.py               # FastAPI app factory, lifespan, middleware
โ”‚   โ”œโ”€โ”€ config.py            # Pydantic Settings (env vars, defaults)
โ”‚   โ”œโ”€โ”€ auth/                # JWT auth, user management, admin routes
โ”‚   โ”‚   โ”œโ”€โ”€ models.py        # User model + Pydantic schemas
โ”‚   โ”‚   โ”œโ”€โ”€ service.py       # Password hashing, JWT, seed_admin, CRUD
โ”‚   โ”‚   โ””โ”€โ”€ routes.py        # Login, change-password, admin user CRUD
โ”‚   โ”œโ”€โ”€ servers/             # Server registry CRUD, connectivity test
โ”‚   โ”‚   โ”œโ”€โ”€ models.py        # Server model + schemas
โ”‚   โ”‚   โ”œโ”€โ”€ service.py       # CRUD with group-based filtering
โ”‚   โ”‚   โ””โ”€โ”€ crypto.py        # Fernet encrypt/decrypt for credentials
โ”‚   โ”œโ”€โ”€ terminal/            # WebSocket SSH bridge (xterm.js <-> asyncssh)
โ”‚   โ”œโ”€โ”€ files/               # SFTP operations with connection pooling
โ”‚   โ”‚   โ”œโ”€โ”€ sftp_service.py  # SFTP client wrapper
โ”‚   โ”‚   โ”œโ”€โ”€ pool.py          # Connection pool (reuse per server, 5min TTL)
โ”‚   โ”‚   โ””โ”€โ”€ routes.py        # REST API: ls, read, write, upload, download, chmod
โ”‚   โ”œโ”€โ”€ db/                  # SQLAlchemy async engine + session factory
โ”‚   โ””โ”€โ”€ static/              # Frontend (single index.html, FileZilla-style UI)
โ”œโ”€โ”€ tests/
โ”œโ”€โ”€ Dockerfile               # Multi-stage build (python:3.13-slim)
โ”œโ”€โ”€ Dockerfile.ssh-demo      # Demo SSH container for development
โ”œโ”€โ”€ compose.yml              # Production deployment
โ”œโ”€โ”€ compose.dev.yml          # Development with SSH demo server
โ””โ”€โ”€ pyproject.toml
flowchart LR
    subgraph Browser
        XT[xterm.js] --> WS[WebSocket]
        UI[Alpine.js UI] --> REST[REST API]
        CM[CodeMirror] --> REST
    end

    subgraph webgate ["webgate (FastAPI)"]
        WS --> SSH[asyncssh Session]
        REST --> POOL[SFTP Pool]
        POOL --> SFTP[asyncssh SFTP]
        REST --> DB[(SQLite)]
        REST --> AUTH[JWT Auth]
    end

    SSH --> RS[Remote Server]
    SFTP --> RS

    style Browser fill:#e8f0fe,stroke:#4a90d9
    style webgate fill:#f0f9e8,stroke:#5cb85c
    style RS fill:#fff3e0,stroke:#ff9800

API Reference

Auth

Method Endpoint Description
POST /api/auth/login Login, returns JWT token
GET /api/auth/me Current user info (includes must_change_password)
POST /api/auth/change-password Change own password
GET /api/auth/users List all users (admin only)
POST /api/auth/users Create user with allowed groups (admin only)
PUT /api/auth/users/{id}/groups Update user's allowed groups (admin only)
PUT /api/auth/users/{id}/password Reset user's password (admin only)
DELETE /api/auth/users/{id} Delete user (admin only)
GET /api/auth/audit Audit log with filters (admin only)

Server Registry

Method Endpoint Description
GET /api/servers List servers (filtered by user's allowed groups)
POST /api/servers Create server (admin only)
GET /api/servers/{id} Server details
PUT /api/servers/{id} Update server (admin only)
DELETE /api/servers/{id} Delete server (admin only)
POST /api/servers/{id}/test Test SSH connectivity
GET /api/servers/groups List groups (filtered by user's access)
POST /api/servers/import Bulk import (admin only)
GET /api/servers/export Export all servers (admin only)

Terminal (WebSocket)

Method Endpoint Description
WS /api/ws/terminal/{server_id} SSH terminal to saved server
WS /api/ws/terminal/quick Quick connect with inline credentials

SFTP File Manager

Method Endpoint Description
GET /api/files/{id}/ls?path= Directory listing
GET /api/files/{id}/read?path= Read text file
GET /api/files/{id}/download?path= Download file
POST /api/files/{id}/upload?path= Upload files (multipart)
PUT /api/files/{id}/write Save text file
POST /api/files/{id}/mkdir Create directory
POST /api/files/{id}/rename Rename/move
DELETE /api/files/{id}/delete?path= Delete file/directory
POST /api/files/{id}/chmod Change permissions
GET /api/files/{id}/stat?path= File metadata

Health

Method Endpoint Description
GET /api/health Health check ({"status": "ok"})

Configuration

All settings are configurable via environment variables with the WEBGATE_ prefix:

Variable Default Description
WEBGATE_HOST 0.0.0.0 Server bind address
WEBGATE_PORT 8443 Server port
WEBGATE_SECRET_KEY change-me-in-production JWT signing + Fernet encryption key
WEBGATE_DB_URL sqlite+aiosqlite:///./webgate.db Database URL
WEBGATE_ALLOWED_ORIGINS * CORS origins (comma-separated)
WEBGATE_ROOT_PATH `` (empty) URL prefix when served behind a reverse proxy at a sub-path (e.g. /webgate)
WEBGATE_DEMO_MODE false Read-only public demo: blocks all writes, seeds a demo/demo user and shows a banner

PostgreSQL

SQLite is the default. To use PostgreSQL, just point WEBGATE_DB_URL at it (the asyncpg driver is bundled as of v0.3.1):

export WEBGATE_DB_URL='postgresql+asyncpg://user:pass@host:5432/webgate'

Lightweight migrations are dialect-aware. Schema is created automatically on first start.

Jump host / bastion

When adding a server, pick another server from the Jump Via dropdown to tunnel the SSH and SFTP connections through it. Useful when the target server is only reachable from a specific bastion. Stored as jump_via_id (FK to another Server row); asyncssh's native tunnel= parameter does the actual chaining.

SSH command snippets

Each user has a personal library of named commands. They appear as buttons in the terminal toolbar -- click to send command + Enter. Right-click to delete, + to create. Stored in the snippets table.

Webhooks

Admins can register HTTPS endpoints that receive a JSON POST when events fire (user_login, ssh_connect, server_added, etc). Each webhook can subscribe to all events (*) or a specific subset.

POST https://your-receiver.example.com/wh
Content-Type: application/json
X-Webgate-Signature: sha256=<hmac of body using your webhook's secret>

{"event": "ssh_connect", "timestamp": "2026-04-15T18:03:18Z",
 "data": {"user": "alice", "server": "prod-web-01", "host": "10.0.1.50:22"}}

Manage from the Webhooks button in the top toolbar (admin only). Last delivery status is shown next to each row. | WEBGATE_LOG_LEVEL | info | Log level | | WEBGATE_SESSION_TIMEOUT | 3600 | SSH session 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 hours) | | WEBGATE_MONITOR_INTERVAL | 60 | Server status check interval (seconds) | | WEBGATE_MONITOR_TIMEOUT | 5 | SSH connect timeout for checks (seconds) | | WEBGATE_MONITOR_CONCURRENCY | 10 | Max parallel status checks |

Docker

Build and Run

docker compose up -d
# Login at http://localhost:8443 with admin / admin

Production with TLS (Caddy reverse proxy)

# compose.yml
services:
  webgate:
    build: .
    container_name: webgate
    restart: unless-stopped
    ports:
      - "8443:8443"
    volumes:
      - webgate-data:/data
    environment:
      WEBGATE_SECRET_KEY: "${WEBGATE_SECRET_KEY}"

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy-data:/data

volumes:
  webgate-data:
  caddy-data:
# Caddyfile
webgate.example.com {
    reverse_proxy webgate:8443
}

Reverse proxy at a sub-path (e.g. https://example.com/webgate/)

When webgate is exposed behind an existing site under a URL prefix, set WEBGATE_ROOT_PATH so FastAPI and the frontend both build URLs with the prefix. The frontend derives the prefix automatically from window.location.pathname, but WEBGATE_ROOT_PATH is still needed on the backend for OpenAPI URLs.

Docker Compose:

services:
  webgate:
    image: kalexnolasco/webgate:latest
    environment:
      WEBGATE_SECRET_KEY: "${WEBGATE_SECRET_KEY}"
      WEBGATE_ROOT_PATH: "/webgate"

Important: the reverse proxy must forward the prefix unchanged (not strip it). Webgate receives requests as /webgate/api/... and handles them natively โ€” do not rewrite them to /api/....

nginx

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 (xterm.js terminal) -- 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;   # keep long-lived SSH sessions alive
        proxy_send_timeout 86400s;
    }

    location /webgate/ {
        proxy_pass http://127.0.0.1:8443;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Prefix /webgate;
        client_max_body_size 100m;       # match WEBGATE_MAX_UPLOAD_SIZE
    }
}

Apache 2.4

# Required modules: proxy proxy_http proxy_wstunnel headers rewrite ssl
# sudo a2enmod proxy proxy_http proxy_wstunnel headers rewrite

<VirtualHost *:443>
    ServerName example.com

    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key

    ProxyPreserveHost On
    RequestHeader set X-Forwarded-Proto  "https"
    RequestHeader set X-Forwarded-Prefix "/webgate"

    # Redirect /webgate -> /webgate/ (trailing slash)
    RewriteEngine On
    RewriteRule ^/webgate$ /webgate/ [R=301,L]

    # WebSocket (xterm.js terminal) -- MUST come before the HTTP ProxyPass
    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/

    # HTTP
    ProxyPass        /webgate/  http://127.0.0.1:8443/webgate/
    ProxyPassReverse /webgate/  http://127.0.0.1:8443/webgate/
</VirtualHost>

Traefik (labels)

services:
  webgate:
    image: kalexnolasco/webgate:latest
    environment:
      WEBGATE_ROOT_PATH: "/webgate"
    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"

Traefik forwards the full path by default, so no extra middleware is needed. Long WebSocket timeouts can be tuned via forwardingTimeouts in the Traefik static config.

Useful Commands

docker compose logs -f webgate    # View logs
docker compose down               # Stop (data preserved)
docker compose down -v            # Stop + delete data (fresh start)
docker compose build --no-cache   # Rebuild from scratch

Development

# Install with dev dependencies
uv sync

# Run with auto-reload
uv run uvicorn webgate.app:create_app --factory --reload --host 0.0.0.0 --port 8443

# Run with demo SSH server
docker compose -f compose.dev.yml up -d

# Lint & format
uv run ruff check src/ tests/
uv run ruff format src/ tests/

# Type check
uv run pyright src/

# Test
uv run pytest tests/ -v

# Test with coverage
uv run coverage run -m pytest tests/ -v && uv run coverage report

Tech Stack

Layer Technology
Backend Python 3.11+, FastAPI, uvicorn, asyncssh, SQLAlchemy, aiosqlite, Pydantic v2
Auth JWT (python-jose), bcrypt, Fernet (cryptography), slowapi (rate limiting)
Frontend Vanilla JS, Alpine.js, xterm.js, CodeMirror 6
Database SQLite (default), any SQLAlchemy-supported DB
Container Docker, multi-stage build, python:3.13-slim

Security

  • Default admin password forced change -- admin/admin is temporary, must be changed on first login
  • SSH credentials encrypted at rest with Fernet (key derived from WEBGATE_SECRET_KEY)
  • JWT authentication with configurable expiry
  • Group-based access control -- users only see servers in their assigned groups
  • Per-server feature control -- admin can disable SSH or SFTP independently per server
  • SFTP path restrictions -- admin can lock SFTP to specific directories per server
  • SFTP read-only mode -- admin can set per-server read-only flag, blocking all write operations
  • SFTP path traversal protection (server-side normalization and validation)
  • CORS configurable per deployment
  • No plaintext password storage (user passwords hashed with bcrypt)
  • Admin-only server management -- regular users cannot add, edit, or delete servers

Roadmap

Completed (v0.1.x)

  • SSH web terminal (xterm.js + asyncssh)
  • SFTP file browser with full CRUD
  • Server registry with groups and tags
  • In-browser text editor (CodeMirror 6)
  • PDF and image preview
  • Quick connect toolbar
  • Docker deployment
  • JWT authentication with forced password change
  • Fernet credential encryption
  • Admin user management with group-based access
  • SFTP connection pool (reuse connections, 5 min TTL)
  • Multi-tab split pane (terminal + files side by side)
  • SSH key management (per-server key upload with visual indicator)
  • File search / filter within SFTP listings
  • Server import/export from UI (JSON)
  • Session persistence across page reloads
  • Rate limiting on auth endpoints (slowapi)
  • Audit log (admin-viewable action history)
  • Per-server SSH/SFTP toggles (admin can enable/disable each feature)
  • SFTP path restrictions (admin can limit access to specific directories)

Completed (v0.2.x)

  • SFTP read-only mode per server (browse and download only)
  • Server status monitoring (background SSH checks, green/red dot)
  • Dark/light theme toggle with localStorage persistence
  • Responsive tablet/mobile layout
  • Keyboard shortcuts (Escape, Ctrl+1, Ctrl+N)
  • Upload progress bar with percentage
  • Folder download as ZIP

Planned (v0.3.x -- Collaboration & Ops)

  • Shared terminal sessions (multiple users watching the same session)
  • Session recording and playback (audit/training)
  • SSH command snippets/macros (saved per server or global)
  • Webhook/notifications on connection events
  • Two-factor authentication (TOTP)
  • LDAP/Active Directory integration
  • API key authentication (for automation/scripts)

Planned (v0.4.x -- Enterprise)

  • PostgreSQL support (tested and documented)
  • Multi-instance deployment with shared DB
  • SSH jump host / bastion support (ProxyCommand equivalent)
  • Custom branding (logo, colors, company name)
  • Backup/restore UI for server registry
  • Internationalization (i18n)

Requirements

  • Python 3.11+
  • Linux, macOS, or WSL (asyncssh requires Unix-like OS)
  • Target servers must have SSH enabled

License

MIT


webgate -- Remote server management, simplified.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

webgate-0.4.0.tar.gz (2.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

webgate-0.4.0-py3-none-any.whl (73.9 kB view details)

Uploaded Python 3

File details

Details for the file webgate-0.4.0.tar.gz.

File metadata

  • Download URL: webgate-0.4.0.tar.gz
  • Upload date:
  • Size: 2.0 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

Hashes for webgate-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f49366ee9d8384741ad488fdf2f07fd28a5e52747eeff49a93c72cc3be1c448c
MD5 21a7da17cb736f8712f40f3b4f8f436c
BLAKE2b-256 9224744212e09a2eac475266ef06d9cd9dbc33c4fa94f0fad8fa37b410d4a481

See more details on using hashes here.

File details

Details for the file webgate-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: webgate-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 73.9 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

Hashes for webgate-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1e1b20597296555b3d84da661960de909259d21da9e02faefe8191500bbc2520
MD5 209a96ee496cb32640459566481bc655
BLAKE2b-256 416fe1ffce13fbfb20b71d2b49b7be50f07ccd9d3b887b7b5061e053d5c827aa

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page