Synopsis #
Installing a daemon and opening its port do not produce a maintainable network service. Publication joins package ownership, process lifecycle, listening addresses, isolation, firewall policy, authentication, secrets, durable data, updates, recovery, and monitoring into one operational boundary.
This guide is a workload-neutral admission checklist. It complements the official network-server documentation rather than reproducing its catalogue of daemon configurations. Complete the service’s current upstream procedure, then use this checklist to decide whether the result is safe to make reachable.
Write the service contract #
Record one contract before installation:
| Item | Required decision |
|---|---|
| Purpose | Named users and the function being provided |
| Owner | Account responsible for configuration, updates, alerts, and incidents |
| Runtime boundary | Host, jail, or virtual machine and the reason for that choice |
| Software source | FreeBSD package origin or documented private repository |
| Data | Configuration, durable data, secrets, cache, and temporary files |
| Listener | Address, interface, transport, and port |
| Reachability | Exact client networks or public names that may connect |
| Protection | PF rule, reverse proxy or VPN, TLS, and authentication |
| Recovery | Backup set, restore order, and accepted recovery time |
| Evidence | Functional check, log signal, resource signal, and alert destination |
A service without an owner, restore path, or update window should remain private. Plan a FreeBSD home server provides the broader host and dataset boundaries.
Establish software ownership #
Install the daemon from one package policy or one reviewed private repository. Record the installed package version and origin:
$ pkg query '%n-%v %o' package-name
Replace package-name with the installed package name. Do not overlay a source-built binary on files owned by a package. If upstream source is required, give the build, artifact, signature or checksum, installation path, update procedure, and removal procedure an explicit owner.
Keep package-branch and private-build decisions visible. See Choose packages, ports, or poudriere and Manage FreeBSD configuration with Ansible or Salt . Automation must not make the same file or package subject to several competing owners.
Choose the runtime boundary #
A small native daemon can run on the host, but every host service expands the base system’s exposed process and configuration surface. Prefer a jail when a FreeBSD-native workload benefits from separate accounts, filesystems, packages, addresses, and lifecycle. Prefer a virtual machine when another kernel, a vendor appliance, or a stronger machine-shaped boundary is required.
The boundary does not remove service-level controls. A jail shares the host kernel, and a virtual machine still needs restricted networks, updates, backups, and monitoring. Use Choose a jail or a bhyve virtual machine before building the workload. For a managed jail publication path, review Publish a Bastille service through PF .
Make rc.d lifecycle explicit #
FreeBSD packages normally install third-party rc.d scripts beneath /usr/local/etc/rc.d. Inspect the actual script and its supported actions instead of guessing a service name from the package name:
$ service -l
# service service_name rcvar
Replace service_name with the installed rc.d name. Read the package message and sample configuration, then validate the daemon configuration with its own documented checker before enabling startup. Not every rc.d script implements a configtest action.
Enable the reviewed service and start it deliberately:
# sysrc service_name_enable=YES
# service service_name start
# service service_name status
Define whether a configuration change supports reload or requires restart, what happens to active connections, and how rollback restores the prior file. Use Manage persistent system settings to keep rc.conf ownership separate from daemon configuration.
Prove the listener before exposing it #
Inspect effective sockets after startup:
# sockstat -4 -6 -l
Match the process, account, address, transport, and port to the service contract. 0.0.0.0 and :: are wildcard listeners; they are not equivalent to loopback or a private jail address. A public address does not prove that upstream routing or PF permits access, and process existence does not prove that the application protocol works.
Test the protocol from each relevant side of the boundary: inside the jail or VM, from the host, from the intended private client network, and from outside the public edge when Internet publication is intended. Use an application request that verifies the expected identity and response, not only a successful TCP handshake.
When evidence disagrees, follow Diagnose DNS, routing, and firewall paths without disabling the firewall as a shortcut.
Publish the narrowest path #
Permit only the intended source, destination address, transport, and port. Preserve a recovery channel and validate PF changes before loading them by following Change PF safely on a remote host .
For HTTP applications, prefer one reviewed reverse-proxy entry point over publishing every application’s administrative interface. Keep upstream listeners on loopback, a Unix socket, or a private service network where the application supports it. Design a reverse proxy, certificates, and monitoring covers Caddy, nginx, certificate ownership, and external health checks.
Not every service belongs behind an HTTP proxy. Mail, DNS, VPN, NFS, SMB, and other protocols need protocol-specific publication and authentication decisions. See Choose a mail server or an outgoing relay and Choose NFS or Samba for file sharing . NFS and SMB should remain on a trusted private network or authenticated VPN rather than being exposed directly to the public Internet.
Define TLS and authentication separately #
TLS authenticates an endpoint and protects traffic when correctly configured; it does not decide which application user may act. Authentication proves an identity; authorization limits what that identity can do. Record each boundary separately.
For a public TLS service, assign ownership for:
- DNS names and address changes;
- certificate issuance and renewal;
- private-key file ownership and mode;
- the daemon reload after renewal;
- expiry and renewal-failure alerts;
- supported protocol and cipher policy from current daemon guidance.
Disable default credentials and anonymous administrative access before publication. Prefer individual identities and the application’s strongest maintained authentication mechanism. Administrative interfaces should normally require a private management network or VPN even when they also have passwords.
Review Establish a practical security baseline for account, patch, time, logging, and recovery prerequisites.
Keep secrets outside ordinary configuration history #
Inventory private keys, API tokens, passwords, database credentials, and recovery codes. Give each secret the narrowest owning account and file permissions supported by the daemon. Do not place plaintext secrets in a public repository, shell command line, world-readable environment file, or captured diagnostic output.
Configuration management should retrieve secrets from its designated protected source and avoid printing them in diffs or run logs. Backup encryption does not correct overly broad permissions on the live host. Define rotation and revocation before the first incident.
Make logs and updates actionable #
Identify where the service writes startup failures, authentication events, rejected requests, application errors, and audit-relevant changes. Confirm log rotation and retention before traffic arrives. Sensitive headers, tokens, message bodies, and personal data should not be logged merely because verbose logging is available.
At minimum, the owner needs evidence for:
- package and base-system security advisories;
- failed startup, reload, and configuration validation;
- repeated authentication failures or abuse signals;
- resource exhaustion, disk capacity, and database health;
- certificate renewal and expiration;
- backup completion and restore-test age.
Updates need a representative test, maintenance window, configuration migration plan, rollback decision, and post-update functional check. Distinguish base-system, package, jail, and guest updates rather than applying one undifferentiated upgrade command.
Back up a restorable service #
List every input required to reconstruct the service:
- package origin and version policy;
- rc.conf variables and daemon configuration;
- secrets and certificate material;
- durable files, datasets, and database state;
- firewall, proxy, DNS, and jail or VM definitions;
- external dependencies and recovery credentials;
- restore order and acceptance test.
A filesystem snapshot taken while a database is writing may not be application-consistent. Use the application’s documented quiesce, dump, or replication mechanism where required. Keep at least one backup outside the service’s credentials and failure boundary.
Restore into an isolated address or disposable jail or VM, then verify authentication, data integrity, and an application-level transaction. Opening the archive is not a restore test.
Admit the service only after an external check #
Publication is complete only when the intended client can reach the intended name, validate the endpoint identity, authenticate, perform one representative operation, and produce the expected log and health signal. Also confirm that a disallowed client cannot reach the service.
Monitor from outside the service host so host, routing, firewall, DNS, certificate, and daemon failures remain observable. Process and port checks are useful layers, but an application-level check is authoritative for availability. Route alerts to a channel that does not depend solely on the failed service.