SSH tunneling with Autossh
AutoSSH is a great tool for Linux administrators. SSH is a must-have – we are using it on daily basis. In many cases, it is just enough. The well-designed tool which is doing its job. From time to time, however, we need something more.
What can I use AutoSSH for?
AutoSSH is a tool to monitor and restart SSH sessions. It is checking the health of the connection and restarts SSH session if necessary. It is useful for non-reliable internet connections such as GSM or in cases when the connection parameters are changing from time to time (for example ISP is assigning new IP to the server from). We are using it to maintain reliable tunnel between our remote servers and main monitoring server.
Remote servers are located in the places where no static IPs are assigned and there is no possibility to open ports on the router. In this case, the connection has to be initiated from the remote host. We are simply creating the tunnel which is forwarding all connections to the port NNNN of monitoring host to the port 22 (SSH) of the remote host. In some cases, we are doing the same for the port 80 (HTTP) of the remote host if we want to forward web server data.
AutoSSH basic usage
AutoSSH is currently available as a package in most of the Linux distributions. You can install it using yum or apt. Once installed, it is ready to use. However, there is one important prerequisite: your SSH has to be able to connect without the password. You don’t want to enter password during each re-connection, don’t you?
The basic example of the autossh command is:
remote.host$ autossh -N -R 6000:localhost:22 [email protected]
The command above should be started on the remote host. It simply creates the tunnel which is forwarding monitoring host port 6000 to the local port 22. This means that I can now run the following command on the monitoring host:
monitoring.com$ ssh remoteuser@localhost -p 6000
Please note that I’m connecting to the localhost’s port number 6000. No need to know IP of the remote server, the tunnel is already there. This also shows one important thing – there can be only one remote host connected to the single port of the monitoring server. Each additional connection has to be placed on the other port.
But I want it to start during the server boot!
Nowadays the most convenient way to run autossh on boot time is to use systemd service. Let’s create the file named autossh-tunnel.service in /etc/systemd/system/ and paste this code into it:
[Unit] Description=AutoSSH tunnel service Remote port 6000 to local 22 After=network.target [Service] Environment="AUTOSSH_GATETIME=0" ExecStart=/usr/bin/autossh -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -N -R 6000:localhost:22 [email protected] [Install] WantedBy=multi-user.target
There are few important things to note – first, the environment variable. Systemd does not support & or -f option to run the service in the background. The environmental variable tells autossh not to wait for the first connection to succeed, but immediately go to background and restart even if this first connection will fail. We also added ServerAliveInterval and ServerAliveCountMax – this tells SSH to test the connection every 10 seconds and assume failure after 3 consecutive failed messages. Such configuration ensures a quick recovery after the connection failure.
Once we have the service file created, we should let systemd know that we changed something, we can start the service and we can enable it to run during the boot time:
remote.host$ systemctl daemon-reload remote.host$ systemctl start autossh-tunnel.service remote.host$ systemctl enable autossh-tunnel.service
We can now test our new tunnel the same way we did before.
What else can I do?
You can also create the tunnel which is working the other way. In some cases, we are using it to forward remote port 80 to the local port 8080 to forward some API calls. The only change you have to do is to change the part of the configuration. Such tunnel can be created like so:
remote.host$ autossh -N -R 8080:localhost:80 [email protected]
Now, on the remote host, you can access monitoring.com HTTP by opening http://localhost:8080/ – the request will be forwarded through the tunnel to the monitoring host.
`remote.host$ autossh -N -L 8080:localhost:80 [email protected]`
This doesn’t work for me, but
`remote.host$ autossh -R 8080:localhost:80 [email protected]` works for me.
You are right, my last example was wrong, I wrote -L instead of -R. I updated the post. Thanks!
There is a way to monitor those ports and create an alert when it connection fail?
It depends on what you want to achieve. In the typical situation, the Autossh process is trying to connect over and over again. You can create a kind of watchdog which will let you know when the connection is down. Can you let me know what scenario are you thinking of?
Good info. Is autossh smart enough to re-resolve the IP address of (in your example) “monitoring.com” via DNS *each* time it needs to re-establish a connection to the remote SSH server? Or does autossh only resolve the IP for monitoring.com one time, at startup? I ask, because in my possible future use case the remote SSH server’s IP address might change occasionally without notice, although the DNS A-record for its IP address should always be kept up to date.
Yes, it is resolving DNS on subsequent connections. The question is: for how long your system caches the DNS responses? 🙂
I was using autossh on the DynDNS base connections with the frequently changed IP address (few times a day) and it was working.
Hello everyone! Help me plz!
Whats wrong? autossh want -M and say forwarding failed
I have try differents ports and same warning
serv1# autossh -M 1234 -R 1234:localhost:22 root@serv2
Warning: remote port forwarding failed for listen port 1234
Last login: Fri Jan 17 13:55:11 2020 from blueexternal
serv2#
Most likely something is already listening on this port you selected (1234). You can check if something is there using this command:
sudo netstat -plant | grep 1234
You can also simply try on the other port number. Something more random 🙂
hi, i learn you write, edit same autossh-tunnel.service in /etc/systemd/system/, but my terminal told me ssh: connect to host localhost port 6000: Connection refused.
Hello,
So, it looks like there is no tunnel created – you should review the logs to see what autossh reports. There can be an issue while trying to connect to the remote computer. If there is no connection, the tunnel is not created. Also, there is a possibility that your service doesn’t start. Once again – you have to check your logs.
The command under “What else can I do?” is exactly the same as the main example (except for different ports). How can it be “working the other way”? Will a tunnel work bidirectionally?
Hello Allan,
The tunnel is the way to connect two computers. It works in both directions. The question is – where is the “listener” and where is the “caller”. In the first example, we are calling the remote host from the monitoring host. On the monitoring host, we are sending data to the port 6000, they are transferred to the remote host and “pushed” to the port 22 of the remote host. In the “What else can I do” example, I assumed that the remote host will call to the local port 80 and this data will be transferred through SSH and pushed to the port 8080 of the monitoring host.
The bi-directional nature of the tunnel is required – if we are calling a remote host, we are expecting it to answer. And this answer comes to us through the same tunnel. So, in the first example, we are calling on the local port 6000, our data is transferred to the port 22 of the remote host. The remote host is answering on the port 22 which is transferred through SSH to port 6000 of the monitoring machine. In the “What else can I do” example, the remote host is calling on the local port 80, data is transferred to the port 8080 of my monitoring host. The monitoring host is answering to the local port of 8080 and this answer is transferred to the remote host to the local port 80.