Announcing ssh2incus – ssh into Incus instances

I’m excited to announce the release of ssh2incus, a comprehensive reimagining of the ssh2lxd project. This isn’t just a simple rename—it represents a significant milestone with a complete code rewrite and architectural overhaul.

The Next Generation

ssh2incus has been thoroughly modernized to harness the power of the Incus 6.x API, bringing enhanced performance, reliability, and security to your container infrastructure. As Incus continues to evolve as the community-driven fork of LXD, ssh2incus provides a seamless SSH experience specifically tailored to this ecosystem.

Why The Change?

This transformation from ssh2lxd to ssh2incus reflects our commitment to supporting the most advanced container technologies. The codebase has been meticulously refactored to improve:

  • Performance: Significantly faster connection handling and session management
  • Reliability: More robust error handling and recovery mechanisms
  • Maintainability: Cleaner code architecture for easier future enhancements
  • Security: Updated authentication mechanisms and security best practices

Key Improvements

The new ssh2incus brings all the features you’ve relied on, now with enhanced capabilities:

  • Full compatibility with Incus 6.11 API
  • Streamlined authentication workflows
  • Improved file transfer performance
  • More intuitive connection syntax
  • Comprehensive port forwarding options
  • Better enterprise integration possibilities

Features

  • Authentication: Uses existing host OS SSH keys via authorized_keys
  • No-Auth Mode: Optional authentication-free mode for local and development environments
  • Terminal Support: Full PTY (terminal) mode and remote command execution
  • File Transfer: Complete SCP and SFTP support with integrated SFTP server
  • Port Forwarding:
    • Local forwarding (ssh -L)
    • Reverse forwarding (ssh -R)
    • Dynamic forwarding (ssh -D)
  • SSH Agent Forwarding: Seamlessly forward your SSH agent into instance sessions
  • Process Models:
    • Master process mode: Maintains SSH connections after service restart
    • Daemon mode: Single process with multiple threads for resource-constrained systems
  • Compatibility:
    • Works with Incus inside Lima and Colima
    • Tested with Jetbrains Gateway, VSCode, Cursor and other IDEs
    • Full Ansible support

Getting Started

We invite all previous ssh2lxd users and new adopters to visit our GitHub repository to download the latest release and explore the documentation. Whether you’re managing containers in development or production environments, ssh2incus delivers a superior SSH experience without compromise.

Your feedback is invaluable as we continue to refine and enhance ssh2incus. Please share your experiences, suggestions, and any issues you encounter here or through GitHub.

3 Likes

Cool idea. I generally install an ssh server on my instances.

What is the main benefit of using this strategy?

The main benefit is fast and hassle-free access to any running instances without the need to setup and configure ssh inside the instances.

ssh2incus eliminates the need to install, configure, and maintain individual SSH servers in each container, significantly reducing resource consumption and attack surface while providing a single, secure point of access. With one centralized SSH service handling authentication and connection management, you gain instant access to all containers without modifying their configurations, simplifying administration and enhancing security across your entire Incus environment.

2 Likes

I see a message thrown (pkgAcquire::Run (13: Permission denied)) while installing the package as root on armbian-x64 (based on Debian12). Not sure if it’s an warning or an error. The service seems fine after installation. Will play around. Thanks!

# cat /etc/os-release
PRETTY_NAME="Armbian 25.2.3 bookworm"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.armbian.com"
SUPPORT_URL="https://forum.armbian.com"
BUG_REPORT_URL="https://www.armbian.com/bugs"
ARMBIAN_PRETTY_NAME="Armbian 25.2.3 bookworm"

# wget https://github.com/mobydeck/ssh2incus/releases/download/0.4/ssh2incus_0.4-0_amd64.deb

# apt-get install -f ./ssh2incus_0.4-0_amd64.deb
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'ssh2incus' instead of './ssh2incus_0.4-0_amd64.deb'
The following NEW packages will be installed:
  ssh2incus
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/8,491 kB of archives.
After this operation, 14.5 MB of additional disk space will be used.
Get:1 /root/ssh2incus_0.4-0_amd64.deb ssh2incus amd64 0.4-0 [8,491 kB]
Selecting previously unselected package ssh2incus.
(Reading database ... 75569 files and directories currently installed.)
Preparing to unpack .../root/ssh2incus_0.4-0_amd64.deb ...
Unpacking ssh2incus (0.4-0) ...
Setting up ssh2incus (0.4-0) ...
N: Download is performed unsandboxed as root as file '/root/ssh2incus_0.4-0_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
# systemctl start ssh2incus.service

# systemctl status -l ssh2incus.service
● ssh2incus.service - SSH server for Incus instances
     Loaded: loaded (/lib/systemd/system/ssh2incus.service; disabled; preset: enabled)
     Active: active (running) since Sat 2025-03-29 12:20:43 PDT; 1s ago
   Main PID: 6973 (ssh2incus)
      Tasks: 8 (limit: 18688)
     Memory: 1.6M
        CPU: 7ms
     CGroup: /system.slice/ssh2incus.service
             └─6973 /bin/ssh2incus -m

N: Download is performed unsandboxed as root as file ‘/root/ssh2incus_0.4-0_amd64.deb’ couldn’t be accessed by user ‘_apt’. - pkgAcquire::Run (13: Permission denied)

The error message is related to the fact that you are installing the package from /root folder.
You will see that error if you try to install any package from that folder.

Other than that everything else looks good in your logs. Enjoy!

1 Like

oh! I didn’t know that. Thanks for the explanation.

Just wanted to confirm it worked!

student@MacBook-Pro-13 ~ % ssh -p 2222 root@c1@192.168.1.145

root@c1:~# uname -a
Linux c1 6.12.20-current-x86 #1 SMP PREEMPT_DYNAMIC Sat Mar 22 19:54:28 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

root@c1:~# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 Mar28 ?        00:00:01 /sbin/init
root         124       1  0 Mar28 ?        00:00:00 /usr/lib/systemd/systemd-journald
root         175       1  0 Mar28 ?        00:00:00 /usr/lib/systemd/systemd-udevd
systemd+     183       1  0 Mar28 ?        00:00:00 /usr/lib/systemd/systemd-networkd
systemd+     189       1  0 Mar28 ?        00:00:00 /usr/lib/systemd/systemd-resolved
root         197       1  0 Mar28 ?        00:00:00 /usr/sbin/cron -f -P
message+     198       1  0 Mar28 ?        00:00:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root         202       1  0 Mar28 ?        00:00:00 /usr/lib/systemd/systemd-logind
root         206       1  0 Mar28 pts/0    00:00:00 /sbin/agetty -o -p -- \u --noclear --keep-baud - 115200,38400,9600 linux
syslog       211       1  0 Mar28 ?        00:00:00 /usr/sbin/rsyslogd -n -iNONE
root         542       0  0 21:24 pts/1    00:00:00 /bin/bash -l
root         558     542  0 21:25 pts/1    00:00:00 ps -ef
root@c1:~# exit
logout
Connection to 192.168.1.145 closed.
student@MacBook-Pro-13 ~ %
1 Like

I’m new to your program. How is this different than incus exec bash ... ?

Reading the docs and examples it looks like it only supports local container?

I have an Incus jumphost setup where all my remote Incus cluster are registered. To connect you need to execute incus ls remote: to list all containers on the remote incus cluster. Seems like this doesn’t currently work properly. Are there any plans to support it?

I’m new to your program. How is this different than incus exec bash ... ?

The difference is that incus exec allows you to run shell or execute commands on the instances where ssh allows you to use SFTP, SCP, port forwarding, agent forwarding and more which is essential for many development and automation scenarios.
With ssh and incus you can use instances as virtual servers for a whole lot of scenarios that are not possible with what incus exec offers out of the box.

2 Likes

Reading the docs and examples it looks like it only supports local container?

It is designed to work with either a local Incus or a single remote.
So if you have a remote configured on your jumphost under root user which points to an Incus cluster then you can run ssh2incus on that jumphost and you will be able to access all your instances in the cluster.

Look at the Available Options:

-r, --remote string         Incus remote defined in config.yml, e.g. my-remote

Yeah, that works… but not really what I was looking for. Properly need to be more clear.

I would like to use the dynamic approach from the SSH command. You can define “projects” but not “remotes”. I tried “remote:containername” but that fails and overwriting the ARGS variable requires to restart the ssh2incus.service

Hops this makes it more clear?

Yes, now that is clear. we can definitely add ability to use multiple remotes in the next version some time this week.

This is well done!

Would it be possible to use SSH authorized_keys from the instances itself? I would like to have more granular who can connect to what instance. Or any other suggestion how can I give users access per instance?

Yes, we can add that feature to the next version within this week.

That would be brilliant. Thanks.

1 Like

We’ve just released ssh2incus 0.5 and launched website ssh2incus.com

@osch we added support for remotes. you can now use ssh remote:container@host.

@Tetrov we added support for authentication using authorized_keys from the instances. you can enable that with --inauth flag added to ARGS= in /etc/default/ssh2incus.

See ssh2incus docs for more details.

3 Likes