Disclaimer: This guide and the provided code are for educational purposes only, designed to teach how containerized networking and ephemeral data storage work.
Before starting, ensure you have a Docker network called dmz created:
docker network create dmz
mkdir tor && cd "$_"
mkdir html
Create the Tor configuration file.
nano torrc
Add the following configuration. This tells Tor to forward traffic on port 80 to our Nginx container:
SocksPort 0
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 tor_web_01:80
Create a basic test page to verify the Tor connection.
nano html/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TOR Test Page</title>
<style>
body { margin: 0; background: #111; color: #ddd; font-family: "Courier New", monospace; text-align: center; }
.container { width: 700px; max-width: 90%; margin: 80px auto; padding: 35px; border: 2px solid #777; background: #1b1b1b; }
h1 { color: #fff; font-size: 36px; letter-spacing: 4px; }
.line { border-top: 1px dashed #777; margin: 25px 0; }
.status { color: #00ff66; font-size: 20px; }
footer { margin-top: 40px; color: #777; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<h1>TOR TEST SERVER</h1>
<div class="line"></div>
<p class="status">[ ONLINE ]</p>
<p>If you can see this page through the <strong>Tor Browser</strong>, the onion service is working correctly.</p>
<div class="line"></div>
<p>SYSTEM STATUS<br>Web Server: ONLINE<br>Tor Service: ONLINE</p>
<footer>© 1996–2026 — Tor Network Test Page<br>Built for educational purposes.</footer>
</div>
</body>
</html>
nano docker-compose.yml
services:
tor_web_01:
image: nginx:alpine
container_name: tor_web_01
restart: unless-stopped
volumes:
- ./html:/usr/share/nginx/html:ro
networks:
- dmz
tor_hidden_service:
image: alpine:latest
container_name: tor_hidden_service
command: >
sh -c "apk update && apk add --no-cache tor &&
chown -R root:root /var/lib/tor/hidden_service &&
chmod 700 /var/lib/tor/hidden_service &&
tor -f /etc/tor/torrc"
volumes:
- ./torrc:/etc/tor/torrc:ro
- ./data:/var/lib/tor/hidden_service
restart: unless-stopped
depends_on:
- tor_web_01
networks:
- dmz
networks:
dmz:
external: true
docker compose up -d
Wait 5 to 10 seconds for Tor to generate the cryptographic keys, then run this command to find the new .onion address:
cat ./data/hostname
Now that we know how to host a basic site, let's build something interactive: a private, live-chat arcade party room.
How does a privacy chat work?
Instead of saving messages to a database (like SQLite or MySQL), we will store them in the server's RAM. This is called Ephemeral Storage. If the Docker container is restarted or stopped, the chat history vanishes instantly and permanently.
We have prepared a ready to use template to get started quickly. Download the zip below
Deploy the container using --build flag:
docker compose down
docker compose up -d --build