Xenadu makes it easy to manage system configurations using version control
Alternatives To Xenadu
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
2 months ago10mitShell
Run GUI applications and desktops in docker and podman containers. Focus on security.
a month ago52February 13, 202218bsd-2-clausePython
🚀 Bring your favorite shell wherever you go through the ssh.
Webssh3,495322 days ago47May 02, 2022108mitPython
:seedling: Web based ssh client
Assh2,7181a day ago29May 28, 2022114mitGo
:computer: make your ssh client smarter
Flightplan1,789305354 years ago53June 23, 201920mitJavaScript
Run sequences of shell commands against local and remote hosts.
Git Sync1,714
15 days ago8November 09, 201823apache-2.0Shell
A sidecar app which clones a git repo and keeps it in sync with the upstream.
4 days ago45February 08, 202275apache-2.0Go
:tophat: simple, fun and transparent SSH (and telnet) bastion server
Goph1,2962511 days ago2October 31, 202122mitGo
🤘 The native golang ssh client to execute your commands over ssh connection. 🚀🚀
22 days ago35otherC
Dropbear SSH
a year ago1March 31, 202110mitGo
Parallel SSH commands runner and file synchronization tool
Alternatives To Xenadu
Select To Compare

Alternative Project Comparisons


Xenadu is a tool for remotely managing system configurations, making it possible to keep track of configurations using a version control tool like git. Once your system configuration is managed by Xenadu, it is easy to crank out clone machines.

Getting started

So let's say you want to use Xenadu to manage a machine on your network named "davidbowie".

  1. Install Xenadu on something other than your target machine (like your laptop):

    curl -L https://github.com/iandennismiller/xenadu/tarball/master -o xenadu.tgz
    tar xvfz xenadu.tgz
    cd iandennismiller-xenadu*
    python setup.py install
  2. Make a directory to store your configuration (we'll call it davidbowie, since that's the name of the machine). The files subdirectory will contain a copy of all the remotely managed files.

    mkdir davidbowie
    cd davidbowie
    mkdir files
  3. Create a host definition file named davidbowie.py (or whatever you want, but again since this machine is named davidbowie, that's what I'm calling it)

    touch ./davidbowie.py
    chmod 755 ./davidbowie.py
  4. Edit davidbowie.py, and paste this skeletal host definition file:

    #!/usr/bin/env python
    from Xenadu import XenaduConfig, Perm
    mapping = [
        ['/etc/hosts', "hosts", Perm.root_644],
        ['/etc/network/interfaces', "interfaces", Perm.root_644],
    env = { 'ssh': { "user": "root", "address": "somewhere.example.com" } }
  5. Set the ssh address to point to your machine.

    env = { 'ssh': { "user": "root", "address": "elsewhere.example.com" } }

    Also, make sure you are familiar with ssh public key authentication. You need to log in as root in order for Xenadu to function correctly. If you are uncomfortable with being able to log in as root, then make sure your private key is password-protected, and use a ssh keychain manager.

  6. Edit mapping to list the files you want to track. mapping is a python list, where each item in the list represents one file on the remote host. An item like ['/etc/network/interfaces', "interfaces", Perm.root_644] consists of 3 values:

    • /etc/network/interfaces is the complete path of the file on the remote host
    • interfaces is the local name of the file, which is in the ./files directory.
    • Perm.root_644 is the permissions that file should have on the remote host (here, owner is root and permission is 644).
  7. Grab all of those files from the remote host:

    ./davidbowie.py --getall

    This will automatically go through every item in mapping and download it to the local ./files directory.

  8. The files are in ./files - save this configuration!

    git init; git commit -m 'initial davidbowie config'

Deploying changes

So let's say you edit ./files/interfaces and you want to push this to the remote machine. This is way easier with Xenadu than manually copying the file with SSH, which requires you to type out the hostname and the paths for the local and remote files.

./davidbowie.py --push interfaces

Or, if you forget what you call the file locally but remember the remote name, use that:

./davidbowie.py --push /etc/network/interfaces

You'll probably end up learning to use the shorter version for files you commonly deal with.


In the "Getting started" example, /etc/network/interfaces uses Perm.root_644 to set its permissions to a fairly standard level. What about a file like /etc/sudoers, which needs stricter permissions? It's pretty easy to create new permission schemes:

# make a new permission
sudoers_perm = {"perm": "0440", "owner": "root", "group": "root"}

# use it as you append the sudoers file to the mapping
mapping.append(['/etc/sudoers', 'sudoers', sudoers_perm])

You could even go so far as to do something like:

mapping.append(['/etc/sudoers', 'sudoers', {"perm": "0440", "owner": "root", "group": "root"}])

In fact, Perm.root_644 is just a convenient equivalent to {"perm": "0644", "owner": "root", "group": "root"}, so that's what it actually means when you say something like ['/etc/hosts', "hosts", Perm.root_644].

Multiple systems using a single definition file

In web app development, it's pretty common to have a staging server that is almost identical to the production server. With Xenadu, it's pretty easy to use a single definition file to control both the staging and production servers. Here is a quick example of what you can put at the end of your definition file, right before the XenaduConfig(env, mapping) directive:

if 'XENADU' in os.environ and os.environ['XENADU'] == 'dev':
    env['ssh']['address'] = "dev.example.com"
    custom_dev_files = [
        ['/etc/network/interfaces', "interfaces-dev", Perm.root_644],
XenaduConfig(env, mapping)

Now putting XENADU=dev before your command will push the development version of /etc/network/interfaces to dev.example.com:

XENADU=dev ./davidbowie.py --push /etc/network/interfaces

This is useful because it lets you keep a single version control repository with all of the files for your stage and production server in one place.

Popular Hosts Projects
Popular Ssh Projects
Popular Networking Categories

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.