Given a internal server without public IP, this cookbook aims to instruct how to use port forward techniques to access resources of it with the help of the outside server with public IP.
Preparation
- One internal server without public IP, has an account named
innerServer
. This server has resources you want to access remotely. - One global server with public IP
xx.xx.xx.xx
, has an account namedpublicServer
. This server is used to forward ports. - Personal PC, named
personalPC
. This one is the only PC around you, enabling you to fetch data from remote nodes.
Target
Manipulate personalPC
to access remote resources from innerServer
through publicServer
.
Procedure
Forward the app port to the public server
1. Remote port forwarding to enable publicServer
to listen applications residing in innerServer
. Run the command on innerServer
:
ssh -NfR <remote_port>:localhost:<inner_port> publicServer@xx.xx.xx.xx
where <remote_port>
is the port specified as the listening port on publicServer
, and inner_port
is the port of the running application on innerServer
, e.g. inner_port
sets to 22 as ssh service is to be forwarded.
If the error ssh : Permission denied (publickey,gssapi-with-mic)
appears, please check FAQ.
It is also helpful to check whether the ports are being listened at backend both on two server:
netstat -nultp | grep <port>
2. Test on publicServer
to check if port forwarding works. Run command on publicServer
:
ssh -p <remote_port> innerServer@localhost
Note that the innerServer is the account name of innerServer
.
Then there are two ways to fetch data to your local PC.
Forward the listening port to the local server
3. Local port forwarding let a connection from a local computer to another server. Run the command on personalPC
:
ssh -NfL <local_port>:localhost:<remote_port> publicServer@xx.xx.xx.xx
where remote_port
is the same to the previous setting in remote forwarding step, and the local_port
is an available port on your personal PC.
Info: If the SSH connection and the port forwarding both go in the same direction, then it is said to be a local forwarding, otherwise remote forwarding.
4. Test connection on your personal PC. Execute the command following or use the third-party app like MobaXTerm to log in the innerServer
:
ssh -p <local_port> innerServer@xx.xx.xx.xx
While it would be convenient to fetch remotely in this way, every time local forwarding the port from the local PC to the public server is not handy. Then comes another way.
Access resources directly through visiting the remote server
Without step 3 and 4, you directly access the listening port of the publicServer
. Try the following command on personalPC
:
ssh -p <remote_port> innerServer@xx.xx.xx.xx
If time out comes out or the connection failed, it is time to check the firewall checking of the publicServer
. The following steps are helpful to the public server deployed on google cloud.
Firewall setting
Google cloud has a series of extremely strict regulations and mechanism to prevent from DDOS and other sorts of malevolent attacks. Thus the available port on the google engine is limited and have to be appended whenever it needed. Google issues a useful firewall documentation to manage ports. Check this link for more info.
Shortly, you could firstly try to find out where Firewall Rules option is available by going to look at VPC Networking title of the google cloud console. Then in the firewall tab, all port rules are listed.
It is a good way to append personal rules by click CREATE FIREWALL RULE, but it is more recommended to use commands on Google Engine:
1. First authorize gcloud to access the Cloud Platform with personal credentials:
gcloud auth login
filling in the verification code through the link command line provides.
2. Append the port through the following command:
gcloud compute firewall-rules create <rule_name> --allow tcp:<remote_port>
where the rule_name
should satisfy the naming rule, and remote_port
is the same to the above specified remote port.
Then you could return to the VPC Networking website to check if the rule is appended. Now it is time to test if you could access the innerServer
directly from you personalPC
through this remote_port
on publicServer
Advanced
The connection frequently invalid and too tricky to deal with the disconnection? Here is a more convenient way to automatically check the tunnel you built between two server.
Waive password to log in
1. Build public&private ssh key on innerServer
, execute:
ssh-keygen
then id_rsa
, id_rsa.pub
and known_hosts
three files are generated in ~/.ssh
2. Add ssh key to the public server to authorize identity, then no more password needed next time when log in. Here are two ways to reach this:
- copy the content of
id_rsa.pub
ofinnerServer
to~/.ssh/authorized_keys
ofpublicServer
. - resort to
ssh-copy-id
command:ssh-copy-id <publicServer>@xx.xx.xx.xx
, which will automatically copy the public key to the authorized list.
Auto reconnect the broken ssh
Specify a new port <listen_port>
to listen the state of the ssh connection and replace ssh
with autossh
instructions:
autossh -M <listen_port> -NfR <remote_port>:localhost:<inner_port> publicServer@xx.xx.xx.xx
warning: The -f
flag of autossh
is different with the one in ssh
, which means autossh
will run in the background without a chance to input password. Thus, it is preferable to append id_rsa.pub
of InnerServer
to authorized_keys
of publicServer
before using autossh -f
More extention
Fill the above instructions in the startup setting in terms of the system version so as to launch the autossh service whenever the system starts up:
SysV:/etc/inid.d/autossh
Upstart: /etc/init/autossh.conf
systemd: /usr/lib/systemd/system/autossh.service
Startup script example
Here is an example of a xxx.service
file as Ubuntu startup script under /etc/systemd/systme/
:
[Unit]
Description=Port forward
After=network.target syslog.target
Wants=network.target default.target
[Service]
Type=forking
User=lz
Group=lz
ExecStart=/bin/bash /home/lz/potter/scripts/portf.sh
ExecReload=/bin/pkill autossh && /home/lz/potter/scripts/portf.sh
ExecStop=/bin/pkill autossh
[Install]
WantedBy=default.target
portf.sh
script is to describe which port to forward under specified path:
autossh -M 9230 -NfR 9220:localhost:22 root@xx.xx.xx.xx
autossh -M 8895 -NfR 8894:localhost:8894 root@xx.xx.xx.xx
then refresh the system daemon and start your service:
sudo systemctl daemon-reload
systemctl start xxx.service
FAQ
SSH Permission Denied
It is common problem happens on the newly deployed server.
Solved it by amending in /etc/ssh/sshd_config
:
PasswordAuthentication yes
, GatewayPorts yes
and also PermitRootLogin yes
if you use root identity to log in, then re-started the service using service sshd restart
.