← Back to Guides
GUIDE

How to Build a Self-Hosted Tool Server

A simple setup for hosting your own practical tools, project pages, and downloads without overcomplicating everything or handing control to somebody else.

What this is

This guide walks through building a small self-hosted server for useful tools and downloads. The goal is not to build a giant platform. The goal is to build something simple, private, and dependable that you can actually understand and maintain.

What you need

1. Install the base system

Flash Raspberry Pi OS Lite, boot the Pi, and make sure SSH is enabled. Then update the system.

sudo apt update && sudo apt upgrade -y

2. Install the packages you actually need

Keep it simple. For a Flask-based site, this is enough to get moving.

sudo apt install python3 python3-venv python3-pip nginx -y

3. Create your project directory

Put your site in its own folder so it stays predictable and easy to back up.

mkdir ~/thehermit-site
cd ~/thehermit-site
python3 -m venv venv
source venv/bin/activate

4. Install your Python packages

pip install flask gunicorn flask-login flask-limiter itsdangerous

5. Build the app

Start with a basic Flask app, then add your routes, templates, downloads, and account features as needed. Do not overbuild it on day one. Useful and stable beats clever and broken.

6. Run it with Gunicorn

Do not leave the Flask development server running for real use.

gunicorn --workers 2 --bind 127.0.0.1:5000 app:app

7. Create a systemd service

This keeps the app running on boot and makes restarting it easy.

[Unit]
Description=The Hermit Site
After=network.target

[Service]
User=devin
WorkingDirectory=/home/devin/thehermit-site
ExecStart=/home/devin/thehermit-site/venv/bin/gunicorn --workers 2 --bind 127.0.0.1:5000 app:app
EnvironmentFile=/etc/thehermit-site.env

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable thehermit-site
sudo systemctl start thehermit-site
sudo systemctl status thehermit-site

8. Put nginx in front of it

nginx listens on the normal web ports and passes requests to Gunicorn.

location / {
    proxy_pass http://127.0.0.1:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
sudo nginx -t
sudo systemctl restart nginx

9. Add a downloads folder

If you want to serve APKs, ZIP files, or other downloads, keep them in one dedicated location.

mkdir /home/devin/thehermit-site/private_downloads

Then serve them through Flask with a controlled route instead of exposing random folders.

from flask import send_from_directory, abort
import os

PRIVATE_DOWNLOADS = "/home/devin/thehermit-site/private_downloads"

@app.route("/downloads/<path:filename>")
@login_required
def download_file(filename):
    safe_path = os.path.abspath(os.path.join(PRIVATE_DOWNLOADS, filename))
    private_root = os.path.abspath(PRIVATE_DOWNLOADS)

    if not safe_path.startswith(private_root):
        abort(403)

    if not os.path.isfile(safe_path):
        abort(404)

    return send_from_directory(PRIVATE_DOWNLOADS, filename, as_attachment=True)

10. Keep secrets out of your code

Put your secret key, base URL, and mail credentials in an environment file instead of hardcoding them.

sudo nano /etc/thehermit-site.env
SECRET_KEY=replace-this
BASE_URL=https://yourdomain.com
SESSION_COOKIE_SECURE=true
SMTP2GO_HOST=mail.smtp2go.com
SMTP2GO_PORT=587
SMTP2GO_USER=your-user
SMTP2GO_PASS=your-pass
[email protected]

11. Use a tunnel instead of opening router ports

A Cloudflare Tunnel is a clean way to expose your site without dealing with direct port forwarding. It is usually less annoying than fighting with consumer routers, which is not a high bar, but still.

12. Back it up

At minimum, back up your project folder, templates, environment notes, and database. A working server with no backup is just a future headache waiting for its cue.

zip -r thehermit-site-backup.zip /home/devin/thehermit-site
Keep at least one backup copy somewhere other than the server itself. A backup stored only on the same machine is not a backup. It is wishful thinking in a different folder.

Final thoughts

A self-hosted tool server does not need to be huge to be valuable. If it runs your tools, hosts your files, and stays under your control, it is doing the job. Start simple, keep it understandable, and add features only when they solve a real problem.