Deploying a Python Backend on Oyster: Step-by-Step Technical Guide
Introduction 
Deploying secure and scalable backends is a core challenge for modern developers. In this article, you’ll learn how to build an asynchronous TCP Echo Server in Python, containerize it with Docker, deploy it securely on Marlin’s Oyster TEEs and verify its remote attestation.
Prerequisites 
Before you begin, ensure you have:
- Basic knowledge of Python and Docker
- Access to a Linux or macOS terminal (or WSL on Windows)
- An Ethereum wallet private key with 0.001 ETH and 1 USDC on the Arbitrum One network
- Docker installed (Docker installation guide)
- Oyster CLI installed (Oyster CLI installation guide)
Step 1 - Setting Up Your Development Environment 
First, verify your development environment is ready:
- Ensure Python is installed:
python --version
- Confirm Docker is installed and running:
docker --version
- (Optional) Use Oyster’s CLI doctor command to check Docker:
oyster-cvm doctor --docker
Step 2 - Creating the Python Asynchronous TCP Echo Server 
We’ll use Python’s asyncio
library to create a simple TCP server that echoes messages back to connected clients, including the server’s hostname for clarity.
Create a file named echo-server.py
and add the following code:
#!/usr/bin/env python3
import platform
import asyncio
# server will listen on PORT 5000.
PORT_ECHO_TCP = 5000
# server will listen on all available network interfaces.
INADDR_ANY = "0.0.0.0"
SERVER_NAME = platform.node()
# provides methods to handle network events.
class TcpEchoServer(asyncio.Protocol):
def connection_made(self, transport):
self.peername = transport.get_extra_info('peername')
print(f'TCP: Connection from {self.peername}')
self.transport = transport
def data_received(self, data):
in_msg = data.decode().strip()
print(f'TCP: Received: {in_msg} from {self.peername}')
out_msg = f'TCP: {SERVER_NAME} received: {in_msg}\n'
self.transport.write(out_msg.encode())
# The main asynchronous function that gets the current event loop.
async def main():
loop = asyncio.get_running_loop()
print(f"Starting TCP server on port {PORT_ECHO_TCP}")
tcp_server = await loop.create_server(
lambda: TcpEchoServer(),
INADDR_ANY, PORT_ECHO_TCP)
async with tcp_server:
await tcp_server.serve_forever()
asyncio.run(main())
To run the server locally:
python echo-server.py
In a new terminal, connect using netcat:
nc localhost 5000
Type messages, and you’ll see them echoed back by the server.
Step 3 - Dockerizing the Server 
Containerizing your application ensures consistency across deployments.
Create a Dockerfile
in your project directory:
FROM alpine:3.11
RUN apk add python3
COPY echo-server.py /echo-server.py
CMD ["python3", "-u", "/echo-server.py"]
EXPOSE 5000/tcp
Build and push the Docker image:
Replace <username>
with your Docker Hub username.
sudo docker login
sudo docker build -t <username>/echo-server:latest .
sudo docker push <username>/echo-server:latest
Test the Docker image locally:
docker run --rm -p 5000:5000 --name echo-server <username>/echo-server
Connect with nc localhost 5000
as before to verify functionality.
Step 4 - Deploying on Marlin’s Oyster TEEs 
Creating a Docker Compose File
Create a file named docker-compose.yml
describing the service being deployed after replacing the <username>/echo-server
with the docker image created in the previous step:
services:
echo-server:
image: <username>/echo-server
network_mode: host
restart: unless-stopped
Deploying the Enclave
Use the Oyster CLI to deploy your containerized backend in a secure enclave.
# replace <key> with private key of the wallet
# for amd64
oyster-cvm deploy --wallet-private-key <key> --duration-in-minutes 15 --docker-compose docker-compose.yml --arch amd64
# for arm64
oyster-cvm deploy --wallet-private-key <key> --duration-in-minutes 15 --docker-compose docker-compose.yml
Make a note of the “Computed image id” and the enclave IP printed in the logs. These are essential for future verification and access.
Connecting to Your Deployed Server
Once deployed, interact with your echo server using:
nc <ip> 5000
Replace <ip>
with the enclave IP from the deployment logs. You should see your messages echoed back, confirming a successful deployment.
Example Output:
$ nc <ip> 5000
We love oyster!
TCP: (none) received: We love oyster!
Hello from Python Backend!
TCP: (none) received: Hello from Python Backend!
Step 5 - Verifying Remote Attestation 
Oyster supports remote attestation, ensuring your backend runs in a trusted environment.
To verify:
# Replace <ip> and <image_id> with values from your deployment
oyster-cvm verify --enclave-ip <ip> --image-id <image_id>
A successful verification will confirm your backend is running securely.
Conclusion 
By following this guide, you have:
- Built an asynchronous TCP Echo Server in Python
- Containerized your application with Docker
- Deployed and verified your backend on Marlin’s Oyster TEE using confidential computing
This workflow ensures your backend is scalable and secure. Next, you can extend your backend’s functionality, explore Oyster’s advanced features, or integrate with other services for a production-ready deployment.