Skip to content

Instantly share code, notes, and snippets.

@baetheus baetheus/
Last active Feb 26, 2020

What would you like to do?
SmartOS Single IP with NAT using VLAN


These intructions might work, but they need a bit of attention. I've been reading through ipf and smf documentation and have found a few ways to improve this process. When I have time I'll add that information here, until then, be sure to look into the ipf settings if you're having issues with routing. Good luck!


This is a modified version of sjorge's instructions for Single IP with NAT. Those instructions can be found here:

The primary difference is that this version does not rely on etherstubs for internal switching, but instead uses a vlan configuration. The benefits of this method over using etherstubs are:

  1. Project Fifo ( can create vms and zones with vlans, but does not currently have etherstub support.
  2. Vlan switching is supposedly more efficient than creating an etherstub to handle switching. I have not tested this statement.

I've tested this setup on servers at both Kimsufi and SoYouStart (Both subsidiaries of OVH). I highly recommend these hosts. In other lab tests, this setup was used as the starting point for private vlan over vpn tunnel configurations.

Make sure to look at the net-setup shell script and to modify it to your settings. If you leave the current settings it will likely break things.


From the root shell of your smartos server.

mkdir -p /opt/custom/{smf,bin}
curl > /opt/custom/bin/net-setup
chmod 770 /opt/custom/bin/net-setup
curl > /opt/custom/smf/net-setup.xml

The above commands will create new directories in opt and download a shell script that sets up the vlan and nat and an smf service manifest. At this point you can either run svccfg import /opt/custom/smf/net-setup.xml or reboot. Be sure to look at the two files associated in this gist and to change whatever you feel needs changing.

I've also included a sample zone config. To get started with that

mkdir /opt/zones
imgadm update
imgadm import d34c301e-10c3-11e4-9b79-5f67ca448df0
curl > /opt/zones/sample-zone.json
vmadm create -f /opt/zones/sample-zone.json

After running this you should be able to ssh to your sample zone like so: ssh -l root -p 2222 <external-ip>.

Good Luck!


Firewall: I've done a small amount of work locking down most of the basic networking holes with ipf, but I am by no means a network administrator. If you really wanted to lock down your stuff, here is where I'd start:

  • Most internal vlan'd traffic should never be broadcast outside of the host. So vlans should be enough to segment internal hosts from external networks. But this is still not a great amount of protection.
  • You may wish to block traffic between zones or to only allow certain outbound port traffic.
  • Additionally, it would be more secure to add a second IP and to perform this routing inside of a zone plumbed to that ip, allowing only ssh traffic through the primary ip.



  • Updated to net-setup to reflect a current working and stripped down ipf/ipnat config
  • Removed insecure curl flags as ssl is now handled by most root cert chains.


  • Update links to point to baetheus github user account instead of slashtact.


  • Updated net-setup script to be a bit simpler.
  • Reorganized README and fixed some minor mistakes.


  • Updated curl links in README to always link to newest file revisions in gist.


  • Fixed the net-setup script to actually include the example ssh tunnel for the example zone.
  • Added some commentary on the firewall config, disclaimerish in nature.
## Warning, comment out once settings are edited.
echo 'WARNING!!! Edit the net-setup script with your settings and comment out this warning to proceed.' && exit 1
## Settings
## Setup vlan and gateway
if [ `dladm show-vnic | grep $INT_IF | wc -l` -ne 1 ]; then
/usr/sbin/dladm create-vlan -l $EXT_IF -v $VLAN
/usr/sbin/dladm create-vnic -l $EXT_IF $INT_IF -v $VLAN
/usr/sbin/ipadm create-addr -T static -a $INT_IP $INT_IF/v4
## Turn on ip forwarding
/usr/sbin/routeadm -u -e ipv4-forwarding
## Clear previous ipfilter and ipnat
[ -e /etc/ipf/ipnat.conf ] && rm /etc/ipf/ipnat.conf
[ -e /etc/ipf/ipf.conf ] && rm /etc/ipf/ipf.conf
## Setup Firewall
echo "## Allow Inbound Ports" >> /etc/ipf/ipf.conf
echo "pass in quick on $EXT_IF proto tcp from any to any port = 22 keep state" >> /etc/ipf/ipf.conf
echo "pass in quick on $EXT_IF proto tcp from any to any port = 80 keep state" >> /etc/ipf/ipf.conf
echo "pass in quick on $EXT_IF proto tcp from any to any port = 443 keep state" >> /etc/ipf/ipf.conf
echo "pass in quick on $EXT_IF proto icmp from any to any icmp-type echo" >> /etc/ipf/ipf.conf
## Outbound can be buttoned down further, try using snoop to determine your traffic profile.
echo "## Allow Out Ports" >> /etc/ipf/ipf.conf
echo "pass out quick on $EXT_IF all keep state" >> /etc/ipf/ipf.conf
echo "## Block all else" >> /etc/ipf/ipf.conf
echo "block in quick log first on $EXT_IF all" >> /etc/ipf/ipf.conf
echo "block out quick log first on $EXT_IF all" >> /etc/ipf/ipf.conf
## Setup Inbound NAT examples for web traffic and ssh forwarding.
echo "rdr $EXT_IF from any to any port = 80 -> port 80 tcp" >> /etc/ipf/ipnat.conf
echo "rdr $EXT_IF from any to any port = 443 -> port 443 tcp" >> /etc/ipf/ipnat.conf
echo "rdr $EXT_IF from any to any port = 2222 -> port 22 tcp" >> /etc/ipf/ipnat.conf
## Setup Outbound NAT
echo "map $EXT_IF from $INT_NET to any -> 0/32 proxy port ftp ftp/tcp" >> /etc/ipf/ipnat.conf
echo "map $EXT_IF from $INT_NET to any -> 0/32 portmap tcp/udp auto" >> /etc/ipf/ipnat.conf
echo "map $EXT_IF from $INT_NET to any -> 0/32" >> /etc/ipf/ipnat.conf
## Enable Firewall and NAT
/usr/sbin/ipf -E -Fa -v -f /etc/ipf/ipf.conf
/usr/sbin/ipnat -C -v -f /etc/ipf/ipnat.conf
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type='manifest' name='site:net-setup'>
<service name='site/net-setup' type='service' version='1'>
<create_default_instance enabled='true' />
<single_instance />
<dependency name='net-physical' grouping='require_all' restart_on='none' type='service'>
<service_fmri value='svc:/network/physical'/>
<dependency name='filesystem' grouping='require_all' restart_on='none' type='service'>
<service_fmri value='svc:/system/filesystem/local'/>
<exec_method type='method' name='start' exec='/opt/custom/bin/net-setup' timeout_seconds='0' />
<exec_method type='method' name='stop' exec=':true' timeout_seconds='0' />
<property_group name='startd' type='framework'>
<propval name='duration' type='astring' value='transient' />
<stability value='Unstable' />
"autoboot": true,
"brand": "joyent",
"image_uuid": "d34c301e-10c3-11e4-9b79-5f67ca448df0",
"max_physical_memory": 1024,
"cpu_cap": 100,
"alias": "sample-zone",
"quota": "5",
"resolvers": [
"nics": [
"interface": "net0",
"nic_tag": "admin",
"vlan_id": "1000",
"ip": "",
"gateway": "",
"netmask": ""

This comment has been minimized.

Copy link

BertrandF23 commented Jan 26, 2016

Very usefull !
But I had to change

Setup Inbound NAT

echo "rdr $EXT_IF from any to any port = 2222 -> port 2222 tcp" >> /etc/ipf/ipnat.conf


Setup Inbound NAT

echo "rdr $EXT_IF from any to any port = 2222 -> port 22 tcp" >> /etc/ipf/ipnat.conf

And I had to comment ipf because neither ping nor ssh access worked with it.


This comment has been minimized.

Copy link
Owner Author

baetheus commented Feb 26, 2016

Thanks for the info BertrandF23. I've been using a different version of the ipf/ipnat config for quite awhile. I've updated the gist to reflect the changes I've made.


This comment has been minimized.

Copy link

jeanparpaillon commented Jul 4, 2018

Thanks for your gist !
I'm using it for setting up a server with single IP. I can't ping external IP from the created zone (nor outside of course).
ipv4-forwarding is enabled and routes looks ok, how can I check config is ok ?


This comment has been minimized.

Copy link

jeanparpaillon commented Jul 23, 2018

Solved: I was doing some routing in the zone and forgot to enable ip_spoofing


This comment has been minimized.

Copy link
Owner Author

baetheus commented Nov 18, 2018

@jeanparpaillon Glad you figured it out. If you find any issues with this documentation let me know so I can keep it updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.