Routing Outbound SMTP from an Isolated Subnet Through an Existing OpenVPN NAT Gateway (OCI)
Published Sept. 6, 2026, 4:54 p.m. by cloudblog
A walkthrough of getting an Oracle EBS environment in a private OCI subnet to send outbound mail through an SMTP relay — without disturbing the OpenVPN Access Server instance's own NAT configuration.
The problem
Our EBS tier lives in a private subnet with no direct route to the internet. A separate instance running OpenVPN Access Server sits in the same VCN and already has working internet egress for VPN clients — it does this via its own NAT chain (AS0_NAT), created and managed by Access Server itself.
The goal: let EBS's Workflow Notification Mailer reach an external SMTP relay over port 465 (implicit TLS), by routing that one subnet's traffic through the same instance's internet-facing interface — without editing or interfering with Access Server's own NAT rules, since it regenerates those chains on its own and any manual edit risks being silently wiped out.
The target flow:
EBS subnet (private)
↓
OpenVPN/NAT instance (private IP)
↓
SNAT
↓
Internet → SMTP relay:465
Step 1 — Understand what's already there
Before touching anything, we inspected the existing NAT setup:
sudo iptables -t nat -S POSTROUTING
sudo iptables -t nat -S AS0_NAT
This showed Access Server's chain SNATs traffic leaving the internet-facing interface to the instance's own address, but it's only ever reached via two very specific jumps: connections already tracked as RELATED,ESTABLISHED, and packets carrying a particular firewall mark that Access Server sets on VPN client traffic. Plain subnet-to-subnet traffic from our EBS network wouldn't hit either of those — meaning our traffic wasn't being NAT'd (or blocked) by the existing config at all; it just wasn't being handled yet.
That confirmed it was safe to add a narrowly-scoped rule of our own alongside the existing chains, rather than modifying them.
Step 2 — Confirm the two OCI prerequisites
Two settings had to be right before any iptables rule could matter:
- Route table — the EBS subnet's route table needed a route sending internet-bound traffic (0.0.0.0/0) to the NAT instance's private IP as the target.
- Skip Source/Destination Check — enabled on the NAT instance's VNIC. This one is easy to miss: OCI silently drops any packet an instance tries to forward that isn't addressed to/from its own IP unless this is turned on. Without it, no amount of iptables tuning will help — packets get dropped before the OS ever sees them.
Step 3 — Verify routing and connectivity before adding NAT
ip route get <a host in the EBS subnet>
confirmed the NAT instance would correctly hand off packets toward the EBS subnet via the VCN's virtual router — normal OCI behavior for inter-subnet routing.
For a reachability test, ping wasn't installed on the box. Rather than adding a package, we used bash's built-in /dev/tcp to probe a known open TCP port directly:
bash
timeout 3 bash -c "cat < /dev/tcp/<host>/22" && echo OPEN || echo CLOSED/FILTERED
Gotcha worth flagging: this returned the remote SSH banner (proof the TCP handshake succeeded) and printed CLOSED/FILTERED. That's a false negative — SSH sends its banner and then waits for the client's reply; since nothing was sent back, cat stayed blocked until timeout killed it, which made the command's exit code non-zero. Getting the banner at all was the real signal that connectivity was fine.
Step 4 — Add the scoped NAT rule
With routing and OCI settings confirmed, we appended (never inserted) a single rule limited to just the subnet in question, so it can never reorder or race with Access Server's own chain:
sudo iptables -t nat -A POSTROUTING -s <EBS-subnet-CIDR> -o <internet-facing-interface> -j SNAT --to-source <NAT-instance-private-IP>
Confirmed it landed correctly, appended after Access Server's existing jumps:
sudo iptables -t nat -S POSTROUTING
Step 5 — Test the actual target port
Port 465 is implicit TLS — the server won't send anything until a TLS handshake starts, so the same /dev/tcp trick would give another false negative. openssl s_client is the right tool here:
bash
timeout 6 openssl s_client -connect <smtp-relay-host>:465 </dev/null
A successful TLS handshake with a valid certificate chain confirmed the new NAT path was working end-to-end.
Step 6 — The application-layer gotcha
With networking solved, the EBS Workflow Notification Mailer setup still failed with a generic "Unable to connect to the mail account" error. Two configuration issues turned out to be the actual cause, unrelated to the network work above:
- The Server Name field contained stray characters mixed in with the hostname, producing an invalid host value instead of a clean hostname.
- The Username configured in EBS didn't match the mailbox account that was actually confirmed working via a command-line test — an easy mismatch to introduce when multiple mailbox accounts exist on the same relay.
Fixing the hostname field and aligning the username with the verified working account resolved the connection test.
Takeaways
- When another service (like OpenVPN Access Server) owns its own NAT chains, add scoped rules alongside them rather than editing them — regenerated configs will wipe manual changes to chains they manage.
- OCI's Skip Source/Destination Check is one of the most commonly missed settings when using an instance as a NAT/router — no iptables rule can compensate for it being off.
- Simple connectivity tests can lie: banner-first protocols (SSH) and implicit-TLS ports (465) both break the naive
/dev/tcpprobe in different ways. Match the test tool to the protocol. - A working network path doesn't rule out an application-layer misconfiguration — always confirm the actual application error message separately once networking is verified.
(Server names, domains, credentials, and internal addressing have been generalized/masked for this write-up.)
Similar posts
There are no similar posts yet.0 comments
There are no comments.
