OmniOS on EC2 - part II
Continue
This is a continuation of part I. Enjoy!
Init - hostname, user, shell, and tools
First thing, let’s set a new hostname. I’ve used Star Control 2 races as a source for hostnames for many years:
omnios@12-34-56-78:~$ pfexec hostname mycon
omnios@12-34-56-78:~$ echo mycon | pfexec tee /etc/nodename
<reconnect>
omnios@mycon:~$
The second thing to do was configure a new user for me and disable the default
user. Though I usually like zsh these days, I’m going to leave it as bash
for now.
omnios@mycon:~$ pfexec useradd -m -z -s /bin/bash -d /home/kenichi kenichi
omnios@mycon:~$ pfexec passwd kenichi
omnios@mycon:~$ pfexec usermod -P "Primary Administrator" kenichi
omnios@mycon:~$ pfexec mkdir /home/kenichi/.ssh
omnios@mycon:~$ pfexec vi /home/kenichi/.ssh/authorized_keys
<paste public key>
omnios@mycon:~$ pfexec chown -R kenichi:other /home/kenichi/.ssh
omnios@mycon:~$ pfexec chmod 700 /home/kenichi/.ssh
omnios@mycon:~$ pfexec chmod 600 /home/kenichi/.ssh/authorized_keys
<reconnect>
kenichi@mycon:~$ pfexec passwd -l omnios
kenichi@mycon:~$ pfexec usermod -s /bin/false omnios
Now, we can continue with Getting Started. The OmniOS folks recommend updating:
$ pfexec pkg refresh
$ pkg list -u
$ pfexec pkg update
WARNING: pkg(7) appears to be out of date, and should be updated before
running update. Please update pkg(7) by executing 'pkg install
pkg:/package/pkg' as a privileged user and then retry the update.
At this point, I had to update pkg itself to continue:
$ pfexec pkg install pkg:/package/pkg
...
$ pfexec pkg update
Now, the docs tell you reboot if this update prcoess tells you to. It told me to. It said there’s a new BE (boot environment) in town, and it will be used on the next reboot. Sounds good, I say, and off we go.
HOLD ON A SEC, this image came with cloud-init
services that are configured to run at boot. For a persistent host, I think it
is only needed once, so let’s uninstall it and cleanup files it wrote first:
$ pfexec pkg uninstall cloud-init
$ pfexec rm /etc/sudoers.d/90-cloud-init-users
$ pfexec init 6
Once it reboots and we re-login, we can continue with the getting started page,
I’ll add the build-essential package. I’ll clearly want tmux, ripgrep, and
vim at least though too. Oh, let’s add zsh and git while we’re at it.
$ pfexec pkg install ooce/text/ripgrep \
terminal/tmux \
editor/vim \
shell/zsh \
developer/build-essential \
developer/versioning/git
...
$ pfexec usermod -s /bin/zsh kenichi
<reconnect>
% tmux
“Crossbow” Networking
Let’s configure the network. I want my zones to live in a NATed subnet for now.
# turn on IPv4 forwarding
% pfexec svcadm enable ipv4-forwarding
# create stub for vnics
% pfexec dladm create-etherstub stub0
# create a gateway vnic linked to the stub
% pfexec dladm create-vnic -l stub0 stub0gw0
# give the gateway vnic an IP
% pfexec ipadm create-addr -T static -a 192.168.42.1/24 stub0gw0/v4
Let’s use ipf to handle firewalling and NAT. We’ll start with very basic
rules. For a more complete overview and ruleset, see
IPFilter. Write these files:
# by default, block everything
block in all
block out all
# loopback
pass in quick on lo0 all
pass out quick on lo0 all
# ena0 egress
pass out quick on ena0 all keep state
# ena0 ingress
pass in quick on ena0 proto tcp from any to any port = 22 flags S keep state
# zones
pass in quick on stub0gw0 from 192.168.42.0/24 to any keep state
pass out quick on stub0gw0 from any to 192.168.42.0/24 keep state# NAT all traffic from zone network out through ena0
map ena0 192.168.42.0/24 -> 0.0.0.0/32 portmap tcp/udp auto
map ena0 192.168.42.0/24 -> 0.0.0.0/32Then, start it up and load our rules:
% svcdam enable svc:/network/ipfilter
% ipf -Fa -f /etc/ipf/ipf.conf
% ipnat -FC -f /etc/ipf/ipnat.conf
Great, now we have a private subnet to boot zones in that can reach the internet via NAT. We’ve also allowed SSH from anywhere; you should probably rate-limit this or lock it down with a security group.
Let’s make sure the configuration works. First, we’ll configure a sparse zone:
% pfexec zfs create /rpool/zones
% pfexec zonecfg -z sparsetest
sparsetest: No such zone configured
Use 'create' to begin configuring a new zone.
zonecfg:signoz-collector> create
zonecfg:signoz-collector> set zonepath=/rpool/zones/sparsetest
zonecfg:signoz-collector> set autoboot=false
zonecfg:signoz-collector> set ip-type=exclusive
zonecfg:signoz-collector> set brand=sparse
zonecfg:signoz-collector> add net
zonecfg:signoz-collector:net> set allowed-address=192.168.42.2/24
zonecfg:signoz-collector:net> set defrouter=192.168.42.1
zonecfg:signoz-collector:net> set physical=stub0sparsetest0
zonecfg:signoz-collector:net> end
zonecfg:signoz-collector> add attr
zonecfg:signoz-collector:attr> set name=resolvers
zonecfg:signoz-collector:attr> set type=string
zonecfg:signoz-collector:attr> set value=10.0.0.1
zonecfg:signoz-collector:attr> end
zonecfg:signoz-collector> verify
zonecfg:signoz-collector> commit
zonecfg:signoz-collector> exit
zoneadm will take care of a number of
things for us:
- Creating the ZFS dataset at
zonepath - Creating the VNIC
stub0sparsetest0with192.168.42.2 - Creating
/etc/resolv.confin the zone with10.0.0.1(this IP is generic, adjust for your own setup)
Let’s see it happen!
% pfexec zoneadm -z sparsetest install
...
% pfexec zoneadm -z sparsetest boot
% pfexec zlogin sparsetest
[Connected to zone 'sparsetest' pts/6]
OmniOS r151054 omnios-r151054-f66c95f374 September 2025
root@sparsetest:~# ping google.com
google.com is alive
🎉 Success! We have configured our host, set up some basic Crossbow networking, and fired up a sparse-brand zone. We’ll continue with running an LX zone based on a Docker image in part III.