VOOZH about

URL: https://www.digitalocean.com/community/tutorials/how-to-configure-port-knocking-using-only-iptables-on-an-ubuntu-vps?comment=14274

⇱ How To Configure Port Knocking Using Only Iptables on an Ubuntu VPS | DigitalOcean


How To Configure Port Knocking Using Only Iptables on an Ubuntu VPS

Published on January 18, 2014
👁 How To Configure Port Knocking Using Only Iptables on an Ubuntu VPS

Introduction


Servers that are connected to the internet are subjected to all manners of attacks and probes by malicious users, scripts, and automated bots. It is sometimes a balancing act to secure your server from attacks without affecting legitimate access to your services and resources.

Certain types of services are meant to be visible and consumable to the public internet. An example of this is a web server. Other types of services are typically used by only the system administrator or a select number of individuals and are not meant to be a public resource.

A concept known as port knocking is a way of shielding processes that fit into the latter description. Port knocking works by covering the ports associated with a process behind a firewall until a specific, predetermined sequence of network activity occurs. At this point, the port knocking service reconfigures the firewall to allow access to the protected application.

In a previous article, we discussed how to enable port knocking through a specially designed port knocking service. In this article, we will discuss an alternative method of configuring port knocking.

This method does not rely on an external application to alter the firewall rules. Instead, the iptables firewall can take advantage of a state-tracking module called “recent” to do all of this within the firewall rules themselves.

We will be configuring this on an Ubuntu 12.04 droplet, but any kind of Linux server should operate in a similar manner.

Note: This tutorial covers IPv4 security. In Linux, IPv6 security is maintained separately from IPv4. For example, “iptables” only maintains firewall rules for IPv4 addresses but it has an IPv6 counterpart called “ip6tables”, which can be used to maintain firewall rules for IPv6 network addresses.

If your VPS is configured for IPv6, please remember to secure both your IPv4 and IPv6 network interfaces with the appropriate tools. For more information about IPv6 tools, refer to this guide: How To Configure Tools to Use IPv6 on a Linux VPS

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

Tutorial Series: How To Implement Port Knocking to Obscure your SSH Daemon

Port knocking is a security concept that involves dynamically altering firewall rules to expose access to an otherwise protected service. This is done by sending a pre-configured special packet, or a pattern of packets that the port knocking software is listening for. In this series, we will discuss a variety of ways to configure port knocking to add an extra layer of security around your SSH daemon.

About the author

Former Senior Technical Writer at DigitalOcean, specializing in DevOps topics across multiple Linux distributions, including Ubuntu 18.04, 20.04, 22.04, as well as Debian 10 and 11.

Still looking for an answer?

Was this helpful?

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

I believe you have a vulnerability in this tutorial that would allow an attacker to discover your secret port numbers. The problem is the -j DROP part. The default behavior would be to forward the SYN to the machine behind the firewall and it would issue a tcp-reset packet that would be sent back to the attacker signifying that the port is truly unused. So the dropping can be used to detect that this port is “special.” This means that the option is to either leave it unchanged with a -j RETURN option and leverage the natural mechanisms (the port will get refused exactly like an unbound port), or imitate the final server’s behavior using -j REJECT --reject-with tcp-reset . The RETURN keyword is needed to prevent the rules in the chain from being processed further as opposed to not giving any -j target. EDIT: Now that I think of it, the -j RETURN thing is actually superior to the tcp-reset because not only will it mimic any custom port scanning refusal you may implement separately, but it will also let the port be used as an ephemeral port by any application! If the port was just blocked, the attacker could analyze the traffic of any ephemeral-port using service and notice which ports never got used, or worse (in case of FTP), which ports got RESET (!) despite being negotiated over the FTP command channel.

zwzserver:

I appreciate you taking the time to leave such good feedback!

While using a DROP on special ports could allow an attacker to distinguish between the important ports and legitimately unused ports, I don’t think the rules in this article put you in that situation.

Here is a gist of the finished ruleset:

https://gist.github.com/imchairmanm/af3816fdc288796f019f

If I’m following the flow of the packets correctly, they would enter through the INPUT chain and all packets that do not match the first three rules (established, local interface, or web server) will jump to the KNOCKING chain.

From here, packets are sent to other chains depending on whether they have flags indicating that they have successfully passed a certain stage of the knocking pattern. The last jump is to GATE1, which is where we start our knock filtering.

The GATE1 chain drops packets that target the correct port, but it <em>also</em> drops all other packets. Since the only difference is an internal one (flagging the source IP as having passed the first port test), the same information will be returned to the user in either case.

The other gates drop packets that match the next rules and then send them back to GATE1 otherwise, resulting in the same situation.

The only user-added chain that results with anything other than a drop is the PASSED chain.

Let me know if I’m mistaken in this assessment. I’m pretty sure that the packets are dropped regardless (with a rule, not a policy). If you think any of this is incorrect though, feel free to get back to me.

Thanks again!

Justin, great series of tutorials. Any chance you might do the same for Moxie Marlinspike’s port knocking tool?

Very nice tutorial. Can you tell me it is possible add log every knock to /var/log ?

Also, Justin, there is a small typo in your knocking script: namp -> nmap.

Bravo! Excelent post. Thanks you for your dedication.

Any idea why mine isn’t working? Please do help. In the meantime, I’ve just set port 22 to be accessible… if I don’t, my connection to 22 times out, whether I try the knocking sequence first or not at all.

EDIT: If GATE1 sets name AUTH3, it works. AUTH1 and AUTH2 gives the above issue, even if the 10 second timeouts are extended to 30. P.S.: I literally do have the 1111 2222 3333 ports set. Intending to change them once this works correctly.

Chain INPUT (policy ACCEPT)
target prot opt source destination 
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED 
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:25565 
KNOCKING all -- 0.0.0.0/0 0.0.0.0/0 

Chain FORWARD (policy ACCEPT)
target prot opt source destination 

Chain OUTPUT (policy ACCEPT)
target prot opt source destination 

Chain GATE1 (4 references)
target prot opt source destination 
DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:1111 recent: SET name: AUTH1 side: source 
DROP all -- 0.0.0.0/0 0.0.0.0/0 

Chain GATE2 (1 references)
target prot opt source destination 
 all -- 0.0.0.0/0 0.0.0.0/0 recent: REMOVE name: AUTH1 side: source 
DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:2222 recent: SET name: AUTH2 side: source 
GATE1 all -- 0.0.0.0/0 0.0.0.0/0 

Chain GATE3 (1 references)
target prot opt source destination 
 all -- 0.0.0.0/0 0.0.0.0/0 recent: REMOVE name: AUTH2 side: source 
DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3333 recent: SET name: AUTH3 side: source 
GATE1 all -- 0.0.0.0/0 0.0.0.0/0 

Chain KNOCKING (1 references)
target prot opt source destination 
PASSED all -- 0.0.0.0/0 0.0.0.0/0 recent: CHECK seconds: 30 name: AUTH3 side: source 
GATE3 all -- 0.0.0.0/0 0.0.0.0/0 recent: CHECK seconds: 10 name: AUTH2 side: source 
GATE2 all -- 0.0.0.0/0 0.0.0.0/0 recent: CHECK seconds: 10 name: AUTH1 side: source 
GATE1 all -- 0.0.0.0/0 0.0.0.0/0 

Chain PASSED (1 references)
target prot opt source destination 
 all -- 0.0.0.0/0 0.0.0.0/0 recent: REMOVE name: AUTH3 side: source 
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 
GATE1 all -- 0.0.0.0/0 0.0.0.0/0 

I am running the following (though uncensored) to attempt knocking in:

for x in 1111 2222 3333; do nmap -Pn --host_timeout 201 --max-retries 0 -p $x XXX.XXX.XXX.XXX && sleep 1; done && ssh username@XXX.XXX.XXX.XXX

Digital Ocean has really great tutorials.

I have a question. Is there any advantage to configuring IP tables over using knockd? It seems easier. Does it use a lot of resources?

Great post! Especially that only iptables is required. But i found that the knocking packets were somehow sent like this in our enviroment:

knock port 1
knock port 1
...knock port 1 several times ...
knock port 2
knock port 2
...knock port 2 several times ...
knock port 3
knock port 3
...knock port 3 several times ...

It’s very hard to see a exact sequence of 1 2 3 and the SSH port is not opened.

So i modify the rules like this and it seems works quite well.

-A GATE1 -p tcp --dport $PORT1 -m recent --name AUTH1 --set -j DROP
-A GATE1 -j DROP

-A GATE2 -p tcp --dport $PORT1 -j DROP # add to deal with the repeated port 1 knocking
-A GATE2 -m recent --name AUTH1 --remove
-A GATE2 -p tcp --dport $PORT2 -m recent --name AUTH2 --set -j DROP
-A GATE2 -j GATE1

-A GATE3 -p tcp --dport $PORT2 -j DROP # add to deal with the repeated port 2 knocking
-A GATE3 -m recent --name AUTH2 --remove
-A GATE3 -p tcp --dport $PORT3 -m recent --name AUTH3 --set -j DROP
-A GATE3 -j GATE1

-A PASSED -p tcp --dport $PORT3 -j DROP # add to deal with the repeated port 3 knocking
#-A PASSED -m recent --name AUTH3 --remove # comment out so that i can establish several ssh connections
-A PASSED -p tcp --dport 22 -j ACCEPT
-A PASSED -j GATE1

# add --reap to purge entries automaticly 
-A KNOCKING -m recent --reap --rcheck --seconds 30 --name AUTH3 -j PASSED
-A KNOCKING -m recent --reap --rcheck --seconds 10 --name AUTH2 -j GATE3
-A KNOCKING -m recent --reap --rcheck --seconds 10 --name AUTH1 -j GATE2
-A KNOCKING -j GATE1

Is it ok?

I have register an username on digital ocean just to comment this tutorial . This is indeed one of the best tutorials i have read and implemented so far in some servers i have . However , in my iptables there are also rules to limit denial of service attacks by using “packet limit” and “burst limit” on opened ports on the server . I want to thank you personally for this excellent article , thank you very much . My best regards also to all of you here commenting and giving ideas in how to make it better .

👁 Creative Commons
This work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
  • Deploy on DigitalOcean

    Click below to sign up for DigitalOcean's virtual machines, Databases, and AIML products.

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and AI-native businesses

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

© 2026 DigitalOcean, LLC.Sitemap.
Dark mode is coming soon.