// Python Dev
RabbitMQ as a bridge between the external and internal networks
Published on 2026-04-03
Queue brokers are usually seen as a tool inside a single system — decouple microservices, smooth out load spikes, organize background jobs. But there’s a much less obvious use: use the broker as a data access point for data that physically resides inside the organization and does not leave it.
In practice any attempt to provide external access to internal data quickly turns into an infrastructure project: approvals, security, network restrictions. Even a simple task like “get a client’s balance” can hit weeks of work and involve multiple teams.
Data inside, request from outside
Typical situation: there is an external application — a personal account, mobile app, or partner service — that needs to get up-to-date data from an internal system. For example, a client’s balance from billing.
The standard options are all worse than each other. Opening a port to the outside is the most obvious one, and it’s the first thing security teams reject — correctly so. Setting up a VPN sounds reasonable, but in practice it’s a separate project with its own approvals, certificates, and support, and it’s not always possible on the external system side, especially if it’s someone else’s cloud. A public IP — there might simply not be one: the provider gives dynamic addressing behind NAT, and forwarding a connection from outside to inside without additional infrastructure is impossible. For small companies and branches this is a perfectly normal situation.
Real-world case
In one project we needed to implement a Telegram bot for a provider, through which a user could view their current balance. The problem was that the billing system was inside a closed network inside a datacenter and had a SOAP API accessible only from inside the network. Opening access to the outside was forbidden, implementing a VPN on the bot side was impossible, and the bot itself ran in the cloud. As a result, even a simple request “show balance” turned into an integration task between completely isolated systems.
Broker outside as a meeting point
The idea is simple but non-obvious: run a RabbitMQ instance not inside the organization, but outside — next to the external application, on a publicly accessible server. This broker is simultaneously reachable by both the external system and the internal one — because the internal service itself initiates an outgoing connection to the outside, and outgoing connections, unlike incoming ones, are almost never blocked by firewalls or NAT.
The scheme looks like this: the external application puts a request into a queue on the broker. The internal service listens to that queue, takes the request, goes to the billing or any other internal source, and puts the response into another queue. The external application retrieves the response.
Data goes outside exactly when it is needed, and only the data that was requested. The internal system remains closed — it decides when and what to give.
RPC over queues: asynchrony without pain
The obvious complexity of this scheme is asynchrony. When there are many requests, you need to understand which response corresponds to which request. You can tag each message manually, but RabbitMQ provides a ready-made mechanism — RPC over queues.
It works like this: when sending a request the client specifies the name of a temporary queue to which it expects the reply (reply_to), and a unique correlation_id. The internal service processes the request and sends the response not to a common queue but directly to this temporary queue with the same correlation_id. The client simply waits for its response — without extra routing logic.
You don’t have to implement this manually — RPC over RabbitMQ is already supported by ready libraries. For example, FastStream provides a convenient declarative interface: a queue subscriber is described as a regular async function, and the library handles the reply_to and correlation_id mechanism. The code becomes more compact and reads like a normal service rather than working with the broker directly.
Below is a minimal example in pika to make clear what happens under the hood.
Client (external system)
import pika, uuid
connection = pika.BlockingConnection(pika.ConnectionParameters('broker.example.com'))
channel = connection.channel()
# Temporary reply queue — RabbitMQ will delete it after disconnect
result = channel.queue_declare(queue='', exclusive=True)
reply_queue = result.method.queue
correlation_id = str(uuid.uuid4())
channel.basic_publish(
exchange='',
routing_key='billing.requests',
properties=pika.BasicProperties(
reply_to=reply_queue,
correlation_id=correlation_id,
),
body='{"client_id": 42, "action": "get_balance"}'
)
# Wait for the response to our specific request
for method, props, body in channel.consume(reply_queue):
if props.correlation_id == correlation_id:
print(f"Balance: {body.decode()}")
channel.cancel()
break
Handler (internal service)
import pika, json
connection = pika.BlockingConnection(pika.ConnectionParameters('broker.example.com'))
channel = connection.channel()
channel.queue_declare(queue='billing.requests')
def on_request(ch, method, props, body):
request = json.loads(body)
balance = get_balance_from_billing(request['client_id']) # call to internal source
ch.basic_publish(
exchange='',
routing_key=props.reply_to,
properties=pika.BasicProperties(correlation_id=props.correlation_id),
body=str(balance)
)
ch.basic_ack(delivery_tag=method.delivery_tag)
channel.basic_consume(queue='billing.requests', on_message_callback=on_request)
channel.start_consuming()
This turns asynchronous interaction into something almost synchronous from the code’s perspective: send a request — wait — receive a response. At the same time there is no need to store any additional state.
What this achieves
This scheme addresses several problems at once without extra infrastructure: no public IP needed, no VPN, no need to open access into the internal network. Authorization and encryption are handled at the RabbitMQ level — TLS and credentials replace the whole infrastructure of API keys and tokens. You can deploy this in a day or two: two small services and one broker instance.
It’s not a universal tool. But for tasks where you need to provide access to data from a closed network on demand — billing, internal CRMs, accounting systems — this is one of the simplest and cheapest options. For streaming large volumes or scenarios with strict latency requirements the scheme is less suitable — other tools are needed there.
// Python Dev
Другие статьи Python Dev
2026-04-01
How to set up queue dialing via SIP and Python
This note analyzes the architecture of an automated outbound calling system: how the processing pipeline is organized, how dialing via Asterisk AMI works, and …
2026-04-01
How to analyze thousands of reviews on Wildberries using LAG: a step-by-step walkthrough
For popular products on Wildberries, the number of reviews easily runs into the thousands. Reading them manually is slow, tedious, and inefficient. Real reasons …
// Python Projects
Проекты Python Dev
2026-03-26
Telegram bot for voice pranks
An upgrade of an existing Telegram bot: calls through SIP and Telegram, response recording, and monetization through Telegram Stars.
2026-03-26
Automatic energy consumption control system
An MVP system for controlling energy usage limits on EV charging points with automatic relay shutdown and full action logging.
2026-03-26
Automatic management of a Telegram channel network for a travel agent
An automated publishing system for 150 Telegram channels with tour and flight selection, image generation, and scheduled posting.
// Contact
Need help?
Get in touch with me and I'll help solve the problem