Skip to content

Instantly share code, notes, and snippets.

@yashkumaratri
Created December 31, 2018 05:19
Show Gist options
  • Star 83 You must be signed in to star a gist
  • Fork 42 You must be signed in to fork a gist
  • Save yashkumaratri/204755a85977586cebbb58dc971496da to your computer and use it in GitHub Desktop.
Save yashkumaratri/204755a85977586cebbb58dc971496da to your computer and use it in GitHub Desktop.
SSH into google colab
#CODE
#Generate root password
import random, string
password = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(20))
#Download ngrok
! wget -q -c -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
! unzip -qq -n ngrok-stable-linux-amd64.zip
#Setup sshd
! apt-get install -qq -o=Dpkg::Use-Pty=0 openssh-server pwgen > /dev/null
#Set root password
! echo root:$password | chpasswd
! mkdir -p /var/run/sshd
! echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
! echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
! echo "LD_LIBRARY_PATH=/usr/lib64-nvidia" >> /root/.bashrc
! echo "export LD_LIBRARY_PATH" >> /root/.bashrc
#Run sshd
get_ipython().system_raw('/usr/sbin/sshd -D &')
#Ask token
print("Copy authtoken from https://dashboard.ngrok.com/auth")
import getpass
authtoken = getpass.getpass()
#Create tunnel
get_ipython().system_raw('./ngrok authtoken $authtoken && ./ngrok tcp 22 &')
#Print root password
print("Root password: {}".format(password))
#Get public address
! curl -s http://localhost:4040/api/tunnels | python3 -c \
"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"
#Copy authentication token after authenticating your ID using google or github and
###./ngrok authtoken 616pgtVvEMKxN6C********************************************
Password will be generated
How to SSH ?
ssh root@0.tcp.ngrok.io -p 10965 <-- port number dictated in colab output
passord : In colab output
@clemente0731
Copy link

@KShivendu

您只能尝试使用
! curl -s http://localhost:4040/api/tunnels

THANKS,IT WORKS
THANK YOU FOR YOUR WORK~!!

@doantientai
Copy link

doantientai commented May 19, 2020

Thank you for your work! I followed your instruction. On google colab, everything looks fine, but when I tried ssh in my terminal. It gives me the error below. Does anyone have the same problem? Please help.
ssh_exchange_identification: Connection closed by remote host

@ethanm88
Copy link

@doantientai I ran into the same problem.

@Laenka-Oss
Copy link

Laenka-Oss commented May 31, 2020

Am trying to work with Windows 10 <===> Google Colab and I ran into thesame problem.
! curl -s http://localhost:4040/api/tunnel gives the public url "public_url":"tcp://0.tcp.ngrok.io:17410" among others but does not show the password. Somehow, I changed the port to:
! curl -s http://localhost:4041/api/tunnel and it diplayed a password like JoeKrRmoT4GLqL2Cq36D which I used for SSHing.

C:\Users\me>ssh root@0.tcp.ngrok.io -p 17410. To confirm that I am connected to the instance:
!hostname on Google colab gives me 3pp4f682af3f similar to root@3pp4f682af3f:~# on my Windows cmd.

@ethanm88
Copy link

I just found a solution to this that's working for me. See this Stack Overflow post: https://stackoverflow.com/questions/48459804/how-can-i-ssh-to-google-colaboratory-vm/53252985#53252985.

@minhtus
Copy link

minhtus commented Jun 19, 2020

Hi, I also got the ssh_exchange_identification: Connection closed by remote host because sshd unable to start because of misconfiguration. Looks like echo command append the quotes together into configuration file, so removing those quote fix for me. Hope this helps.

!echo PermitRootLogin yes >> /etc/ssh/sshd_config
!echo PasswordAuthentication yes >> /etc/ssh/sshd_config
!echo LD_LIBRARY_PATH=/usr/lib64-nvidia >> /root/.bashrc
!echo export LD_LIBRARY_PATH >> /root/.bashrc

@vdivakar
Copy link

vdivakar commented Jun 25, 2020

Hi, thanks for the solution. I faced a few problems, so I had put the steps together here with screenshots:
Will be helpful for someone who is stuck.
https://github.com/vdivakar/Colab-SSH-and-GDrive

@libinruan
Copy link

Hi, thanks for the solution. I faced a few problems, so I had put the steps together here with screenshots:
Will be helpful for someone who is stuck.
https://github.com/vdivakar/Colab-SSH-and-GDrive

Hi @vdivakar,

Is it possible to specify a user name instead of root when configuring the SSH setting?

@rituparnakhaund
Copy link

Hi . Even after entering the correct passowrd , I face an issue here. Someone kindly help.
C:\Users\ritup>ssh root@0.tcp.ngrok.io -p 11026
Warning: Permanently added the ECDSA host key for IP address '[3.13.191.225]:11026' to the list of known hosts.
root@0.tcp.ngrok.io's password:
Permission denied, please try again.

@vitalii-ui
Copy link

ssh login password is wrong

@ShreyJ1729
Copy link

This method works without gpu, but when I enable gpu on colab, it says permission denied and gives the json error. Does anyone know a workaround?

@chhaileng
Copy link

chhaileng commented Jun 4, 2021

You can use reverse shell method to get a shell on Colab:

1. Getting reverse shell

On local machine terminal 1, run:

$ ngrok tcp 8000

On local machine terminal 2, run:

$ nc -lvnp 8000

nc or ncat or netcat must be installed on your machine

On Colab, run:

! bash -i >& /dev/tcp/<NGROK_HOSTNAME>/<NGROK_PORT> 0>&1

2. Upgrading shell to fully interactive TTYs (recommend)

If you are on Mac and using ZSH shell, please switch to BASH shell first before running nc -lvnp 8000

On local machine terminal 2 (this terminal now should be a shell of Colab), run:

# python -c 'import pty; pty.spawn("/bin/bash")'

Press Ctrl-Z (you are now back to shell on your machine) then run:

$ stty raw -echo
$ fg

You are now back to Colab shell. if you see nothing, run:

reset

All Done!! You also can update these env variables if you want.

# export TERM=xterm-256color
# stty rows <num> columns <cols>

@h5gq3
Copy link

h5gq3 commented Jun 11, 2021

You can use reverse shell method to get a shell on Colab:

1. Getting reverse shell

On local machine terminal 1, run:

$ ngrok tcp 8000

On local machine terminal 2, run:

$ nc -lvnp 8000

nc or ncat or netcat must be installed on your machine

On Colab, run:

! bash -i >& /dev/tcp/<NGROK_HOSTNAME>/<NGROK_PORT> 0>&1

2. Upgrading shell to fully interactive TTYs (recommend)

If you are on Mac and using ZSH shell, please switch to BASH shell first before running nc -lvnp 8000

On local machine terminal 2 (this terminal now should be a shell of Colab), run:

# python -c 'import pty; pty.spawn("/bin/bash")'

Press Ctrl-Z (you are now back to shell on your machine) then run:

$ stty raw -echo
$ fg

You are now back to Colab shell. if you see nothing, run:

reset

All Done!! You also can update these env variables if you want.

# export TERM=xterm-256color
# stty rows <num> columns <cols>

any idea why reverse shell exits after some time when I've switched windows?

@VickTheRock
Copy link

import secrets, json, re, pathlib, getpass

This script is not fully made by me!

Parts were copied from other people.

Installing SSH server

!apt-get update > /dev/null
!apt-get install -qq -o=Dpkg::Use-Pty=0 openssh-server > /dev/null

Installing ngrok

!wget -nv -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
!unzip -n ngrok-stable-linux-amd64.zip

Creating user accounts

root_password = secrets.token_urlsafe()
user_password = secrets.token_urlsafe()
user_name = "colab"
!useradd -s /bin/bash -m $user_name
!echo root:$root_password | chpasswd
!echo $user_name:$user_password | chpasswd
!usermod -aG sudo $user_name
!mkdir -p /run/sshd
!service ssh restart

Installing VNC related stuff

libjpeg_ver = "2.0.4"
virtualGL_ver = "2.6.3"
turboVNC_ver = "2.2.5"

libjpeg_url = "https://iweb.dl.sourceforge.net/project/libjpeg-turbo/{0}/libjpeg-turbo-official_{0}_amd64.deb".format(libjpeg_ver)
virtualGL_url = "https://iweb.dl.sourceforge.net/project/virtualgl/{0}/virtualgl_{0}_amd64.deb".format(virtualGL_ver)
turboVNC_url = "https://iweb.dl.sourceforge.net/project/turbovnc/{0}/turbovnc_{0}_amd64.deb".format(turboVNC_ver)

!curl -fsSL -O $libjpeg_url
!curl -fsSL -O $virtualGL_url
!curl -fsSL -O $turboVNC_url
!dpkg -i *.deb

Installing the desktop environment and some additional software

!add-apt-repository ppa:x2go/stable -y
!apt-get update
!apt-get -qq install xfce4 xfce4-terminal xfce4-taskmanager htop leafpad chromium-browser x2goserver x2goserver-xsession > /dev/null

Setting up TurboVNC

vnc_sec_conf_p = pathlib.Path("/etc/turbovncserver-security.conf")
vnc_sec_conf_p.write_text("""
no-remote-connections
no-httpd
no-x11-tcp-connections
""")

Installing Nvidia drivers

!wget -nv -nc http://us.download.nvidia.com/tesla/410.104/NVIDIA-Linux-x86_64-410.104.run
!chmod +x NVIDIA-Linux-x86_64-410.104.run
!echo 1 | ./NVIDIA-Linux-x86_64-410.104.run --no-kernel-module --ui=none

Make sure GPU is indeed working

!export LD_PRELOAD=/usr/lib64-nvidia/libnvidia-ml.so
!nvidia-smi -L

Creating a headless screen

!nvidia-xconfig -a --allow-empty-initial-configuration --virtual=1920x1080 --busid PCI:0:4:0

Edit xorg.conf so that Nvidia driver is loaded on seat-1.

with open("/etc/X11/xorg.conf", "r") as f:
conf = f.read()
conf = re.sub('(Section "Device".*?)(EndSection)', '\1 MatchSeat "seat-1"\n\2', conf, 1, re.DOTALL)

with open("/etc/X11/xorg.conf", "w") as f:
f.write(conf)

!/opt/VirtualGL/bin/vglserver_config -config +s +f

Setting up ngrok

if not pathlib.Path('/root/.ngrok2/ngrok.yml').exists():
print("---")
print("Copy and paste your tunnel authtoken from https://dashboard.ngrok.com/auth")
print("(You need to sign up for ngrok and login)")
ngrok_token = getpass.getpass()
!./ngrok authtoken $ngrok_token

print("Select your ngrok region:")
print("us - United States (Ohio)")
print("eu - Europe (Frankfurt)")
print("ap - Asia/Pacific (Singapore)")
print("au - Australia (Sydney)")
region = input()

get_ipython().system_raw("./ngrok tcp -region {} 22 &".format(region))
!sleep 1
tunnels = !curl -s http://localhost:4040/api/tunnels
url = json.loads(tunnels[0])["tunnels"][0]["public_url"]
m = re.match("tcp://(.+):(\d+)", url)
hostname = m.group(1)
port = m.group(2)
ssh_common_options = "-o UserKnownHostsFile=/dev/null -o ServerAliveInterval=60"

Give the user login credentials etc.

print("✂️"*24)
print("root password: {}".format(root_password))
print("{} password: {}".format(user_name, user_password))
print("✂️"*24)
print("---")
print("Command to connect to the ssh server:")
print("✂️"*24)
print("ssh {} -p {} {}@{}".format(ssh_common_options, port, user_name, hostname))
print("✂️"*24)
print("---")
print("If you use X2Go:")
print("✂️"*24)
print("ssh {} -L 2222:localhost:22 -p {} {}@{}".format(ssh_common_options, port, user_name, hostname))
print("✂️"*24)
print("---")
print("If you use VNC:")
print("✂️"*24)
print("ssh {} -L 5901:localhost:5901 -p {} {}@{}".format(ssh_common_options, port, user_name, hostname))
print("✂️"*24)

And finally run the Xorg server

get_ipython().system_raw("Xorg -seat seat-1 -allowMouseOpenFail -novtswitch -nolisten tcp &")

vncrun_py = pathlib.Path("vncrun.py")
vncrun_py.write_text("""
import subprocess, secrets, pathlib

vnc_passwd = secrets.token_urlsafe()[:8]
vnc_viewonly_passwd = secrets.token_urlsafe()[:8]
print("✂️"*24)
print("VNC password: {}".format(vnc_passwd))
print("VNC view only password: {}".format(vnc_viewonly_passwd))
print("✂️"*24)
vncpasswd_input = "{0}\n{1}".format(vnc_passwd, vnc_viewonly_passwd)
vnc_user_dir = pathlib.Path.home().joinpath(".vnc")
vnc_user_dir.mkdir(exist_ok=True)
vnc_user_passwd = vnc_user_dir.joinpath("passwd")
with vnc_user_passwd.open('wb') as f:
subprocess.run(
["/opt/TurboVNC/bin/vncpasswd", "-f"],
stdout=f,
input=vncpasswd_input,
universal_newlines=True)
vnc_user_passwd.chmod(0o600)

subprocess.run(
["/opt/TurboVNC/bin/vncserver"]
)
""")

!su -c'python3 vncrun.py' $user_name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment