{"id":2303,"date":"2021-07-20T23:33:34","date_gmt":"2021-07-20T23:33:34","guid":{"rendered":"https:\/\/dft.wiki\/?p=2303"},"modified":"2026-06-08T22:34:31","modified_gmt":"2026-06-09T02:34:31","slug":"using-port-knocking-to-secure-ssh-in-ubuntu-20-04","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=2303","title":{"rendered":"Using Port Knocking to Secure SSH in Ubuntu"},"content":{"rendered":"<p><strong>Port Knocking<\/strong> allows you to open or close a remote port in a server&#8217;s firewall using a secret sequence of ports (with approximately 141 trillion possible combinations).<\/p>\n<p>It creates an extra layer of security for sensitive services such as SSH.<\/p>\n<hr \/>\n<p><strong>SERVER-SIDE<\/strong><\/p>\n<pre>sudo apt update\r\nsudo apt install knockd -y\r\nsudo nano \/etc\/knockd.conf<\/pre>\n<p>Edit the configuration accordingly:<\/p>\n<pre>[options]\r\n        UseSyslog\r\n\r\n[openSSH]\r\n        sequence    = <span style=\"color: #008000;\"><strong>54321,12345,10101<\/strong><\/span>\r\n        seq_timeout = <span style=\"color: #0000ff;\"><strong>5<\/strong><\/span>\r\n        command     = \/sbin\/iptables -A INPUT -s <strong><span style=\"color: #ff6600;\">%IP%<\/span><\/strong> -p tcp --dport 22 -j ACCEPT\r\n        tcpflags    = syn\r\n\r\n[closeSSH]\r\n        sequence    = <span style=\"color: #ff0000;\"><strong>12345,10101,54321<\/strong><\/span>\r\n        seq_timeout = <span style=\"color: #0000ff;\"><strong>5<\/strong><\/span>\r\n        command     = \/sbin\/iptables -D INPUT -s <span style=\"color: #ff6600;\"><strong>%IP%<\/strong><\/span> -p tcp --dport 22 -j ACCEPT\r\n        tcpflags    = syn\r\n<\/pre>\n<p>Note: the port will only be open to connections from the <strong><span style=\"color: #ff6600;\">%IP%<\/span><\/strong> that knocked with the correct sequence, remaining closed to everyone else. The timeout is set to <span style=\"color: #0000ff;\"><strong>5<\/strong><\/span> seconds from the first to the last knock, with no other ports knocked in between.<\/p>\n<p>Then,<\/p>\n<pre>sudo nano \/etc\/default\/knockd<\/pre>\n<p>Change the following:<\/p>\n<pre>START_KNOCKD=<strong>1<\/strong>\r\n<\/pre>\n<p>Start the service.<\/p>\n<pre>sudo systemctl start knockd\r\nsudo systemctl enable knockd\r\nsudo ufw enable\r\nsudo reboot<\/pre>\n<p>Ensure that port 22 is not open in the firewall.<\/p>\n<hr \/>\n<p><strong>CLIENT-SIDE<\/strong><\/p>\n<pre>sudo apt update\r\nsudo apt install knockd -y<\/pre>\n<p>Send the knock sequence to <span style=\"color: #008000;\">open<\/span> the port:<\/p>\n<pre>knock -v myserver.com <span style=\"color: #008000;\"><strong>54321 12345 10101<\/strong><span style=\"color: #000000;\"> --delay <strong>100<\/strong><\/span><\/span><\/pre>\n<p>Send the knock sequence to <span style=\"color: #ff0000;\">close<\/span> the port:<\/p>\n<pre>knock -v myserver.com <span style=\"color: #ff0000;\"><strong>12345 10101 54321<\/strong><span style=\"color: #000000;\"> --delay <strong>100<\/strong><\/span><\/span><\/pre>\n<p>Note: a delay of <strong>100<\/strong> milliseconds is recommended because packets may arrive out of order depending on the route they take.<\/p>\n<p>The sequence can also be sent using telnet:<\/p>\n<pre>timeout 0.1 telnet myserver.com <span style=\"color: #008000;\"><strong>54321<\/strong><\/span> ; timeout 0.1 telnet myserver.com <span style=\"color: #008000;\"><strong>12345<\/strong><\/span> ; timeout 0.1 telnet myserver.com <span style=\"color: #008000;\"><strong>10101<\/strong><\/span>\r\ntimeout 0.1 telnet myserver.com <span style=\"color: #ff0000;\"><strong>12345<\/strong><\/span> ; timeout 0.1 telnet myserver.com <strong><span style=\"color: #ff0000;\">10101<\/span><\/strong> ; timeout 0.1 telnet myserver.com <span style=\"color: #ff0000;\"><strong>54321<\/strong><\/span><\/pre>\n<hr \/>\n<p><strong>AUTHENTICATED PORT KNOCKING<\/strong><\/p>\n<p>LetMeIn offers authenticated port knocking with a simple authentication mechanism [<a href=\"https:\/\/github.com\/mbuesch\/letmein\">Link<\/a>].<\/p>\n<p><strong>Note:<\/strong> it requires <code>nftables<\/code> (not compatible with <code>iptables<\/code>) and the Rust toolchain. Encryption is based on a symmetric pre-shared key.<\/p>\n<p>Build and install on the <strong>Server<\/strong>.<\/p>\n<pre>sudo apt update\r\nsudo apt install git cargo build-essential -y\r\ngit clone https:\/\/github.com\/mbuesch\/letmein.git\r\ncd letmein\r\ncargo build --release --bin letmeind\r\nsudo cp target\/release\/letmeind \/usr\/local\/bin\/ \r\nsudo mkdir -p \/etc\/letmein \r\nsudo cp install-server.sh \/etc\/letmein\/\r\nsudo nano \/etc\/systemd\/system\/letmeind.service<\/pre>\n<p>Add the following content.<\/p>\n<pre>[Unit]\r\nDescription=Letmein port-knocking daemon\r\nAfter=network.target\r\n\r\n[Service]\r\nExecStart=\/usr\/local\/bin\/letmeind -c \/etc\/letmein\/letmeind.conf\r\nRestart=on-failure\r\n\r\n[Install]\r\nWantedBy=multi-user.target\r\n<\/pre>\n<p>Start the service.<\/p>\n<pre>sudo systemctl daemon-reload\r\nsudo systemctl enable --now letmeind\r\n<\/pre>\n<p>Configure <code>nftables<\/code>.<\/p>\n<pre>sudo apt install nftables\r\nsudo systemctl enable --now nftables\r\nsudo nano \/etc\/nftables\/letmein.conf<\/pre>\n<p>The following is an example for reference and should be tailored to your system&#8217;s requirements.<\/p>\n<pre>table inet filter {\r\n  chain input {\r\n    type filter hook input priority 0; policy drop;\r\n    iif \"lo\" accept\r\n    ct state established,related accept\r\n\r\n    # jump to letmein chain\r\n    jump letmein-input\r\n  }\r\n\r\n  chain letmein-input {\r\n    # LetMeIn will insert rules here to allow per-IP access to protected resources.\r\n    # Defines the default to reject\r\n    tcp dport 22 reject\r\n  }\r\n}\r\n<\/pre>\n<p>Apply the rules.<\/p>\n<pre>sudo nft -f \/etc\/nftables\/letmein.conf\r\nsudo systemctl restart nftables<\/pre>\n<p>Notify LetMeIn of the new rule set.<\/p>\n<pre>sudo nano \/etc\/letmein\/letmeind.conf<\/pre>\n<p>The content below is an example that will need to be updated once the client shares its key.<\/p>\n<pre>[KEYS]\r\n00000000 = \"PLACE_HOLDER_SECRET_KEY\"\r\n\r\n[RESOURCES]\r\n00000022 = \"port:22\"<\/pre>\n<p>On the <strong>Client<\/strong> side, after installing LetMeIn, generate a key (secret + user ID).<\/p>\n<pre>letmein gen-key -u 00000000<\/pre>\n<ol>\n<li>Copy the output (key) to <code>\/etc\/letmein\/letmein.conf<\/code> or <code>~\/.config\/letmein\/<\/code><\/li>\n<li>Paste the same key into the <strong>Server<\/strong> configuration.<\/li>\n<\/ol>\n<p>Then test knocking and connecting to the service.<\/p>\n<pre>letmein knock -u 00000000 server.example.com 22\r\nssh user@server.example.com<\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>Automate port knocking in the SSH workflow.<\/p>\n<pre>nano ~\/.ssh\/config<\/pre>\n<pre>Host server\r\n  HostName server.example.com\r\n  ProxyCommand bash -c \"letmein knock -u 00000000 %h 22; nc %h %p\"\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Port Knocking allows you to open or close a remote port in a server&#8217;s firewall [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,6],"tags":[],"class_list":["post-2303","post","type-post","status-publish","format-standard","hentry","category-linux","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2303"}],"version-history":[{"count":9,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2303\/revisions"}],"predecessor-version":[{"id":5719,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/2303\/revisions\/5719"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}