en

Python Flask Tor Hidden Service: Build and Deploy Guide

Python Flask is an excellent choice for Tor hidden service development: simple to learn, flexible, has strong libraries for cryptography and database access, and deploys well with uWSGI and Nginx. This guide covers building a Flask application from development through production hidden service deployment.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

Development Environment Setup

Create an isolated development environment: python3 -m venv venv; source venv/bin/activate. Install Flask and dependencies: pip install flask flask-sqlalchemy flask-login werkzeug. Development structure: app/__init__.py (factory pattern), app/models.py (SQLAlchemy models), app/routes/ (blueprint-organized routes), app/templates/ (Jinja2 templates), config.py (configuration class). Development configuration: DEBUG=True, SQLite database for development. Security note: never use Flask's debug mode in production - it provides an interactive debugger that allows arbitrary code execution. Flask development server (flask run) is for development only - use uWSGI or Gunicorn in production.

Flask Security Configuration for Hidden Services

Critical Flask security settings in config.py: SECRET_KEY = os.urandom(32) (generate once, store securely - losing this invalidates all sessions), SESSION_COOKIE_HTTPONLY = True, SESSION_COOKIE_SAMESITE = 'Strict', WTF_CSRF_ENABLED = True (if using Flask-WTF), SQLALCHEMY_ENGINE_OPTIONS = {'pool_pre_ping': True}. Disable Flask debug toolbar and Werkzeug debugger in production: app.config['DEBUG'] = False, app.config['TESTING'] = False. Error handling: configure custom 404 and 500 error pages that do not reveal stack traces or server information. Avoid revealing Python version, Flask version, or server details in error responses.

Database Layer with SQLAlchemy for Hidden Services

SQLAlchemy provides ORM access to PostgreSQL or SQLite for Flask hidden services. Define models in app/models.py: from flask_sqlalchemy import SQLAlchemy; db = SQLAlchemy(). User model: class User(db.Model): id = db.Column(db.Integer, primary_key=True); username = db.Column(db.String(80), unique=True, nullable=False); password_hash = db.Column(db.String(200), nullable=False). Password hashing with werkzeug: from werkzeug.security import generate_password_hash, check_password_hash. Always use parameterized queries via SQLAlchemy ORM (prevents SQL injection automatically). If raw SQL is needed: db.session.execute(text('SELECT * FROM users WHERE id = :uid'), {'uid': user_id}). Never format user input into SQL strings.

Production Deployment: uWSGI + Nginx + Tor

Production stack: uWSGI runs Flask application, Nginx reverse proxies to uWSGI via Unix socket, Tor serves the .onion address pointing to Nginx. uWSGI configuration (uwsgi.ini): [uwsgi]; socket = /run/uwsgi/hidden-site.sock; chmod-socket = 660; vacuum = true; module = app:create_app(); callable = app; master = true; processes = 2. Nginx upstream: upstream flask_app { server unix:/run/uwsgi/hidden-site.sock; }. Nginx server block: listen 127.0.0.1:80; location / { uwsgi_pass flask_app; include uwsgi_params; }. Tor torrc: HiddenServicePort 80 127.0.0.1:80. Systemd service for uWSGI ensures restart on crash: ExecStart=/path/to/venv/bin/uwsgi --ini uwsgi.ini; Restart=always.

Request Validation and CSRF Protection

All form submissions must include CSRF tokens to prevent cross-site request forgery. Flask-WTF provides automatic CSRF protection: from flask_wtf.csrf import CSRFProtect; csrf = CSRFProtect(app). All forms include: {{ form.csrf_token }}. For AJAX requests: include X-CSRFToken header from cookie. Input validation: validate all user inputs on the server side (never trust client-side validation alone). Limit: username length (80 chars max), message length (10,000 chars max), file upload size (set in Flask config: MAX_CONTENT_LENGTH = 16 * 1024 * 1024 for 16MB). Strip dangerous characters from displayed content or use Jinja2's auto-escaping (enabled by default for .html templates). File uploads: validate MIME type against actual content (use python-magic), store outside webroot, never execute uploaded files.

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online