{"id":57,"date":"2024-06-29T13:16:15","date_gmt":"2024-06-29T13:16:15","guid":{"rendered":"http:\/\/blog.ltzs.us\/?p=57"},"modified":"2025-04-11T20:52:42","modified_gmt":"2025-04-11T20:52:42","slug":"reverse-ssh-tunnel","status":"publish","type":"post","link":"http:\/\/blog.ltzs.us\/?p=57","title":{"rendered":"Reverse SSH tunnel"},"content":{"rendered":"\n<p>*edited 5apr25 to add sshtunnel user<\/p>\n\n\n\n<p>Some cell carriers and ISPs do carrier-grade network address translation (CGNAT) so you don&#8217;t get a public IPv4. So to connect to a computer (or network) behind CGNAT, you need a virtual private server (VPS) or some other machine that <em>is<\/em> reachable directly. You can then create a tunnel between the CGNAT&#8217;d machine to the exposed machine and use that tunnel to connect directly. There are many ways to skin a cat (Cloudflare, Tailscale, Headscale, RealVNC) but my method uses SSH and OpenVPN since it doesn&#8217;t rely on cloud services. I used to use autossh (of which there are <a href=\"https:\/\/dadhacks.org\/tag\/autossh\/\">various<\/a> <a href=\"https:\/\/www.it-react.com\/index.php\/2020\/01\/06\/how-to-setup-reverse-ssh-tunnel-on-linux\/\">guides<\/a>), but systemd renders <a href=\"https:\/\/unix.stackexchange.com\/questions\/423795\/is-autossh-redundant-with-systemd\">it<\/a> <a href=\"https:\/\/dev.to\/bulletmark\/create-a-reverse-ssh-tunnel-for-remote-access-to-a-restricted-machine-1ma0\">unnecessary<\/a>, and was more complicated (some solutions use old initd methods). I use the guide <a href=\"https:\/\/blog.stigok.com\/2018\/04\/22\/self-healing-reverse-ssh-systemd-service.html\">here<\/a>, but will recreate it here in case it disappears. (credit: <a href=\"https:\/\/blog.stigok.com\">https:\/\/blog.stigok.com<\/a>). Options used:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">-g  Allows remote hosts to connect to local forwarded ports\n-N  Do not execute a remote command\n-T  Disable pseudo-terminal allocation\n-o  Used to give options in the format used in the configuration file (man ssh_config)\n  ServerAliveInterval   Interval in seconds to ping the server while connection has been inactive\n  ExitOnForwardFailure  Whether to terminate the connection if it cannot set up all requested port forwards\n-R  Forward given remote TCP port (22221) to the local port (22)\n-v  Verbose mode. More v&#039;s increase verbosity.<\/code><\/pre>\n\n\n\n<p>Create a service file in \/lib\/systemd\/system or \/etc\/systemd\/system called ssh-reverse.service <mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>sudo nano \/etc\/systemd\/system\/ssh-reverse.service<\/code><\/mark> and put in the following:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">[Unit]\nDescription=Reverse SSH connection\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=\/usr\/bin\/ssh -vvv -g -N -T -o &quot;ServerAliveInterval 10&quot; -o &quot;ExitOnForwardFailure yes&quot; -o StrictHostKeyChecking=no -R 21194:localhost:1194 -R 20022:localhost:22 sshtunnel@12.34.56.78\nRestart=always\nRestartSec=5s\n\n[Install]\nWantedBy=default.target<\/code><\/pre>\n\n\n\n<p>Just add the ports you want to forward (in my case ssh and openvpn) and put in the ip address of the VPS. You will need to adjust the <mark style=\"background-color:#fcb900\" class=\"has-inline-color\">\/etc\/ssh\/sshd_config<\/mark> settings on the VPS to allow port forwarding as follows:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">AllowAgentForwarding yes\nAllowTcpForwarding yes\nGatewayPorts yes\nX11Forwarding yes\nTCPKeepAlive yes\nClientAliveInterval 300\nClientAliveCountMax 2\nPermitTunnel yes<\/code><\/pre>\n\n\n\n<p>Not sure if all those are strictly necessary for it to work, but at a minimum <mark style=\"background-color:#fcb900\" class=\"has-inline-color\">GatewayPorts yes<\/mark> is. For OpenVPN to work, a few more have to be on, like AllowTcpForwarding, PermitTunnel, and TCPKeepAlive.<\/p>\n\n\n\n<p>You&#8217;ll then want to create a sshtunnel user on the VPS that has privileges to port forward but nothing else. Credit from <a href=\"https:\/\/unix.stackexchange.com\/questions\/14312\/how-to-restrict-an-ssh-user-to-only-allow-ssh-tunneling\">here<\/a>.<\/p>\n\n\n\n<p><mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>useradd sshtunnel -m -d \/home\/sshtunnel -s \/bin\/true<\/code><\/mark><\/p>\n\n\n\n<p>For the initial SSH connection from the host to the VPS, it needs to be done manually to add the fingerprint to known_hosts (on the host machine) (in <mark style=\"background-color:#fcb900\" class=\"has-inline-color\">\/root\/.ssh\/known_hosts<\/mark>). And need to use ssh-keygen to generate the public\/private key pair to allow password-less connection. Once the id_rsa.pub is generated on the host, it can be copied to the VPS manually to \/sshtunnel\/.ssh\/authorized_keys, or you can use <mark style=\"background-color:#fcb900\" class=\"has-inline-color has-black-color\">ssh-copy-id $target_host<\/mark> if you can login with a password. I&#8217;ve heard that allowing remote root ssh login via password is not a good idea, so you should probably turn that off afterwards. Make sure \/etc\/ssh\/sshd_config on the VPS has the following lines:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">PermitRootLogin prohibit-password #or without-password, which is deprecated\nPubkeyAuthentication yes<\/code><\/pre>\n\n\n\n<p>I&#8217;ve run into issues with the fingerprint adding, and altering the service file to include <mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>-o StrictHostKeyChecking=no<\/code><\/mark> in the ssh line takes care of it.<\/p>\n\n\n\n<p>Final step is to save the service file, then do <mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>sudo systemctl daemon-reload<\/code><\/mark>, <mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>sudo systemctl enable ssh-reverse<\/code><\/mark>, <mark style=\"background-color:#fcb900\" class=\"has-inline-color\"><code>sudo systemctl start ssh-reverse<\/code><\/mark><\/p>\n","protected":false},"excerpt":{"rendered":"<p>*edited 5apr25 to add sshtunnel user Some cell carriers and ISPs do carrier-grade network address translation (CGNAT) so you don&#8217;t get a public IPv4. So to connect to a computer (or network) behind CGNAT, you need a virtual private server (VPS) or some other machine that is reachable directly. You can then create a tunnel&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-57","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/posts\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=57"}],"version-history":[{"count":14,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/posts\/57\/revisions"}],"predecessor-version":[{"id":291,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=\/wp\/v2\/posts\/57\/revisions\/291"}],"wp:attachment":[{"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.ltzs.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}