Railway.app: How to Retrieve a User's IP Address In FastAPI

blog image

Recently, I initiated the shift of my side project applications from the robust Virtual Private Servers offered by OVH to the innovative and streamlined hosting services of Railway.app.

The motivations behind this move are manifold and certainly merit a dedicated discussion in a future post.

Nevertheless, this transition brought to light a common challenge when dealing with modern hosting solutions: handling client IP retrieval behind Railway.app’s proxy layer.

The solution was quickly highlighted by Brody from Railway.app’s discord community, but I knew this deserved a dedicated blog post for anyone looking this up.

Understanding the X-Envoy-External-Address Header

Applications deployed on Railway.app run behind a proxy, which means the client’s direct IP is not readily available through standard request attributes. Railway.app uses the X-Envoy-External-Address header to forward the original client IP. FastAPI’s request handling features come in handy to extract this information seamlessly.

Step-by-Step Guide to Retrieving the Client IP

To integrate client IP retrieval into your FastAPI app, you can use the following function:

# Assuming this is function is stored in a filed called helpers.py

from fastapi import Request

def get_client_ip(request: Request) -> str:
    # Attempt to retrieve the 'X-Envoy-External-Address' header
    client_ip = request.headers.get("X-Envoy-External-Address")

    # If the header is absent or None, fall back on 'client.host'. Comes in handy if you're developing locally, or want to migrate from Railway.app in the future.
    if client_ip is None:
        client_ip = request.client.host 

    return client_ip

This function checks for the presence of the X-Envoy-External-Address header and uses it if available. If not, it defaults to request.client.host.

Integration with Endpoints

You can call the get_client_ip function within any FastAPI endpoint:

# Assuming this is section of your code is in your main.py file
import helpers

@app.get("/get-my-ip")
async def get_my_ip(request: Request):
    client_ip = helpers.get_client_ip(request)
    return {"Client IP": client_ip}

This way, the client’s IP address is returned whenever the /get-my-ip endpoint is accessed.

Conclusion

Retrieving the client’s IP address in a FastAPI application on Railway.app necessitates special handling to account for the platform’s proxy configuration. By using the X-Envoy-External-Address header and providing a fallback to request.client.host, developers can ensure they capture this critical information effectively.

In closing, it’s important to note that the code snippets presented in this post are for example purposes. They serve to demonstrate the concept of IP retrieval in a FastAPI environment configured behind Railway.app’s proxy.

Before integrating these examples into your own projects, please ensure to review and refactor the code in accordance with the architecture and directory structure of your applications.

Every app has its unique setup, and it’s crucial that you adapt the provided solutions to fit seamlessly into your existing codebase for optimal functionality and maintainability.

Liked this story? Share it with someone who needs to see it 👇