Access LXD containers via SSH/SFTP

I’m following these tutorials to host multiple websites in a VM:

In these tutorials, they are using HAProxy and iptables to redirect traffic from port 80 to each container. My first thought was to do the same with port 22, but I was afraid that by doing that I would lock myself out of my VM, so I went to my container (which I have a website) and changed ssh_config file to listen to port 25000.

After that in the host, I set some iptable rules:
sudo iptables -t nat -I PREROUTING -i ens3 -p TCP -d HOST_IP_ADDRESS/32 --dport 25000 -j DNAT --to-destination CONTAINER_IP_ADDRESS:25000

I also edited /etc/haproxy/haproxy.cfg to:

Doing that, I can access via SSH if I’m inside host, but not from outside. Is it possible to access each container invidually via SSH? Could someone help me to solve this?

I’m using Ubuntu 18.10 and LXD version is 3.6.

Thank you!

Why are you using a proxy for ssh? iptables should be enough. There is no need to use the same port for all ssh connections. I have picked a range of ports on the host and I mapped them to port 22 for each container ip address.

I’ve been using shorewall to do this. Shorewall is an iptables front-end. I use the two-interfaces configuration, where the loc interface is the lxd bridge (lxdbr0). In one of my systems I’ve constrained the last byte of the dhcp addresses of the containers between 20-99, and I have lines like this in /etc/shorewall/rules:
DNAT net loc: tcp 7020
DNAT net loc: tcp 7021

DNAT net loc: tcp 7099
So, port 7020 of the host is connected to port 22 of container with ip x.y.z.20, etc.

I have put the port numbers of each container in my ~/.ssh/config file, so I don’t need to put them on the ssh command line. I have setup a script that extracts the ip addresses from the containers and generates the appropriate config file for ssh. For ssh between containers on the same host, I generate config files that use the private ip address instead of the public one.

I just provided an answer to someone on Reddit that was trying to do something similar. He tried it and reported back that it worked great so perhaps you can use this too…

This leave Port 22 alone in your Host.

For each container just use a different port like 2222, 2223, 2224 etc (or whatever) for each container.

The only thing you have to do is use:

ssh -p xxxx

where xxxx is the port number you used for each container you configured.

This worked for me…

Here’s the ~/.ssh/config example

my .ssh/config sample:

Host main_server
    HostName server_address
    User root
    Port 2022
    ForwardAgent yes

Host lxc_container
    User root
    Port 22
    ProxyCommand ssh main_server nc lxc_container 22
    ForwardAgent yes

Although I always get error messages from ssh on my local machine like this one…

Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.

It’s not pretty but it’s quicker for me to edit ~/.ssh/config than to run lots of lxc config device add CN1 proxyport2222 proxy listen=tcp: connect=tcp:localhost:22 style commands…

Does anyone know how to get ride of the REMOTE HOST IDENTIFICATION HAS CHANGED! error given that lots of containers are on the same IP?

as long as the IP addresses are different, the port numbers can be the same. you can then distinguish which container you connect to by IP address. if the ssh port can be reached from the internet, then i would suggest using a different number other than 22. that’s so the internet children don’t flood your logs with password attempts. if your internet provider gives you only one IP address, then you will want different port numbers if you are connecting in via the internet. or you can use port forwarding with your first ssh connection to the host then make more ssh connections through the first ssh connection’s port forwarding. with port forwarding listening on host you can connect to other IP addresses in to make it look to the ssh client as different hosts to get rid of the REMOTE HOST IDENTIFICATION HAS CHANGED! message.

ssh 2202
ssh 2203
ssh 2204

If you are using LXD 3.0 (or newer), you can avoid using iptables by using a LXD proxy device.


I decided to use LXD proxy device and it worked. Thank you, guys!

1 Like

Maybe you do not have to use iptables or LXD proxy - if you have configured your host with multiple network interfaces, then you can use network type nictype=physical and bind that network interface of your host directly to container without any overhead, fully transparent …