diff --git a/TODO b/TODO
index ba9a0b34377e603f60bf14b81582d7e250b14066..1db4b41c304355430b6d7025142d9c1484374f28 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,9 @@
 - colors
 - status: do not exit on non-zero return code
 - "shc CONTAINER start" vs. "shc CONTAINER shell"
+- exec -i
+
+Albireo cleanup:
+- prerouting rule
+- shc@.service
+- containers
diff --git a/shipcat.py b/shipcat.py
index d3c965bbd2c631d2aaecf960bb27e81c5d1cfc29..8ddd883c885c998594267ab549524bda81dc4169 100755
--- a/shipcat.py
+++ b/shipcat.py
@@ -42,12 +42,12 @@ def load_config() -> GlobalConfig:
         sys.exit(1)
 
 
-def setup_container(args: argparse.Namespace, require_root: bool) -> ContainerConfig:
+def setup_container(args: argparse.Namespace, require_root: bool, container: str = None) -> ContainerConfig:
     if os.geteuid() != 0:
         die('This program must be run setuid root')
 
     try:
-        cc = ContainerConfig.load(config, args.name)
+        cc = ContainerConfig.load(config, container or args.name)
     except ConfigError as e:
         die(str(e))
 
@@ -277,6 +277,36 @@ def cmd_exec(args: argparse.Namespace) -> None:
     run_command(cmd)
 
 
+def cmd_rsync(args: argparse.Namespace) -> None:
+    rsync = args.arg
+    if verbose:
+        print('rsync passed:', rsync, file=sys.stderr)
+
+    if len(rsync) >= 2 and rsync[0] == '-l':
+        user = rsync.pop(0)
+        rsync = rsync.pop(0)
+    else:
+        user = None
+
+    if not rsync or rsync[0].startswith('-'):
+        die('Cannot parse rsync arguments')
+
+    machine = rsync.pop(0)
+
+    if not rsync or rsync[0] != 'rsync':
+        die('Cannot parse rsync arguments')
+
+    cc = setup_container(args, False, container=machine)
+
+    cmd = ['podman', 'exec', '-i']
+    if user is not None:
+        cmd.extend(['--user', user])
+    cmd.append(cc.container)
+    cmd.extend(rsync)
+
+    run_command(cmd)
+
+
 def parse_int_list(s: str) -> List[int]:
     return list(map(int, s.split(',')))
 
@@ -307,6 +337,15 @@ create_parser.add_argument('arg', nargs='+', help='command and its arguments')
 create_parser.add_argument('--tty', '-t', default=False, action='store_true', help='stdio will be attached to a pseudo-terminal')
 create_parser.add_argument('--user', '-u', metavar='USER[:GROUP]', help='user/group to run the command under (default: root)')
 
+start_parser = subparsers.add_parser('rsync', help='rsync connection wrapper', description="""
+Connection wrapper for rsync.
+
+If rsync is invoked with "--rsh='shc rsync --'", it connects to local containers
+instead of remote machines. Please note that rsync must be installed inside the
+container, too.
+""")
+start_parser.add_argument('arg', nargs='+', help='arguments passed by rsync')
+
 start_parser = subparsers.add_parser('shell', help='run a shell inside a container', description='Run a shell inside a container')
 start_parser.add_argument('name', help='name of the container')
 
@@ -328,6 +367,7 @@ actions = {
     'enable': cmd_enable,
     'exec': cmd_exec,
     'init': cmd_init,
+    'rsync': cmd_rsync,
     'shell': cmd_shell,
     'start': cmd_start,
     'status': cmd_status,
diff --git a/shipcat/config.py b/shipcat/config.py
index 94be7ecc5c8225adfe82282ce1b37a2804c5d075..b8a6bdbcfd1f849de3092fe28239b2731532244b 100644
--- a/shipcat/config.py
+++ b/shipcat/config.py
@@ -64,16 +64,16 @@ class ContainerConfig:
             with open(path, 'rb') as f:
                 root = tomllib.load(f)
         except FileNotFoundError:
-            raise ConfigError(f'Cannot load {path}')
+            raise ConfigError(f'Cannot load container configuration {path}')
         except tomllib.TOMLDecodeError as e:
-            raise ConfigError(f'Cannot parse {path}: {e}')
+            raise ConfigError(f'Cannot parse container configuration {path}: {e}')
 
         cc = ContainerConfig()
         cc.container = name
         try:
             cc.parse(Walker(root))
         except WalkerError as e:
-            raise ConfigError(f'Cannot parse {path}: {e}')
+            raise ConfigError(f'Cannot parse container configuration {path}: {e}')
 
         return cc