Setting Up a NixOS Oracle Cloud Instance as a Small Public Edge Host

The job of a public edge host is simple: give the public internet one small thing to hit so the rest of your homelab does not have to. If you are behind CGNAT, or if you just prefer not to bolt public reachability directly onto the home WAN, that separation is worth the trouble.

For this role, I want a box that is small, rebuildable, and boring. Oracle Cloud Infrastructure is useful here because Oracle still documents an Always Free Arm shape that can fit a narrow edge role, and the current public NixOS path on OCI is workable. The path worth teaching is not custom-image wizardry. It is duller and better: launch Oracle Linux 9, use it as the bootstrap environment, then install NixOS in place.

What This Guide Covers

This guide is about the host baseline, not the whole remote-access stack.

In scope:

  • why a public edge host exists at all
  • why the role should stay separate from the NAS or main service host
  • the current public-safe Oracle Linux 9 to NixOS path
  • the smallest OCI network shape worth understanding
  • the first-pass NixOS host baseline for SSH and firewall policy

Out of scope:

  • tunnel setup
  • reverse-proxy routes
  • real service exposure
  • a private ruleset dump from the live estate
  • the full remote-access layer that belongs in the next article

If you finish this guide with one small rebuildable NixOS box on the public edge and no urge to turn it into a second platform too early, that is success.

OCI In Plain English

If you have not used OCI before, the vocabulary is more annoying than the underlying idea.

  • VCN: Oracle’s private network container for your cloud resources
  • subnet: one slice of that network where an instance lives
  • public subnet: a subnet whose route table can reach an Internet Gateway, so an instance there can be reachable from outside if it also has a public IP
  • Internet Gateway: the route out to the public internet
  • security list or network security group (NSG): Oracle-side packet filtering before traffic reaches the host itself
  • public IP: the address the outside world uses to reach the instance

For this article, the mental model is simple:

  • Oracle-side objects decide whether traffic can reach the instance at all
  • NixOS decides what the instance itself will accept once traffic gets there

When I say admin source range, I mean the public IP range you actually SSH from. For most people that is a home connection, office connection, or VPN egress range. It does not mean “the whole internet and good luck.”

Once that split is clear, the rest of the article is straightforward.

What This Host Is Actually For

This box is not a second homelab. It is a boundary tool.

Its job is to:

  • terminate the public side somewhere other than the home router
  • give you one place to apply Oracle-side and host-side network policy
  • stay small enough that rebuilding it is less dramatic than repairing it

That last point matters. A public edge host should feel disposable. If it turns into a precious snowflake, you have recreated the usual VPS problem with better branding.

Keep It Separate From The Rest

There are three good reasons not to fold this role into the NAS or the main service host.

  • Blast radius stays smaller when the public boundary and the storage boundary are not the same machine.
  • Rebuilds are easier when the edge box does one narrow job instead of carrying half the estate’s folklore.
  • Troubleshooting gets cleaner when “public reachability is broken” and “the backup target is on fire” are not the same sentence.

That does not make the cloud box magical. It just keeps the public-facing part of the mess small enough to reason about.

Start With Oracle Linux 9, Then Replace It

The current public NixOS-on-OCI path starts from an Oracle Linux 9 instance and installs NixOS from there. That is the route documented on the NixOS Wiki, and it is the route worth teaching because it is current, legible, and does not depend on a private bag of image-prep tricks.

Oracle does support custom image import, including qcow2, so there are other ways into the platform. I am not leading with them here. For a small edge host, the useful thing is a documented path you can repeat, not a story about how clever you were once with an image pipeline.

The practical working order is:

  1. Launch a small Oracle Linux 9 instance.
  2. Give it one public IP and one narrow SSH allow rule from the public IP range you actually administer from.
  3. Follow the current NixOS Oracle Cloud install path from that running instance.
  4. Reboot into NixOS and keep the host on an SSH-first firewall.
  5. Put the host config under version control and rebuild from there.

The install transcript itself will drift. That is normal. What should stay stable is the host shape you are aiming for: one bootable NixOS edge box, one narrow network policy, one sane SSH baseline, and one rebuild path you can repeat later without rummaging through old console notes.

If you want the fuller repo-backed host pattern after first boot, Building a Minimal NixOS Homelab Host is the right follow-on. This article is about the role and the guardrails, not about freezing a temporary installer transcript in amber.

The Smallest OCI Shape Worth Explaining

Oracle’s current Always Free documentation still includes the VM.Standard.A1.Flex shape. That is enough to make OCI relevant for a small edge role. A 1 OCPU / 6 GB RAM instance is a sensible example size here: small enough to stay cheap or free-tier-friendly, large enough to stop feeling like a stunt.

The OCI side should stay equally small:

OCI pieceWhy it existsPublic-safe baseline
VCNGives the instance a network boundaryOne VCN, no heroic topology
Public subnetMakes the edge box reachableOne public subnet for the edge host
Public IPGives the box an address from the outsideOne public IPv4 address
Internet routeLets the box reach package mirrors and the outside worldOne route to an Internet Gateway
Security rulesStop the subnet from becoming a surprise welcome matOne narrow SSH allow rule from an authorized CIDR

OCI gives you two main packet-filtering tools here: security lists and network security groups. Oracle’s docs now recommend network security groups over security lists. For one small host, the practical point is not the acronym. The practical point is that the rule set stays narrow and deliberate.

If you are launching this for the first time, the minimum OCI checklist is:

  1. create one VCN
  2. create or keep one public subnet inside it
  3. make sure that subnet has a route to an Internet Gateway
  4. apply one narrow SSH allow rule from the public IP range you actually SSH from
  5. launch one Oracle Linux 9 instance on a small shape
  6. attach one public IP and confirm you can reach the box with SSH

That is enough OCI for this article. If you are three menus deep into route-table heroics before the host even boots, you have taken the scenic route by mistake.

For a beginner, the important mistake to avoid is 0.0.0.0/0 on SSH just because it is easy. The point of the edge box is not to become public in every possible way at the first opportunity.

One more beginner point: OCI can assign an ephemeral public IP or a reserved one. For a throwaway rehearsal, ephemeral is fine. For a host you expect to keep rebuilding while preserving the same public identity, a reserved public IP is the tidier choice.

Do not publish your real region, your real CIDRs, or your real ruleset. That is not coyness. It is what good sense looks like when the article is about the public boundary.

Oracle-side work stops once the instance is reachable, has the right basic network path, and is not being greeted by a firewall made of wishful thinking. After that, the job moves inside the guest: install NixOS, harden SSH, make the firewall explicit, and make the box rebuildable.

Keep The NixOS Side Boring

Once NixOS is on the box, the host should look more like a disciplined SSH endpoint than a baby platform. The exact disk and rescue steps belong to the current Oracle Cloud install guide, but the target host shape is straightforward.

This snippet is the target state after installation, not a full rescue-console walkthrough. The addresses, gateway, DNS, interface name, and SSH key are synthetic placeholders. The point is the shape of the box, not these exact numbers.

This is the kind of baseline I mean:

{
  # OCI's current documented NixOS path uses systemd-boot.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # This keeps the simpler eth0 naming used by the OCI install guide.
  boot.kernelParams = [ "net.ifnames=0" ];

  networking = {
    hostName = "edge-host";

    # These are synthetic placeholder values, not real network settings.
    defaultGateway = "192.0.2.1";
    nameservers = [ "9.9.9.9" "149.112.112.112" ];

    interfaces.eth0 = {
      ipv4.addresses = [
        {
          address = "192.0.2.10";
          prefixLength = 24;
        }
      ];
      useDHCP = false;
    };

    firewall = {
      enable = true;

      # Start with SSH only. Open anything else later on purpose.
      allowedTCPPorts = [ 22 ];
      rejectPackets = true;
    };
  };

  services.openssh = {
    enable = true;
    settings = {
      # Treat this as a key-only admin box from day one.
      PasswordAuthentication = false;
      PermitRootLogin = "no";
    };
  };

  users.users.operator = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
    openssh.authorizedKeys.keys = [
      # Replace this with your real admin workstation public key.
      "ssh-ed25519 AAAA... operator@admin-workstation"
    ];
  };
}

Read that snippet for what it is:

  • systemd-boot is the recommended OCI bootloader path in the current public install guidance
  • net.ifnames=0 gives you the simpler eth0 naming the OCI install guide uses
  • the address, gateway, DNS, and SSH key are placeholders from documentation ranges and must be replaced with your own values
  • the firewall allows 22 and nothing else

That is enough for the first pass. If you later decide this host should accept 80 or 443, do that as a second decision with second-order consequences. The first job is to get a small rebuildable edge box into service, not to publish every future port in one sitting.

If this host later needs credentials for an agent, tunnel, or service wrapper, keep them out of the Nix store. Managing Homelab Secrets with NixOS and agenix is the right follow-on for that.

Keep Oracle-Side And Host-Side Controls Separate In Your Head

These two layers are related, but they are not the same thing:

LayerWhat it controlsMinimum sane policy
OCI route and public-IP configWhether the host is reachable at allOne public edge path only
OCI security rulesWhat reaches the instance at the VNIC levelSSH from an authorized CIDR, nothing broader by accident
NixOS firewallWhat the host itself acceptsMirror the same narrow stance on the host
OpenSSH configHow the operator gets inKeys only, no root login, no password auth

If you only harden one side, you have not really finished the job. Cloud-console rules and host-firewall rules are not rivals. They are two separate opportunities not to be lazy.

Validate The Host, Not A Fantasy

You are done when the box behaves like a small rebuildable edge host, not when the console screenshots look tidy.

At minimum, check:

  1. SSH only works from the source range you intended to allow.
  2. The host boots into NixOS cleanly after the install.
  3. sshd is running and the firewall stance is explicit.
  4. A rebuild still works after first boot.

That looks like:

systemctl is-system-running
systemctl status sshd --no-pager
sudo ss -ltnp
sudo nft list ruleset
sudo nixos-rebuild switch

If the host lives in a flake repo, also run:

nix flake check

Reachability is not readiness. A reachable mistake is still a mistake.

IPv6 Is A Real Decision, Not A Checkbox

The current NixOS Oracle Cloud guide covers IPv6, and OCI can support it if the VCN, subnet, route table, and security rules are set up for it.

That does not mean you must turn it on in the first draft of the host. If you need IPv6 now, mirror the policy properly on both the Oracle side and the NixOS side. If you do not, start with IPv4 and add IPv6 when you are ready to reason about it instead of merely feeling modern.

What Comes Next

Once this host exists, you have a place to hang the real remote-access layer. That next layer is where tunnel choice, proxy shape, access policy, and service exposure start to matter.

Do not solve that by improvised firewall edits on the home router and a burst of optimism. Get the edge host boring first. Then put the remote-access machinery on top of it deliberately.

Source Notes