Announcing ssh2incus – ssh into Incus instances

Thanks. Here are some examples I have tried.
I am connecting to the host itself on the incus host (192.168.100.130), but I get the same results from another machine.
If I use the option --noauth the problem goes away.
(Name ‘Docker’ is instance)

$ id
uid=1000(inagaki) gid=1000(inagaki) groups=1000(inagaki),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),102(input),105(render),106(netdev),991(incus-admin),992(incus),993(gpio),994(i2c),995(spi)

$ groups
inagaki adm dialout cdrom sudo audio video plugdev games users input render netdev incus-admin incus gpio i2c spi

$ ssh -p 2222 Docker@192.168.100.130 -i ~/.ssh/id_raspi01_ed25519 
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 

$ ssh -p 2222 Docker+root@192.168.100.130 -i ~/.ssh/id_raspi01_ed25519 
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 

$ ssh -p 2222 Docker+inagaki@192.168.100.130 -i ~/.ssh/id_raspi01_ed25519 
Docker+inagaki@192.168.100.130: Permission denied (publickey).

We’ve just released ssh2incus 0.6.
Download new release from https://ssh2incus.com/downloads

This new version introduces Incus shell and many improvements around logging and user authentication.

Incus shell provides direct access to the Incus command line interface from an SSH session, allowing you to manage your Incus instances without needing to log into the host directly.
Only root is allowed to connect to Incus shell.

This feature is especially useful for:

  • Quick management tasks without direct host access
  • Systems administration from remote locations

Usage

To access the Incus shell, connect using (notice % sign):

ssh -p 2222 %shell@incus-host

Features

  • Interactive Incus command execution
  • Ctrl+C to exit the shell cleanly

Example Session

$ ssh %shell@incus-colima

incus shell emulator on colima-incus (Ctrl+C to exit)

Hit Enter or type 'help <command>' for help about any command

Type incus command:
> incus version
Client version: 6.11
Server version: 6.11

Type incus command:
> incus

and a side note in response to @igktr :
Version 0.6 should also address your issues. Just make sure that ssh public key is present in ~/.ssh/authorized_keys on Incus host.
For example, if you are connecting using ssh -p 2222 Docker+inagaki@192.168.100.130... then make sure that user inagaki has your ssh public key in ~/.ssh/authorized_keys on 192.168.100.130 Incus host.

1 Like

Hmmm… it doesn’t work properly.

Apr 08 08:14:36 raspi01 systemd[1]: Started ssh2incus.service - SSH server for Incus instances.
Apr 08 08:14:36 raspi01 ssh2incus[2375]: level=debug msg=log: DEBUG enabled func=ssh2incus.init.0() file=ssh2incus/init.go:149
Apr 08 08:14:36 raspi01 ssh2incus[2375]: level=info msg=starting ssh2incus on :2222 as master process, pid 2375 func=ssh2incus/server.(*Server).Run() file=ssh2incus/server/server.go:52
Apr 08 08:14:42 raspi01 ssh2incus[2375]: level=info msg=connection accepted, handing off to child process func=ssh2incus/server.(*Server).Listen.func1() file=ssh2incus/server/server.go:136
Apr 08 08:14:42 raspi01 ssh2incus[2375]: level=info msg=started detached child process with pid 2389 func=ssh2incus/server.handoffToChild() file=ssh2incus/server/server.go:256
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=debug msg=log: DEBUG enabled func=ssh2incus.init.0() file=ssh2incus/init.go:149
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=info msg=starting ssh2incus as child process, pid 2389 func=ssh2incus/server.(*Server).Run() file=ssh2incus/server/server.go:45
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=info msg=child serving connection from 192.168.100.130:34664 func=ssh2incus/server.(*Server).Serve() file=ssh2incus/server/server.go:168
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=debug msg=auth (host): attempting key auth for root@Docker.default+inagaki: ssh-ed25519 SHA256:G7/iXrSxz4LkDiX7FHGeNs0ddX+u3NCajxi3PKL9vho func=ssh2incus/server.hostAuthHandler() file=ssh2incus/server/auth.go:16 session=76b29a7d
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=debug msg=auth (host): host user "inagaki" matched "incus" group func=ssh2incus/server.hostAuthHandler() file=ssh2incus/server/auth.go:39 session=76b29a7d
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=info msg=auth (host): succeeded for root@Docker.default+inagaki: ssh-ed25519 SHA256:G7/iXrSxz4LkDiX7FHGeNs0ddX+u3NCajxi3PKL9vho func=ssh2incus/server.hostAuthHandler() file=ssh2incus/server/auth.go:60 session=76b29a7d
Apr 08 08:14:42 raspi01 ssh2incus[2389]: level=debug msg=new incus client created func=ssh2incus/server.NewIncusClientWithContext() file=ssh2incus/server/incus.go:67 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shell: connecting root@Docker.default+inagaki func=ssh2incus/server.shellHandler() file=ssh2incus/server/shell.go:125 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=reusing existing incus client func=ssh2incus/server.NewIncusClientWithContext() file=ssh2incus/server/incus.go:41 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shell: CMD /usr/sbin/nologin -l func=ssh2incus/server.shellHandler() file=ssh2incus/server/shell.go:193 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shell: PTY true func=ssh2incus/server.shellHandler() file=ssh2incus/server/shell.go:194 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shell: ENV HOME=/root LANG=en_GB.UTF-8 SHELL=/usr/sbin/nologin SSH_SESSION=76b29a7d TERM=tmux-256color USER=root func=ssh2incus/server.shellHandler() file=ssh2incus/server/shell.go:195 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shell: exit 1 func=ssh2incus/server.shellHandler() file=ssh2incus/server/shell.go:248 session=76b29a7d
Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=debug msg=shutting down devices... func=ssh2incus/server.(*Server).Serve() file=ssh2incus/server/server.go:180Apr 08 08:14:46 raspi01 ssh2incus[2389]: level=info msg=child server stopped func=ssh2incus/server.(*Server).Serve() file=ssh2incus/server/server.go:186
$ id
uid=1000(inagaki) gid=1000(inagaki) groups=1000(inagaki),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),102(input),105(render),106(netdev),991(incus-admin),992(incus),993(gpio),994(i2c),995(spi)

$ cat .ssh/config
Host ssh2incus
        Hostname localhost
        User inagaki
        Port 2222
        IdentityFile ~/.ssh/id_raspi01_ed25519

$ file ~/.ssh/id_raspi01_ed25519
/home/inagaki/.ssh/id_raspi01_ed25519: OpenSSH private key

$ ssh -p 22 ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
Linux raspi01 6.12.20+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.12.20-1+rpt1~bpo12+1 (2025-03-19) aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Apr  8 09:44:00 2025 from ::1
$ exit
logout
Connection to localhost closed.

$ ssh Docker@ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
This account is currently not available.
Connection to localhost closed.

$ ssh Docker+inagaki@ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
This account is currently not available.
Connection to localhost closed.

$ ssh Docker+root@ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
This account is currently not available.
Connection to localhost closed.

Thanks for sharing the logs! There’s one line that explains why you cannot connect.

Let’s break it down:

Apr 08 08:14:46 raspi01 ssh2incus[2389]: 
  level=debug 
  msg=shell: CMD /usr/sbin/nologin -l
  func=ssh2incus/server.shellHandler() 
  file=ssh2incus/server/shell.go:193 
  session=76b29a7d

You see this: msg=shell: CMD /usr/sbin/nologin -l and to be more specific /usr/sbin/nologin.
Somehow your user root has shell set to nologin which means you won’t be able to connect to shell.

First you need to fix shell for root in your instance.
You can do it as follows:

incus shell Docker
usermod -s /bin/bash root

Another solution is to override user shell via ssh2incus argument:

--shell string          shell access command: login, su, sush or user shell

Now if you make a change in your /etc/default/ssh2incus to something like:

ARGS=-m -d --shell login

it will force it to use login instead of nologin and you will be able to login without making changes to your root user.

Many thanks.
I didn’t think about the accounts in the instance.
Yes, I remembered that I disabled root when creating the Docker instance.

$ ssh inagaki@Docker+inagaki@ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
$ id
uid=1000(inagaki) gid=1000(inagaki) groups=1000(inagaki)
$ groups 
inagaki
$ exit
logout
Connection to localhost closed.

$ ssh root@Docker+inagaki@ssh2incus
Enter passphrase for key '/home/inagaki/.ssh/id_raspi01_ed25519': 
This account is currently not available.
Connection to localhost closed.
$ 
1 Like