There are different ways to achieve your goal.
If the guests share a virtual network (i.e. are not just bridged to the physical interface) it's easy. Just tell your services to listen on that interface - or create a new guest and let that one host the service.
If the guests are bridged to
ethX, you might still want to consider creating a virtual guest+host-only interface as that kind of encapsulation makes sense for all kinds of services (internal mail-server, any database server, local DNS, etc.)
(And obviously there's the way you already discarded for some reason: firewall rules)
lo: each lxc host has its own, and that's good imo
My lxc guests all share a virtual interface and for each service that should be exposed to the public internet, I create port forwarding rules on the host's iptables. And I try to run as few services as possible on the host itself. That way there's little to no rist accidentally exposing any services.
And for the sake of completeness, here's my config:
interfaces file (debian stable):
iface br0 inet static
# if there are lxc clients that need a public IP, add something like this (a.b.c.d being the public IP) and set the client's `lxc.network.ipv4` config parameter to the same address:
#post-up route add a.b.c.d dev br0
The relevant part of the client config:
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.veth.pair = lxc-apache # each client gets their own .pair name
lxc.network.ipv4 = 192.168.x.y/24 # ... and of course their own address