Create more secure ssh keys
Create a key using elliptic curve cryptography (more secure):
ssh-keygen -a 100 -t ed25519
generate RSA key of length 4096 to file
ssh-keygen -t rsa -b 4096 -C "email@example.com" -f my_key
Generate md5 fingerprint of the key (works in newer ubuntu, 16):
ssh-keygen -lf ./my_key -E md5
see also: Upgrade Your SSH Key to Ed25519
How to prevent SSH from scanning all the keys in .ssh directory
$ ssh -o IdentitiesOnly=yes -F /dev/null -i ~/path/to/some_id_rsa firstname.lastname@example.org
The options are as follows:
-o IdentitiesOnly=yes- tells SSH to only use keys that are provided via the CLI and none from the
$HOME/.sshor via ssh-agent
-F /dev/null- disables the use of
-i ~/path/to/some_id_rsa- the key that you explicitly want to use for the connection
No strict server checking
To disable confirmation about unknown server fingerprints add this to command line:
Set correct permissions for .ssh directory
You may get and error while connecting to ssh if you have wrond permissions for .ssh directory on server for a given user.
Error message on client while
debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering RSA public key: /home/user-on-client/.ssh/YOUR_KEY debug1: Authentications that can continue: publickey debug1: No more authentication methods to try. Permission denied (publickey).
Error message on server:
Aug 11 10:55:21 comp sshd: Connection closed by 10.1.0.12 port 47794 [preauth]
And nothing more in logs.
The reason was that
.ssh directory on the server had too strict permissions:
dr-------- 2 user-on-server user-on-server 4096 Aug 11 10:54 .ssh/
Read only is not enough. It must be
chmod 700 .ssh
For authorized_keys file use the following premissions:
chmod 644 ~/.ssh/authorized_keys
Remote port forwarding
Take all the connections to
0.0.0.0:8080 of the remote machine (
and forward it to
localhost:80 on the local machine:
ssh -R 0.0.0.0:8080:localhost:80 -N email@example.com
The command above creates a general IPv4-only bind, which means that the port is accessible on all interfaces via IPv4.
This version binds to all interfaces individually:
ssh -R \*:8080:localhost:80 -N firstname.lastname@example.org
ssh -R "[::]:8080:localhost:80" -N email@example.com
The third version is probably technically equivalent to the first,
but again it creates only a single bind to
::, which means that the port is accessible via IPv6
natively and via IPv4 through IPv4-mapped IPv6 addresses (doesn’t work on Windows, OpenBSD).
(You need the quotes because
[::] could be interpreted as a glob otherwise.)
Full list of specifications for the remote forwarding.
-R [bind_address:]port:host:hostport -R [bind_address:]port:local_socket -R remote_socket:host:hostport -R remote_socket:local_socket
Specifies that connections to the given TCP port or Unix socket on the remote (server) host are to be forwarded to the given host and port, or Unix socket, on the local side.
By default, TCP listening sockets on the server will be bound to the loopback interface only. This may be overridden by specifying a bind_address. An empty bind_address, or the address ‘*’, indicates that the remote socket should listen on all interfaces. Specifying a remote bind_address will only succeed if the server’s
GatewayPorts option is enabled (see sshd_config(5)).
If the port argument is ‘0’, the listen port will be dynamically allocated on the server
and reported to the client at run time.
When used together with
-O forward the allocated port will be printed to the standard output.
When bind_address is omitted (as in your example), the port is bound on the loopback interface only.
Note that if you use OpenSSH sshd server, the server’s
option needs to be enabled (set to
clientspecified) for arbitrary interface to work
/etc/ssh/sshd_config on the server).
Otherwise (default value for this option is
the server will always force the port to be bound on the loopback interface only.
Local port forwarding
ssh -L localhost🔢localhost:5678 firstname.lastname@example.org
With this command
- all the connections to the
localhost:1234of the host machine
- are forwarded to
localhost:5678at the server (
Port forwarding between two machines that don’t have external ip’s using a server
On machine 1:
ssh -L localhost:10002:localhost:10001 email@example.com
On machine 2:
ssh -R localhost:10001:localhost:10000 firstname.lastname@example.org
Now when I access
localhost:10002 on machine 1 the request is redirected to
localhost:10000 of machine 2.
The connection goes through port
10001 of host
config for multiple port forwarding
How to forward multiple ports with one command. It is possible with a config file.
Imagine we want to forward local ports 22, 9999, 9998 to the corresponding ports of machine
192.168.1.2 using ssh on machine
In order to do that add the following to
Host all-port-forwards Hostname 192.168.1.1 User user LocalForward 22 192.168.1.2:22 LocalForward 9999 192.168.1.2:9999 LocalForward 9998 192.168.1.2:9998
Now you can run a single command:
Port forwarding on system startup with retry
We want our port to be forwarded on the startup of the system. Also we want to deal with failures: retry on disconnect etc.
Initial version - it doesn’t work
In my experience the approach didn’t really work. The built-in mechanisms of systemctl didn’t allow me to achieve robust restarting.
Create a file
[Unit] Description=tunnel ssh to server [Service] User=YOUR_LOCAL_USER ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -i PATH_TO_YOUR_PRIVATE_KEY -R REMOTE_SERVER_INTERFACE:PORT_ON_REMOTE_SERVER:localhost:LOCAL_PORT user_at_remote_server@REMOTE_SERVER StartLimitIntervalSec=10 StartLimitBurst=1 RestartSec=3 Restart=Always [Install] WantedBy=multi-user.target
Then enable and start
systemctl enable tunnelssh.service systemctl start tunnelssh.service systemctl status tunnelssh.service
Unfortunately it doesn’t work on startup. It says that the unit entered failed state and doesn’t restart. The problem is that
- our service may start before network connection is up. You may add
After=network-online.targetas suggested here but it doesn’t save you from the next issue.
- our server can be down for some time
- retry mechanism of systemd is somehow broken. I couldn’t make it work with configuration of burst intervals from here, here and here. And it seems I am not the only one.
(in the spirit of this solution)
[Unit] Description=tunnel ssh to server # After=network.target network-online.target multi-user.target # Requires=network-online.target [Service] User=YOUR_LOCAL_USER Environment=AUTOSSH_GATETIME=0 ExecStart=/usr/bin/autossh -M 0 -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -i PATH_TO_YOUR_PRIVATE_KEY -R REMOTE_SERVER_INTERFACE:PORT_ON_REMOTE_SERVER:localhost:LOCAL_PORT user_at_remote_server@REMOTE_SERVER RestartSec=5 Restart=Always [Install] WantedBy=multi-user.target
Configuring SSH server
Enable only ssh v2:
Disable password authentication. Replace corresponding values in
ChallengeResponseAuthentication no PasswordAuthentication no
Restrict SSH access to only user accounts that should have it. For example, you may create a group called “sshlogin” and add the group name as the value associated with the
AllowGroups variable located in the file
Then add your permitted SSH users to the group “sshlogin”, and restart the SSH service.
sudo adduser username sshlogin sudo systemctl restart sshd.service
Restarting ssh service
after each change in sshd_config you have to restart ssh service to enable the changes
Add user for ssh tunnel only
useradd sshtunnel -m -d /home/sshtunnel -s /bin/rbash passwd sshtunnel
.profile in the home directory of the user (in our example it is /home/sshtunnel/):
chmod 555 /home/sshtunnel/ cd /home/sshtunnel/ chmod 444 .bash_logout .bashrc .profile
Restrictions in sshd config:
Match User that-restricted-guy AllowTcpForwarding yes X11Forwarding no AllowAgentForwarding no ForceCommand /bin/false
Restricting root user
For security reason you should always block access to root user and group on a Linux or Unix-like systems.
First, make sure at least one user is allowed to use ‘su -‘ or ‘sudo’ command on the server.
Then add to
DenyUsers root DenyGroups root
set PermitRootLogin to
Save the file and restart the ssh service.
How To Configure SSH Key-Based Authentication on a Linux Server
See How To Configure SSH Key-Based Authentication on a Linux Server. Should I put public or private key to the server?
Use ssh authentication by key instead of password
How to load ssh key without placing it to ~/.ssh
You must load a key to the ssh agent running in the background.
To start the ssh-agent in the background:
You can add your SSH private key to the ssh-agent using
ssh-add and full path to the key:
Now you can for example do
git clone from github using ssh key.
see also 1
mount remote file system using ssh
sudo apt-get install sshfs sudo mkdir /mnt/droplet sudo sshfs -o allow_other,IdentityFile=~/.ssh/id_rsa email@example.com:/ /mnt/droplet
With identity files only:
sudo sshfs -o allow_other,IdentitiesOnly=yes,IdentityFile=~/.ssh/id_rsa firstname.lastname@example.org:/remote/path /mnt/local/path/
Specific settings for a website
I have a private key with a custom name in
~/.ssh/ add the .pub is uploaded to github. When I try to clone my repo, git returns
Cloning into 'repo'... Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
Probably git reads only keys with standard names (e.g. id_rsa).
To make it pick up your custome key you can create a config file
Host github.com IdentityFile ~/.ssh/your_custom_private_key IdentitiesOnly yes
How to run socks proxy. It’s a bit easier than using VPN because it doesn’t require sudo to launch. Also it doesn’t require to install anything on the server except openssh server.
ssh -D 1337 -q -C -N user@your_server.ip
-D defines the port on the local machine,
-q is quiet mode,
-N causes remote commands not to be executed, just straight port forwarding.
Then one can set up a socks proxy in the settings of the browser.
Faster retry after disconnecting
In order to make recovery faster after network issues use options
-o "ServerAliveInterval 2" -o "ServerAliveCountMax 2".
Alternatively one can add the following to
Host * ServerAliveInterval 2 ServerAliveCountMax 2
- sshd_config - SSH Server Configuration - nice guidelines