I have two network interfaces on my Ubuntu server, eth0 and eth1. Currently both are configured with the standard routing rules, but I want to configure eth1 so it can only access other computers on the local network and NOT the Internet. Eth0 should be able to access everything. I've seen similar questions where people want to accomplish the opposite (access the Internet but not local computers), but am unsure how to adjust the rules to accomplish what I desire.

What rule(s) would I add to lock out eth1 from accessing (and be accessed by) the Web, but still allow LAN access?

Edit: A bit more information.

Current Scheme. Here's a paint image of what I currently have set up. There is a separate router on the network that handles connections to the internet.

I want to be able to disconnect the server from the internet at the drop of a hat if I suspect an attack (such as someone swiping my private keys and I need time to "change the locks"), but still be able to access the server via SSH from another local machine to fix the problems. I either want to accomplish this by disconnecting the red wire or running a script to bring down the eth0 interface.

Is there a way to accomplish this scenario with both interfaces connected to the switch, or do I need to move the red wire and connect eth0 directly to the router? I suspect by the answer below the ideal scenario would be to let eth0 handle all the internet activity and let eth1 handle the local activity.

  • How does the Ubuntu server access the Internet? Via WLAN? In principle you need iptables rules to block allow forwarding from eth0, but block forwarding from eth1. – dirkt Jul 6 '17 at 21:32
  • The sever connects to the internet through the eth0 interface by default, and so does eth1. I don't want to alter eth0 and alter eth1 to be denied access to the Web. So in the end, eth0 should have access to the internet and other computers; eth1 should only be able to interact other computers and unable to touch/be touched by the Web. What routing rule would accomplish this scenario? My knowledge of Linux doesn't extend very far into networking and routing unfortunately. – MrZander Jul 6 '17 at 23:22
  • Is the server acting as a gateway for your local network? i.e. Do all the computers on your local network access the Internet via the server? – Larssend Jul 7 '17 at 4:23
  • I've edited my question with a little more information. The server does not act as a router; there is a router on the network already. – MrZander Jul 7 '17 at 14:26

I'm still a bit confused by your description. Here is what I understood:

+--------------+    +---------+
| Ubuntu  eth0 |----| Router/ |---- Internet
|              |    | Modem   |
|              |    +---------|
|              |
|              |    +---------+
|         eth1 |----| Switch  |---- LAN PC 1
|              |    |         |
|              |    |         |---- LAN PC 2
+--------------+    +---------+

So LAN PC 1, LAN PC 2 and the Ubuntu Server should be able to talk to each other (via eth1 on the Ubuntu server), and the Ubuntu server should be able to access the Internet, but neither LAN PC 1 nor LAN PC 2 should be able to access the Internet.

In that case, you just have to disable forwarding on the Ubuntu server (echo 0 > /proc/sys/net/ipv4/ip_forward, though it's disabled by default, or edit /etc/sysctl.conf to do that on boot). The server will contact the Internet via eth0, and the LAN via eth1.

If the situation is different, please edit your question to describe the situation.

Note that it's not network interfaces (eth0, eth1) that "access" anything, it's the computers themselves. Maybe that is the reason of the communication problem.


Yes, you can accomplish your scenario according to your drawing, but it will be tricky: "Double" connections to a network are no fun.

There's a solution that's a lot simpler, of it's ok that the other local PCs loose internet connection during an attack: Connect all PCs to the switch, and remove cable from switch to router when you suspect something. All computers keep their IP addresses, you can ssh from a local PC into the server using the numeric address. (Or you can run DNS/DHCP from the server instead of the modem/router in the first place.)

The proper solution to protect your server and at the same time allow your local PCs to continue using the internet is to set up a firewall (a cheap embedded computer with at least two LAN interfaces will do) between the modem/router and the Ubuntu server in the DMZ on the one side, and the local PCs on the other side. If you have full access to your modem/router (e.g. with OpenWRT), this firewall can also be placed there.

Now for your plan: It doesn't matter if the Ubuntu server is connected directly to the router or to the switch: The router has an internal switch, and cascaded switches don't change things, they count all as part of the same LAN segment.

Here's an outline what you need to do. It's untested, and will need a bit of fiddling, and there may be gotchas which prevent it from working at all.

  • Assuming the Router/Modem runs a DHCP server, make sure both eth0 and eth1 get different IP addresses. Also make sure eth1 doesn't get the default route. You may have to modify dhclient.conf for that, possibly write different request lines for both inrefaces.

  • Routing: eth0 should get the default route. eth1 should never get a default route, even when eth0 is down. You may have to fight installed programs/scripts to achieve this. eth1 should either only get a link-local route with higher metric (if that is possible), or no route at all (or a /1 subnet) while eth0 is up, and a link-local one when eth0 is down. That means you may have to set routes for eth1 in /etc/network/if-{up,down} for eth0 (or whatever the systemd equivalent is these day, if it works in systemd at all...).

Reason: if both eth0 and eth1 have routes with same metric into the local LAN, packets will be randomly sent from both interfaces, with different source IP addresses. To the receiving end in the LAN it will look like about half the packets are dropped (because the ones with the right source address never arrive). This is why a "double interface" into the same segment is no fun.

  • You need iptables rules that block anything on eth1 except the port for ssh to and from the local LAN. Google for tutorials.

Quite a bit of work.


A simpler alternative is to create a network namespace (google for tutorials), move eth1 into that namespace, run sshd inside it, and all the other services outside of the namespace. That means both interfaces can have default routes etc., only sshd goes via eth1, and all other services go via eth0. eth1 would need iptables rule to restrict it to the local LAN on INPUT and OUTPUT.


As I said, remote debugging is very difficult (no feedback). If you can't get it to work, please make a new question and describe exactly what you did (ip route, ip addr on all relevant machines, tcpdump on relevant interfaces when you do ssh, etc.).

I just checked; as I don't have two ethernet interfaces, I used a virtual eth pair. Roughly, create a namespace and move your eth1 into it

# ip netns add blue
# ip link set eth1 netns blue

Make sure it gets a valid address and route, either by enabling DHCP and making sure it gets run, whatever method your system uses, or by setting it manually (for testing), something like

# ip netns exec blue ip link set eth1 down
# ip netns exec blue ip addr add dev eth1
# ip netns exec blue ip link set eth1 up

You should get an address and a route, e.g. (this was done with a virtual eth pair, so it won't look exactly like this):

# ip ip netns exec blue ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
  link/ether e6:5a:19:e0:63:75 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  inet scope global veth1b
     valid_lft forever preferred_lft forever
  inet6 fe80::e45a:19ff:fee0:6375/64 scope link 
     valid_lft forever preferred_lft forever
# ip netns exec blue ip route dev eth1 proto kernel scope link src 

Run sshd in that namespace in another xterm, add debugging flags and use a different port to make sure there's no confusion:

# ip netns exec blue /usr/sbin/sshd -D -d -p 222

Connect to it from the outside with ssh -p 222, and that worked fine here: you can see the connection process in the debug messages.

  • Update: I added a namespace like you suggested and added the routes Nathan suggested in his answer below. It seems to be working mostly. As desired, my server loses it's connection when I pull the (eth0) plug or ifdown the interface. However, while eth0 is down, my PuTTY throws a "Connection Refused" error when I try to SSH in through the eth1 IP. I'm Googling around trying to get to the bottom of it. – MrZander Jul 8 '17 at 17:51
  • Difficult to debug remotely. Possible reasons: iptables rules wrong (remove rules, see if it starts working), ssh config needs tweaking, ... tcpdump on eth1 may help. – dirkt Jul 8 '17 at 19:21
  • Well, my scenario seems to be working thanks to the namespace. However, I have been googling around for a few hours new and cannot seem to get sshd to work within the new namespace; seems it (the namespace) isn't listening on port 22, and PuTTY can't connect. It doesn't seem to be an iptables or firewall issue, but a forwarding issue. Would you mind pointing me in the right direction to some literature that might help me fix this forwarding issue? Thanks for all your help. – MrZander Jul 9 '17 at 1:28

If your local PCs need to acces the Internet

Assuming your local network is, and that it is not a problem if LAN traffic uses eth0.

On the server, add the following rules:

iptables -A INPUT -i eth1 -s -j ACCEPT
iptables -A INPUT -i eth1 -j DROP
iptables -A OUTPUT -o eth1 -d -j ACCEPT
iptables -A OUTPUT -o eth1 -j DROP

This will unconditionnally cancel any in- and outgoing traffic from eth1 that is not for your LAN. Replace with your LAN's CIDR. Don't forget to add their ip6tables equivalent if needed.

If your local PCs don't need to access the Internet

Disconnect the router from the switch, and connect it directly to eth0. This is way more simple than the above, provided that your network equipments are close to each other.

A router is only useful when two different networks need to communicate, it is useless when both machines are on the same network (which is usually the case when connected to the same switch without VLANs).

  • I added the rules you suggested, and brought down the eth0 interface temporarily to test, but the server still has internet access. Should the ip address in the rule match the gateway address of the router? Or what should it match? I use a 192.168.1.xxx scheme. – MrZander Jul 7 '17 at 18:32
  • If your LAN IPs range from to (with netmask, then the CIDR to use is (the /24 at the end is important). This designates the entire network. Now if your server still accesses the internet, you could try inserting the rule -i eth1 -s 192.168.1.x -j DROP before the two rules I suggested, as well as its OUTPUT equivalent, where 192.168.1.x is the LAN IP of your router. Oh, and make sure your router doesn't route IPv6 traffic. – Nathan.Eilisha Shiraini Jul 8 '17 at 8:20
  • If it still doesn't work, check the OUTPUT table for any rule that may authorize outgoing traffic regardless of the interface. – Nathan.Eilisha Shiraini Jul 8 '17 at 8:21

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.