Skip to main content
  1. Posts/

The Secret Self‑Hosted Tools Developers Keep Private – Real Community Examples & How to Build Yours

·4 mins

The Community Spark #

r/selfhosted erupted this week with the “coolest private tool” thread. Users proudly displayed bespoke scripts, low‑profile dashboards, and automation bots they deliberately keep under wraps—often because the tools solve niche problems, contain sensitive credentials, or give them a competitive edge. The buzz isn’t just about bragging; it surfaces a real need for secure, reproducible, and truly private solutions that never see the public GitHub spotlight.

Synthesized Community Perspectives #

PerspectiveCore ArgumentTypical Examples
Privacy‑First Engineers“If it’s on a public repo, it’s a target.”Encrypted password rotator, internal API gateway.
Open‑Source Advocates“Sharing improves security via peer review.”Minimalist log aggregator, self‑hosted CI pipeline.
Business‑Oriented Users“Proprietary tools protect revenue streams.”Custom invoice‑generator, client‑specific data scrubber.
Security Auditors“Even private tools need documentation.”Threat‑model checklist, automated hardening script.

The consensus: private tools thrive when they’re reproducible, auditable, and containerized, even if the source never leaves the developer’s vault. The main debate circles around how much to document without leaking the secret sauce.

Deep‑Dive Actionable Guide: Build a Private “Secure File‑Drop” Service #

Below is a practical, reproducible recipe that mirrors the most up‑voted community example—a self‑hosted, password‑protected file drop that never leaves your VPS.

1. Prerequisites #

# Ubuntu 22.04 LTS, Docker, and Docker‑Compose installed
sudo apt update && sudo apt install -y docker.io docker-compose

2. Directory Layout #

mkdir -p ~/secure-drop/{app,nginx,certs}
cd ~/secure-drop

3. Application – Python FastAPI #

Create app/main.py:

from fastapi import FastAPI, File, UploadFile, HTTPException, Depends
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import os, secrets, shutil

app = FastAPI()
security = HTTPBasic()
UPLOAD_DIR = "/data"

def verify(credentials: HTTPBasicCredentials = Depends(security)):
    # Credentials stored in Docker secret, never in code
    correct_user = os.getenv("DROP_USER")
    correct_pass = os.getenv("DROP_PASS")
    if credentials.username != correct_user or credentials.password != correct_pass:
        raise HTTPException(status_code=401, detail="Unauthorized")
    return True

@app.post("/upload")
def upload(file: UploadFile = File(...), auth: bool = Depends(verify)):
    dest = os.path.join(UPLOAD_DIR, secrets.token_hex(8) + "_" + file.filename)
    with open(dest, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    return {"filename": dest}

Create app/Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

requirements.txt:

fastapi
uvicorn

4. Reverse Proxy – Nginx (TLS termination) #

Create nginx/nginx.conf:

server {
    listen 443 ssl;
    server_name drop.example.com;

    ssl_certificate /certs/fullchain.pem;
    ssl_certificate_key /certs/privkey.pem;

    location / {
        proxy_pass http://app:8000;
        proxy_set_header Host $host;
    }
}

5. Docker‑Compose (with Docker secrets) #

version: "3.8"

services:
  app:
    build: ./app
    environment:
      DROP_USER_FILE: /run/secrets/drop_user
      DROP_PASS_FILE: /run/secrets/drop_pass
    secrets:
      - drop_user
      - drop_pass
    volumes:
      - ./data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/certs:ro
    depends_on:
      - app
    restart: unless-stopped

secrets:
  drop_user:
    file: ./secrets/drop_user.txt
  drop_pass:
    file: ./secrets/drop_pass.txt

6. Secure the Secrets #

mkdir secrets
echo "admin" > secrets/drop_user.txt
openssl rand -base64 32 > secrets/drop_pass.txt   # strong random password
chmod 600 secrets/*

7. Launch #

docker compose up -d

Your private file‑drop is now reachable at https://drop.example.com/upload. Because the credentials live as Docker secrets and the code never contains them, the tool can stay forever private while remaining reproducible for your own team.

Pros & Cons / Comparative Table #

AspectPrivate‑Only Tool (e.g., above)Public Open‑Source Alternative
SecuritySecrets stored in Docker secrets, no public exposureCommunity scrutiny but risk of supply‑chain attacks
MaintainabilityRequires internal documentation; single point of failureCommunity updates, broader support
Speed to DeployFast – only internal testing neededSlower – must vet PRs and dependencies
ScalabilityContainerized, easy to scale on any VPSDepends on project’s architecture
LongevityAs long as you keep the repo & secretsDepends on community interest

The Verdict / Expert Advice #

  • Solo Hobbyist / DevOps Learner – Start with the containerized pattern above; it gives you a production‑grade baseline without exposing code.
  • SMB / Startup – Keep the tool private but document the architecture in an internal wiki. Use Docker secrets or HashiCorp Vault to avoid credential leaks.
  • Enterprise – Pair the private tool with policy‑as‑code (e.g., Open Policy Agent) and periodic audit scripts to satisfy compliance while preserving secrecy.

In every case, reproducibility beats obscurity. A private tool that can be rebuilt from a single docker-compose.yml is far more valuable than a one‑off script hidden in a laptop.

Frequently Asked Questions (FAQ) #

Q1: How can I share a private tool with teammates without publishing it?
A: Use a private Git repository (GitLab self‑hosted, Gitea, or a password‑protected Bitbucket repo) and store secrets in Docker secrets, Vault, or environment files excluded via .gitignore.

Q2: Is it safe to keep credentials inside Docker images?
A: No. Embed them as Docker secrets or mount them at runtime. Images should never contain raw passwords or API keys.

Q3: What backup strategy works for private self‑hosted services?
A: Snapshot the entire data volume (docker volume), version‑control your docker-compose.yml, and store encrypted backups (e.g., restic with GPG) off‑site.

Q4: When should I consider open‑sourcing a private tool?
A: If the tool solves a generic problem, has no proprietary data, and you can separate the secret parts (credentials, keys) into a config layer, open‑sourcing can improve security and attract contributions.