Skip to content

casudo/KiwiSSH

Logo

KiwiSSH

Backup your network device configurations with ease and keep track of changes.

GitHub License GitHub release (with filter) GitHub action checks GitHub issues GitHub last commit

About KiwiSSH

KiwiSSH is a network device configuration backup tool that connects to your devices via SSH, fetches their configurations, and stores them in git repositories for easy version control and change tracking. It also provides a user-friendly web interface to manage your devices, view backup logs, and see configuration changes over time.

It was created as better alternative to RANCID and Oxidized, with a focus on simplicity, ease of use, and modern technologies.

Warning

KiwiSSH is still in early development and may contain bugs and support for only a limited number of vendors. If you want to collaborate, contribute or just have questions, please open an issue or PR.

Table of Contents

Features

The frontend offers:

  • Dashboard (statistics, favorite devices, overview of KiwiSSH)
  • Information-rich device List with filtering, search and favorite option, backup contribution calender, group and vendor belonging , status badge, config diff view and more
  • Overview of configured SSH profiles, vendors and groups for easy management and device tracking
  • Detailed backup job logs with timestamps, status and error messages for each backup attempt
  • Swagger API documentation

The backend provides:

  • SSH connectivity to network devices for configuration backup
  • Configurable backup schedules with cron expressions on global, group and device level
  • Local git repositories for each device group to store configuration history and provide diff view
  • Optional remote git repository support to push configuration changes to a central Git server (e.g. GitHub, GitLab, Gitea, etc.)
  • Support for loading device lists from CSV files or PostgreSQL databases
  • Configurable SSH options and backup commands per vendor, group and device
  • Configurable processing rules for captured configurations, including line stripping, cropping and regex-based redaction of sensitive information
  • The ability to easily add support for new vendors by creating YAML configuration files that define how to interact with the device CLI and process the output
  • RESTful API endpoints for device management, backup job logs and configuration retrieval to enable integration with other tools and automation

Supported OS/Device Types

For a detailed overview of supported OS/Device types, please refer to the OS_TYPES.md file.

Screenshots

Note

Screenshots as of version v1.0.0

Dashboard

Device List

Vendors

Groups

SSH Profiles

Backup Job Logs


Installation

Bare Metal

To run KiwiSSH on your local machine without Docker, follow these steps:

  1. Clone the repository
  2. Navigate to the backend directory and install the required Python dependencies from requirements.txt
  3. Set up the kiwissh.yaml configuration file in the config/ directory
  4. Run the backend using python entrypoint.py
  5. Navigate to the frontend directory and install the dependencies with npm install
  6. Start the frontend with npm run dev

Docker

KiwiSSH uses separate Docker images for backend and frontend.

  • Backend: FastAPI API service
  • Frontend: Nginx serving the built Vue app and proxying /api/* to backend
  1. Update the docker-compose.yaml.example with the correct image tags for backend and frontend and set your desired environment variables (optional) and volume mounts. You can find an overview of all available environment variables here in the README or in the example .env file.
  2. Run the docker-compose.yaml.example file
  3. Open the UI at http://<IP>:8123

Important

If you're using SSH key authentication (remote git push, device backup auth, or jumphost auth), mount your SSH material into /home/kiwissh/.ssh and ensure permissions are correct (typically 600 for private keys/config/known_hosts, owned by kiwissh uid:gid 1000:1000).

Note

  • API calls are available through the frontend proxy: http://<IP>:8123/api/v1/...
  • The backend image includes default ssh_profiles.yaml and vendors/*.yaml directly in /config
  • The backend always reads configuration from /config
  • You still need a valid kiwissh.yaml in /config and should persist backups/ on a host volume

Configuration

KiwiSSH can be configured using a combination of environment variables and a YAML configuration file. The YAML file contains the main configuration settings, while environment variables are used to define global, application-unspecific values for different deployments.

Environment Variables

See the example backend/.env.example file. Either rename it to .env and fill in the values or set the environment variables directly in your deployment environment (e.g. Docker, systemd, etc.). KiwiSSH will automatically load these environment variables on startup.

Variable Name Description Required Default Value
KIWISSH_LOCAL_TEST_MODE If set to true, the application will run in local test mode, which enforces certain config values for easier local testing and development. No false
TZ Timezone for the application. This is used for timestamps in backup job logs and Git commit messages. No UTC

kiwissh.yaml

Found at /config/kiwissh.yaml

Below you'll find a detailed overview of all available configuration options in the kiwissh.yaml file. This file is the main configuration file for KiwiSSH and contains settings for the application, database connection, device sources, git integration, groups and nodes.

Important

Changes to the kiwissh.yaml file will require a restart of the backend and frontend applications to take effect.

app

Full available options:

Key Description Required Default Value
app.debug If set to true, the application will run in debug mode, which enables more verbose logging No false
app.threads The maximum number of concurrent SSH sessions for backups. No 20
app.timeout The global connection timeout in seconds. This can be overridden for specific groups or nodes. No 30
app.retry The global retry count, which defines how many additional attempts should be made after the first failed attempt. This can also be overridden for specific groups or nodes. No 3
app.protocol Default protocol for device connections (ssh or telnet). No ssh
app.api.host The host on which the API server will run. Should be set to 0.0.0.0 when running in Docker. No 127.0.0.1
app.api.port The port on which the API server will run. No 8000
app.api.cors_origins A list of allowed CORS origins for the API server. No ["http://localhost:5173", "http://127.0.0.1:5173"]
app.schedule.cron The cron expression for the global backup schedule. No 0 2 * * *
app.schedule.TZ The timezone for the backup schedule. No TZ environment variable or UTC

application_database

The application_database segment is used to configure the connection to the PostgreSQL database where KiwiSSH will store its application data (e.g. backup job logs, favorite devices, etc.). This database is required for KiwiSSH to function properly.

Important

Make sure that the database exists and that the provided user has the necessary permissions to create tables and perform operations on the database. KiwiSSH will automatically create the required tables on startup.

Key Description Required Default Value
application_database.host The host of the PostgreSQL database. Yes -
application_database.port The port of the PostgreSQL database. No 5432
application_database.database The name of the PostgreSQL database. Yes -
application_database.username The username for the PostgreSQL database. Yes -
application_database.password The password for the PostgreSQL database. Yes -

sources

Configure where KiwiSSH load the devices to backup from. You can choose between loading the devices from a CSV file or from a PostgreSQL database.

Important

At least one source must be configured. The following columns are required in the device source: group, device_name, ip_address, enabled.

File

Key Description Required Default Value
sources.file The absolute path to the CSV file containing the device entries. Yes -

The devices will be loaded from the specified CSV file. The headers must be seperated by commas like this:

group,device_name,ip_address,enabled
prod-firewalls,firewall-prod-01,10.50.240.100,true
prod-firewalls,firewall-prod-02,10.50.240.101,true
test-firewalls,firewall-test-01,10.60.194.10,true
test-firewalls,firewall-test-02,10.60.194.11,true
spine-switches,dc-spine-01,172.16.37.2,true
spine-switches,dc-spine-02,172.16.37.3,true
leaf-switches,dc-leaf-01,172.16.37.4,true
leaf-switches,dc-leaf-02,172.16.37.5,true
leaf-switches,dc-leaf-03,172.16.37.5,true
leaf-switches,dc-leaf-04,172.16.37.6,true
dev-rack,test-c8200-1n-4t,192.168.5.1,true
dev-rack,marketing-catalyst-24p,192.168.5.2,true
dev-rack,sales-catalyst-24p,192.168.5.3,false

PostgreSQL

Important

Make sure that the database exists and that the provided user has the necessary permissions to read from the database.

Key Description Required Default Value
sources.postgres.host The host of the PostgreSQL database containing the device entries. Yes -
sources.postgres.port The port of the PostgreSQL database containing the device entries. No 5432
sources.postgres.database The name of the PostgreSQL database containing the device entries. Yes -
sources.postgres.table The name of the PostgreSQL table containing the device entries. Yes -
sources.postgres.username The username for the PostgreSQL database containing the device entries. Yes -
sources.postgres.password The password for the PostgreSQL database containing the device entries. Yes -

The backup_jobs table can grow quite large over time depending on the number of devices and backup frequency. To prevent the database from growing indefinitely, it's recommended to set up a regular maintenance job to clean up old backup job logs that are no longer needed. This can be done using a simple SQL query to delete old records based on a retention policy (e.g., delete logs older than 90 days). We might implement this as a built-in feature in the future, but for now it's up to the user to set this up.

Tip

Consider backing up your PostgreSQL database(s) regularly, independently of KiwiSSH. We recommend Databasus for that.

git

KiwiSSH will always store the device configurations in local git repositories to provide diff view, history and download options. You can optionally set a remote git location to push the commits (the device config) to.

Caution

DO NOT delete the "backups" folder ever unless you want to lose all your local git repositories and their history.

Key Description Required Default Value
git.local_path The local path where the git repositories for the device groups will be stored. No /config/backups
git.commit_message_template The global template for the git commit messages. Available placeholders: {group}, {device_name}, {timestamp}. No "Backup: {group}/{device_name} at {timestamp}"
git.remote.url The global remote git repository URL. Available placeholders: {group}. This can be overridden for specific groups. No -
git.remote.branch The global remote git branch to push to. This can be overridden for specific groups. No main

groups

Key Description Required Default Value
groups.<group>.username The username for SSH authentication for devices in this group. Yes -
groups.<group>.password The password for SSH authentication for devices in this group (optional when ssh_key_file is used). No -
groups.<group>.enable_password Optional enable password for devices in this group. Vendor YAML then values can reference it with {{ enable_password }}. No -
groups.<group>.ssh_key_file The private key file path for SSH authentication for devices in this group (alternative to password). No -
groups.<group>.ssh_profile The SSH profile to use for devices in this group. This is used to determine the SSH options to use when connecting to the devices. Yes -
groups.<group>.protocol Protocol to use for devices in this group (ssh or telnet). No Global app.protocol
groups.<group>.port Protocol port for devices in this group. No 22 (or 23 when protocol: telnet)
groups.<group>.vendor The vendor of the devices in this group. This is used to determine the CLI commands to run for fetching the configuration. Yes -
groups.<group>.jumphost.hostname Jumphost hostname or IP for this group. If set, devices in this group are reached through this jumphost. Yes, if jumphost -
groups.<group>.jumphost.port Jumphost SSH port. No 22
groups.<group>.jumphost.username Jumphost SSH username. Yes, if jumphost -
groups.<group>.jumphost.password Jumphost SSH password (optional when groups.<group>.jumphost.ssh_key_file is used). No -
groups.<group>.jumphost.ssh_key_file Jumphost private key file path (alternative to jumphost password). No -
groups.<group>.jumphost.ssh_profile SSH profile for the jumphost connection. This is separate from groups.<group>.ssh_profile (device connection profile) and is required when a jumphost is configured. Yes, if jumphost -
groups.<group>.timeout The SSH timeout in seconds for devices in this group. This overrides the global SSH timeout. No Global app.timeout
groups.<group>.retry The SSH retry count for devices in this group. This overrides the global SSH retry count. No Global app.retry
groups.<group>.schedule.cron The cron expression for the backup schedule for devices in this group. This overrides the global backup schedule. No Global app.schedule.cron
groups.<group>.git.commit_message_template The git commit message template for this group. This overrides global git.commit_message_template. No Global git.commit_message_template
groups.<group>.git.remote.url The remote git repository URL for this group. This overrides the global git.remote.url. No Global git.remote.url or if set globally
groups.<group>.git.remote.branch The remote git branch to push to for this group. This overrides the global git.remote.branch. No Global git.remote.branch if set globally

nodes

Important

Group cannot be overridden on node level.

Key Description Required Default Value
nodes.<device_name>.username The username for SSH authentication for this device. No groups.<group>.username
nodes.<device_name>.password The password for SSH authentication for this device. No groups.<group>.password
nodes.<device_name>.enable_password Optional enable password for this device. This overrides groups.<group>.enable_password and can be referenced from vendor YAML then values with {{ enable_password }}. No groups.<group>.enable_password
nodes.<device_name>.ssh_key_file The private key file path for SSH authentication for this device. No groups.<group>.ssh_key_file
nodes.<device_name>.ssh_profile The SSH profile to use for this device. This is used to determine the SSH options to use when connecting to the device. No groups.<group>.ssh_profile
nodes.<device_name>.protocol Protocol override for this device (ssh or telnet). No groups.<group>.protocol or Global app.protocol
nodes.<device_name>.port Port override for this device. No groups.<group>.port or 22 (or 23 when protocol: telnet)
nodes.<device_name>.vendor The vendor of this device. This is used to determine the CLI commands to run for fetching the configuration. No groups.<group>.vendor
nodes.<device_name>.jumphost.hostname Node-level jumphost hostname/IP override. Yes, if jumphost groups.<group>.jumphost.hostname
nodes.<device_name>.jumphost.port Node-level jumphost SSH port override. No groups.<group>.jumphost.port or 22
nodes.<device_name>.jumphost.username Node-level jumphost username override. Yes, if jumphost groups.<group>.jumphost.username
nodes.<device_name>.jumphost.password Node-level jumphost password override. No groups.<group>.jumphost.password
nodes.<device_name>.jumphost.ssh_key_file Node-level jumphost key file override. No groups.<group>.jumphost.ssh_key_file
nodes.<device_name>.jumphost.ssh_profile Node-level jumphost SSH profile override. Yes, if jumphost groups.<group>.jumphost.ssh_profile
nodes.<device_name>.timeout The SSH timeout in seconds for this device. This overrides the group and global SSH timeout. No groups.<group>.timeout or Global app.timeout
nodes.<device_name>.retry The SSH retry count for this device. This overrides the group and global SSH retry count. No groups.<group>.retry or Global app.retry
nodes.<device_name>.schedule.cron The cron expression for the backup schedule for this device. This overrides the group and global backup schedule. No groups.<group>.schedule.cron or Global app.schedule.cron
nodes.<device_name>.git.commit_message_template The git commit message template for this device. This overrides group and global git commit templates. No groups.<group>.git.commit_message_template or global git.commit_message_template

Vendor folder

Found at /config/vendors

Vendor YAML files define how KiwiSSH interacts with each device CLI and how captured output is processed before it is saved.

Important

Only the {{ enable_password }} placeholder is supported, and only in then values. If it resolves to an empty string (""), KiwiSSH sends Enter.

Tip

You can create your own vendor YAML file by copying one of the existing ones and modifying it according to the CLI output of your devices. If you want to contribute your vendor file to the project, please create a Pull Request with the new vendor YAML file in the config/vendors folder.

Important

You should read the contents of the vendor YAML files for the device types you want to backup to understand which CLI commands are used to fetch the configuration and how the output is processed. You can always add your own processing.strip_patterns or redaction.patterns to further customize the output processing for your specific devices if needed.

Vendor YAML file

Each vendor file contains these top-level sections:

  • vendor: metadata (id, name, description)
  • session: session-level output settings (comment_prefix, prompt, pagination, include_metadata_in_config)
  • commands: command phases (pre_backup, backup, post_backup); you can nest protocol-specific overrides under commands.ssh or commands.telnet
  • processing: optional output cleanup/redaction rules

Each segment is explained in detail below.

[TIP] You can override the vendor for a specific device in kiwissh.yaml under nodes.<device_name>.vendor.

vendor

Key Description Required Default Value
vendor.id A unique identifier for the vendor. Yes -
vendor.name The name of the vendor. Yes -
vendor.description A brief description of the vendor. No -

session

Key Description Required Default Value
session.comment_prefix If set, command outputs will be prefixed with this string and rendered as comments in the saved config file. This is useful for adding metadata like command descriptions or timestamps directly in the config file. No !
session.prompt Optional prompt regex (or list of regexes) used to detect command completion in interactive shells. Match should cover the full prompt line. If omitted or invalid, KiwiSSH falls back to the built-in generic prompt pattern. No [^\r\n=]*[A-Za-z0-9][^\r\n=]*[>#]\s*$
session.pagination.enabled Enables pagination prompt handling for this vendor. No false
session.pagination.patterns Pagination pattern config. Supports a string, a list of regex strings, or a list of objects like { pattern: "...", response: "..." }. Matching uses contains-style regex search against the normalized output line. When using object entries, response is configured per pattern and should be preferred. If session.pagination is omitted entirely, KiwiSSH falls back to built-in standard pagination detection patterns. No Built-in standard pagination pattern list
session.include_metadata_in_config Controls whether outputs from metadata: true commands are prepended as a block in the saved config. Metadata is always present in the backup job log. No false

commands

Key Description Required Default Value
commands.<phase> A list of commands to run in the specified phase. Supported phases are pre_backup, backup, and post_backup. Yes -

Steps run in a single interactive shell session in this order: pre_backup -> backup -> post_backup

Each item in the commands.<phase> list follows this structure:

commands:
  backups:
    - command: "show running-config" # simple command
      description: "Get running configuration"
    - command: "another command here" # another simple command
    - command: "enable" # interactive command
      then: ["{{ enable_password }}"]
    - command: "logout" # another interactive command
      then:
        - "y"
        - "n"

You can use the following keys for each command step:

Key Description Required Default Value
command Directly run the command on the device. Yes -
then Optional interactive input sequence to send after command. Must be a YAML list (then: ["value1", "value2", ...]) with up to 5 entries. Empty strings are sent as Enter. String values may use {{ enable_password }} to inject the device enable password. No -
description A brief description of the command. No -
metadata If set to true, the output of this command will be saved as comment-prefixed metadata block in the backup job log. This is useful for adding important information to the backup job log. No false
wait_for_prompt If set to false, KiwiSSH will not wait for the command prompt to return after running this command before proceeding to the next step. Use with caution. No true
show_command_in_config If set to true, the command will be included directly in the main config body above its output, prefixed with the comment prefix. This provides better context for the captured output when viewing the saved config file. show_command_in_config: true and metadata: true cannot be used together and will fail validation. No false

processing

Key Description Required Default Value
processing.strip_patterns A list of regex patterns. Lines matching any of these patterns will be removed from the captured config before saving. No -
processing.config_start A regex pattern that marks the start of the actual configuration in the CLI output. Lines before the matched line will be removed. No -
processing.config_end A regex pattern that marks the end of the actual configuration in the CLI output. Lines after the matched line will be removed. No -
processing.redaction.enabled If set to true, the patterns defined in processing.redaction.patterns will be applied to the captured config to redact sensitive information. No false
processing.redaction.patterns A list of redaction rules. Each rule should contain a search regex pattern, a replacement string, and an optional ignore_case boolean. No -

Important

If ignore_case is set to true for a redaction rule (default is false), the search pattern will be applied in a case-insensitive manner. Make sure to set this according to the expected CLI output of your devices to ensure effective redaction.

Processing behavior:

  • processing is optional; if no processing options are configured, config output is left unchanged
  • strip_patterns: remove matching lines
  • config_start / config_end: crop output to boundaries; if one side is missing, file edge is used
  • redaction.enabled + redaction.patterns: apply replacements
  • Each redaction rule uses search, replacement, and optional ignore_case

SSH Profiles YAML file

Found at /config/ssh_profiles.yaml

SSH profiles define reusable options for SSH connections. Assign a profile via groups.<group>.ssh_profile and optionally override it per device with nodes.<device_name>.ssh_profile.

Note

Notes for the usage of known_hosts_policy: strict validates against ~/.ssh/known_hosts ignore skips known-host validation (mapped to known_hosts: None in AsyncSSH) auto_add currently falls back to ignore and logs a warning Device and jumphost connections can use separate profiles (ssh_profile for devices, jumphost.ssh_profile for jumphosts) Port and timeout are configured in group/node/app settings, not in SSH profiles

You can create your own SSH profile by adding a new entry to the ssh_profiles.yaml file. Each profile should have a unique name.

FAQ

Frequently Asked Questions about the configuration of KiwiSSH.

How do I setup a remote git location?

KiwiSSH can push local git commits via SSH to their remote repository. To set up the remote repositories (in general), follow these steps:

  1. Create one remote repository per group.
    • If all groups live under one org, use one global template in git.remote.url with {group}.
    • If groups are spread across multiple organizations, set per-group overrides under groups.<group>.git.remote.url.
  2. Ensure the branch from git.remote.branch (or per-group branch override) exists or can be created by the push user. Default is main.
  3. Create an SSH keypair for KiwiSSH if you haven't already and add the public key to your Git provider.
  4. Make sure the remote Git user has write access to the repositories
  5. Run backup and confirm commits are present locally and remotely.

Tip

Since KiwiSSH will use the local OpenSSH client to push commits to the remote repository, the SSH config file (~/.ssh/config or C:\Users\user\.ssh\config) can be used to manage SSH connection details for the Git provider (e.g. GitHub, GitLab, etc.) and set up things like SSH key usage, custom ports, etc.

Example: groups.<group>.git.remote.url: "ssh://git@gitea/customer-aaa/prod-firewalls.git" Config in ~/.ssh/config:

Host gitea
   HostName 192.168.24.4
   Port 222
   User git
   IdentityFile ~/.ssh/kiwissh-client

When do I choose the global git.remote vs per-group overrides (groups.<group>.git.remote)?

Global: You should use the global git.remote configuration if all your groups should push to the same remote organization/repository structure (for example one repository per group under the same organization on GitHub). In this case, you can use the {group} placeholder in the global git.remote.url to dynamically generate the remote URL for each group based on its name. -> Example:git.remote.url: git@github.com:<YOUR_ORGANIZATION_HERE>/{group}.git will result in repositories like <YOUR_ORGANIZATION_HERE>/customer-aaa.git, <YOUR_ORGANIZATION_HERE>/abc-company.git, etc.

Group overrides: If your groups belong to different organizations or if you need more granular control over the remote URL each group, setup per-group overrides. In this case, you would leave the global git.remote configuration empty (aka remove it) and set the git.remote.url and optionally git.remote.branch for each group under groups.<group>.git.remote. -> Example: Group 1 groups.datacenter-firewalls.git.remote.url: ssh://git@192.168.45.25:222/company-abc/datacenter-firewalls.git, Group 2 groups.office-switches.git.remote.url: ssh://git@192.168.45.25:222/company-xyz/office-switches.git

In the next example, the global git.remote.url is configured with a placeholder {group} which will be replaced by the actual group name for each group. All groups will use the global template except for development-firewalls which has a per-group override for the remote URL, so it will push to the specified SSH URL instead of the global template.

git:
  local_path: "/config/prod/kiwissh/backups"
  remote:
    url: "ssh://git@github.com:<YOUR_ORGANIZATION_HERE>/kiwissh-{group}.git"

groups:
  development-firewalls:
    username: "admin"
    password: "password"
    vendor: "fortinet_fortigate"
    ssh_profile: "modern"
    git:
      remote:
        url: "ssh://git@github.com:dev_orga/development-firewalls.git"
        branch: "dev"

fatal: Could not read from remote repository

If you encounter the error message ..

ERROR: Remote push failed for group <your-group>: Cmd('git') failed due to: exit code(128)
  cmdline: git push --porcelain -- origin main:main
  stderr: 'fatal: Could not read from remote repository.'

.. you should do ssh git@<domain> manual first to add the host to ~/.ssh/known_hosts.

Tip

In order to persistently keep the known_hosts file in Docker, make sure to mount a volume to /home/kiwissh/.ssh and ensure the permissions are correct to ensure successful SSH authentication when pushing even after restarting the container.


Future Goals

Short Term:

  • Checks for device source: No duplicate hostnames, valid IPs, ... (What if multiple groups hold the same IP address range?)
  • Update ssh_service to use FQDN instead of IP to avoid?
  • Add new vendors

Mid-term:

  • Implement backup job log rotation and retention policies (e.g. delete logs if line >10000 or older than 90 days)
  • Add visual popup when opening JobView.vue if the page load takes longer than 2 seconds to inform the user that the page is still loading and to prevent them from thinking the UI is frozen
  • Pentests
  • Rework Pydantic models (required vs optional fields, default values, validators, etc.)
  • Update Ruff linter and formatter
  • Add Vue linter/formatter?
  • Telnet support? SCP support?
  • Update ssh_profile legacy with Synology NAS ssh settings "Low"
  • Show "backup time" when NO_CHANGES" in log line "No configuration changes detected for {device_name}"?

Long Term:

  • Notification System (Email, Slack, Webhook) (#5)
    • Special notification IF git diff shows a minus or plus of 100 lines or more to quickly inform about major config changes
  • i18n localization support
  • New Update available notification in the UI
  • Fix logging strings to use lazy formatting instead of f-strings (Ruff G004) (Add to ruff.toml)
  • Swagger API documentation on GitHub Pages
  • Allow group passwords to bet set via env vars or other input
  • Optional share anonymouse usage data for statistics (needs opt-in, privacy policy and telemetry server)
  • Add UI banner when new update is available
  • Login Screen, User management and RBAC

Technical Documentation

Please visit TECHNICAL.md for detailed technical documentation about the architecture and design decisions of KiwiSSH.

Contributing to KiwiSSH

Important

If you would like to contribute to the project, please to a look at the CONTRIBUTING.md file for guidelines on how to contribute and the code of conduct.

License

See LICENSE file for license information.

Support

I work on KiwiSSH in my free time and unpaid. If you find it useful and would like to support its development, consider supporting me with a coffee:

Buy Me a Coffee

About

Backup your network device configurations with ease and keep track of changes. 4.52x faster than Oxidized!

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors