Public-facing is the part that stays hard. Two things that helped on my own box: nothing listens on 0.0.0.0 unless it has to (admin UIs go behind WireGuard), and each service owns a separate data volume, so a compromise is one container rather than the whole disk. Neither stops a 0-day — they only decide how bad the morning is.