The Handbook

    Theme
    • Guides
        • Check a system before installing FreeBSD
        • Orient a Linux administrator on FreeBSD
        • Supported FreeBSD releases
        • Choose a FreeBSD documentation and support channel
        • Move files safely without GNU mv -t
        • Update, upgrade, or update packages?
        • Upgrade 14.4 or 15.0 to FreeBSD 15.1
        • Choose packages, ports, or poudriere
        • Choose the quarterly or latest package branch
        • Choose a FreeBSD download or package mirror
        • Make a system setting persistent
        • Configure locale, keyboard, and time zone
        • Configure a serial console for recovery
        • Choose a custom kernel, module, or loader setting
        • Run a Linux binary with the compatibility layer
        • Check desktop and laptop hardware before installation
        • Choose and check a graphics driver
        • Choose Xorg or Wayland
        • Build a maintainable desktop baseline
        • Install and check a desktop browser
        • Check laptop Wi-Fi, power, and suspend
        • Check multimedia readiness
        • Choose and configure a printing stack
        • Run Windows applications with Wine
        • Snapshot and replicate a ZFS dataset
        • Choose a filesystem and storage layout
        • Operate ZFS without losing the recovery path
        • Restore files from a ZFS snapshot
        • Read ZFS pool health and run a scrub
        • Replace a failed device in a ZFS mirror
        • Replicate a ZFS dataset over SSH
        • Change PF safely on a remote host
        • Configure a narrow WireGuard tunnel
        • Plan a FreeBSD home server
        • Choose a mail server or an outgoing relay
        • Publish a network service safely
        • Choose a jail network model
        • Choose native jails or a jail manager
        • Choose a jail or a bhyve virtual machine
        • Establish a FreeBSD security baseline
        • Choose a MAC policy
        • Audit security-relevant activity
        • Start a DTrace performance investigation
    • Integrations
        • Create a first jail with Bastille
        • Compare jail managers and OCI tooling
        • Publish a Bastille service through PF
        • Mount a ZFS dataset in a Bastille jail
        • Update and upgrade Bastille jails
        • Back up and restore a Bastille jail
        • Prepare bhyve and vm-bhyve
        • Choose NFS or Samba for file sharing
        • Choose ZFS backup automation
        • Operate a signed poudriere repository
        • Manage FreeBSD configuration with Ansible or Salt
        • Run Motion with webcamd on FreeBSD
        • Design a reverse proxy, certificates, and monitoring
    • FAQ
      • Troubleshooting
          • Recover an interrupted freebsd-update run
          • Resolve a package repository or ABI mismatch
          • Diagnose the FreeBSD boot path
          • Recover with a ZFS boot environment
          • Diagnose DNS, routing, and firewall paths
          • Diagnose network mbuf exhaustion
          • Bind a service to a low port without running it as root
          • Diagnose audio output or input
          • Diagnose webcamd, cuse, and a webcam
          • Fix USB device permissions without opening every device
      • About this handbook
      • Synopsis
      • Verify the service without publishing it
      • Check the host boundary
      • Add the narrowest mapping
      • Test from outside the host
      • Remove the mapping
      • Primary references

      Publish a Bastille service through PF

      Last reviewed
      13 August 2026
      Applies to
      15.1-RELEASE, 15.0-RELEASE, 14.4-RELEASE

      Synopsis #

      A service in a private Bastille jail needs three working layers: a listener inside the jail, routing and NAT for the jail address, and an explicit PF redirection from a host address and port. Publishing the port before verifying the first two layers makes failures harder to locate.

      This guide uses a jail named web, HTTPS on jail port 443, and host port 8443. The default Bastille private-network setup and its rdr/* PF anchor must already exist. Review Choose a jail network model first.

      Verify the service without publishing it #

      Confirm the jail address and listening socket:

      # bastille list jail
      # bastille cmd web sockstat -4 -6 -l
      # bastille service web nginx status
      

      The service should listen on the jail address or on all jail addresses, not only on 127.0.0.1. From the host, connect directly to the private address before adding redirection:

      $ fetch -o /dev/null https://10.17.89.20/
      

      Substitute the actual jail address. Certificate-name errors are expected when an IP address is used; a timeout or refused connection indicates a listener or local path problem that PF redirection will not repair.

      Check the host boundary #

      Identify the external address, confirm the Bastille anchors, and inspect existing mappings:

      $ ifconfig -a
      # pfctl -nf /etc/pf.conf
      # pfctl -sr | grep anchor
      # bastille rdr web list
      

      The host rules must contain rdr-anchor "rdr/*" and the Bastille anchor expected by the installed release. A clean syntax check does not prove that the rules preserve remote access. Use the precautions in Change PF safely on a remote host before loading a changed base ruleset.

      Also check whether port 8443 is already occupied on the host:

      # sockstat -4 -6 -l | grep ':8443'
      

      Add the narrowest mapping #

      To expose host TCP port 8443 to jail port 443 on the default external interface:

      # bastille rdr web tcp 8443 443
      # bastille rdr web list
      

      When only a management network should connect, use a source restriction. Replace the documentation prefix before running this example:

      # bastille rdr -t ipv4 -s 192.0.2.0/24 web tcp 8443 443
      

      On a host with several addresses or interfaces, use Bastille’s --destination and --interface options rather than publishing on every address. Confirm the generated rule with bastille rdr web list; do not infer its scope from the command alone.

      Test from outside the host #

      Test from a system on the intended source network:

      $ nc -vz host.example.net 8443
      $ fetch -o /dev/null https://host.example.net:8443/
      

      During the test, inspect states and rule counters on the host:

      # pfctl -ss
      # pfctl -vvsr
      

      No matching state normally means that traffic did not reach the expected interface or did not match the rule. A state with no successful application response points toward the jail listener, return route, or service policy.

      Remove the mapping #

      List all rules before clearing them:

      # bastille rdr web list
      # bastille rdr web clear
      

      clear removes the jail’s mappings, not only one guessed entry. Record the intended mappings as configuration and verify them after Bastille, PF, or host restarts. A dynamic rule that worked once is not an adequate deployment record.

      Primary references #

      • Bastille rdr command
      • Bastille networking and PF anchors
      • FreeBSD Handbook: Firewalls
      • pfctl(8)
      • sockstat(1)

      Independent documentation. Not affiliated with or endorsed by the FreeBSD Project or the FreeBSD Foundation.

      Report a bug
      • Synopsis
      • Verify the service without publishing it
      • Check the host boundary
      • Add the narrowest mapping
      • Test from outside the host
      • Remove the mapping
      • Primary references