Skip to content

Latest commit

 

History

430 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DockHub — your self-hosted server, simplified

License: MIT ShellCheck Shell Docker Platforms ARM64

Services Categories NPM Portainer TLS Backups GPU

Self-hosted services, deployed properly. One script installs the Docker foundation; a menu deploys any of 42 services on top of it — each with a reverse proxy route, a backup path, and documentation written from actually running it.

git clone https://github.com/IbrahimAljuhani/dockhub.git
cd dockhub
sudo bash install_dockhub.sh

📑 Contents


🎯 What DockHub is

A catalogue of self-hostable services with a consistent deployment script for each, plus the infrastructure they all share: a reverse proxy, a container manager, and one predictable place on disk for everything.

It is not a control panel and not a PaaS. Nothing runs in the background, nothing phones home, and nothing hides what it did — every deployment is a plain docker-compose.yml you can read, edit, or take somewhere else.

Who it is for: anyone standing up services on their own hardware — a home server, a VPS, a spare machine under a desk — who wants them proxied, backed up and reachable without assembling each one by hand.


🚀 Getting started

1 — Install the foundation. Docker CE, Docker Compose, NGINX Proxy Manager and Portainer, with every port and image overridable:

sudo bash install_dockhub.sh

2 — Deploy services. The installer hands off to the picker when it finishes, or run it yourself at any time:

bash services/services.sh

You get a category menu, then a service menu, then a short interview — domain or host port, memory limit, and whatever that particular service genuinely needs. Nothing is assumed.

Run the installer with sudo, the picker as yourself. install_dockhub.sh drops privileges before handing off, so services deploy under your own user with your own file ownership.


🧱 The core: what install_dockhub.sh gives you

Purpose Reached at
Docker CE + Compose Installed for your distribution, or skipped if already present
NGINX Proxy Manager Routes domains to containers, issues Let's Encrypt certificates :81 admin — you are asked where it listens, see below
Portainer CE A web view of every container, volume and network no host port by default — see below
main-net The shared bridge network the proxy and your services meet on

First-login credentials — change both immediately:

NGINX Proxy Manager admin@example.com / changeme
Portainer No default — the first visitor creates the admin account. Reach it and create yours before anyone else can, or close it again until you do

Docker is not optional; NPM and Portainer are. The installer asks about the last two, because a host that only ever uses LAN ports needs neither. It does not ask about Docker — a choice you cannot decline is not a choice.

Portainer gets no host port unless you ask for it. It mounts /var/run/docker.sock, so reaching its web interface is equivalent to root on the machine — it is not a dashboard, it is a key. By default it joins main-net only, reachable as portainer:9000, and you publish it deliberately through NGINX Proxy Manager with HTTPS in front. Answer yes to the port question and it binds every interface, which on a VPS means the internet.

The same rule already removed the host-port option from Vaultwarden outright. Portainer is the more dangerous of the two and kept its ports open for longer than it should have.

NPM's admin panel is asked about too, and it took even longer. Port 81 was published on every interface unconditionally, with admin@example.com / changeme — a pair printed in this very file, so treat it as already known. The installer now asks, and the two answers are every interface or 127.0.0.1 only, reached over ssh -L 8181:127.0.0.1:81 <user>@<server>. It defaults to loopback when you say you are using a Cloudflare Tunnel, and warns loudly on a directly exposed VPS.

There is deliberately no "no port at all" option: you cannot put the admin panel behind NPM without first reaching the admin panel to configure it. Loopback is the honest floor — invisible to every network, and it can never lock you out.

The installer also asks, once, whether this is a home server or a VPS, and how you intend to reach it from outside — port forwarding (or, on a VPS, direct exposure) versus Cloudflare Tunnel. Both questions are asked in both cases: a tunnel is not only a workaround for lacking a public IP, and on a VPS it is the stronger option, being the only arrangement with no inbound port at all. The answers are remembered in ~/docker/.dockhub-env and shape the advice this installer and every later script give you — which ports to open, where NPM's admin panel should listen, and what the closing summary tells you to visit.


📚 The catalogue

Each category has its own README explaining what the services are for, how they differ, and the traps found while building them.

Category Services Built
🧠 AI Ollama · llama.cpp · LocalAI · Open WebUI 4/4
🤖 AI-Agents OpenClaw · Hermes · OpenHands 3/3
🧩 Multi-Agent Paperclip · Dify · Flowise · Langflow 4/4
⚙️ Automation n8n 1/1
🌐 DNS Pi-hole · AdGuard Home 2/2
🏢 ERP Odoo · ERPNext · Dolibarr 3/3
🏠 Home-Automation Home Assistant · Mosquitto 2/2
🎬 Media Jellyfin · Plex 2/2
📷 Photos Immich · PhotoPrism 2/2
📋 Projects OpenProject · Plane · Redmine · Taiga · Vikunja 5/5
🔐 Security Vaultwarden 1/1
🧪 Security-Lab Juice Shop · WebGoat · Vulhub 3/3
💾 Storage Nextcloud · ownCloud · Seafile 3/3
🔒 VPN WireGuard · NetBird · OpenVPN 3/3
🕸️ Web WordPress · Ghost · LinkStack 3/3

⚠️ Security-Lab is deliberately vulnerable software — training targets, not services. It sits behind its own gate and must never touch a network you care about. Read that category's README before deploying anything in it.


🔧 How every service behaves

The value of a catalogue is that the second service works like the first. Every deploy.sh here follows the same contract:

One command bash deploy.sh, or pick it from the menu
Asks, never assumes Domain or host port, memory limit, and any service-specific decision — each with the trade-off stated
Generates its own secrets Written to ~/docker/<service>/.<service>-docker-secrets.txt, chmod 600
Never overwrites your edits An existing .env or docker-compose.yml is reused, not replaced. Delete it yourself to take the newer version
Safe to rerun Reruns reconfigure; they do not reinstall or wipe
Self-tests at the end And says plainly what the test did not prove
Writes NEXT-STEPS.txt The manual steps that remain, with the reasoning behind them

Deployment is always a real Compose stack. Nothing is generated behind your back and nothing depends on DockHub staying installed.


🌐 Three networks, and why

Network Who is on it Purpose
main-net NGINX Proxy Manager, Portainer, and any service you want proxied Lets the proxy reach a container by name — no IPs, no published ports
ai-net Model providers, the AI-Agents services, and Paperclip Keeps model traffic on its own bridge
models-net Model providers, Open WebUI, and the Multi-Agent builders (Dify · Flowise · Langflow) The same models, reachable without reaching the agent services

A service on main-net can be given a domain and a certificate. A service not on it is reachable only through an optional host port on your LAN — which is exactly right for anything without a login of its own, and is why several services here default to no proxy at all.

Why the models have two networks rather than one. A Docker network is flat: every member can reach every other. So joining one to reach a model is also joining it to reach everything else on it — and ai-net carries OpenHands, which has no authentication of its own and mounts the Docker socket. That was fine while only agent services shared it. It stopped being fine when builders whose whole purpose is running code somebody else wrote needed a local model too.

So the three providers (Ollama, llama.cpp, LocalAI) join both networks and act as a hub: each consumer group reaches the models, neither reaches the other. The providers gain nothing from it — a network gives a container callers, and they call nobody. deploy.sh creates and joins both, so this needs no thought from you.

In NGINX Proxy Manager, always point a Proxy Host at the container name (jellyfin-app), never at the server's own IP — the container and the proxy share a network, and an IP would loop back through the proxy itself.


📁 Where everything lives

One tree, so the whole host is one backup target:

~/docker/
├── install_dockhub.log        # the installer's log, rotated on rerun
├── .dockhub-env               # your one-time home/VPS + access answers
│                              #   delete it and rerun the installer to change them —
│                              #   neither Reset nor Reconfigure re-asks
├── npm/                       # NGINX Proxy Manager: compose, data, certs
├── portainer/                 # compose (its data is a named volume, kept on rerun)
├── backups/
│   └── <service>/<timestamp>.tar.gz
└── <service>/                 # one folder per deployed service
    ├── docker-compose.yml
    ├── .env                   # chmod 600
    ├── deploy.log
    ├── NEXT-STEPS.txt
    └── data/                  # the service's own state

Runtime state stays flat under ~/docker/ regardless of the repo's category folders — services/ERP/odoo/ in git deploys to ~/docker/odoo/.


💾 Backups

The picker's Backup option archives a service's whole directory to ~/docker/backups/, and Restore puts it back. Services with a database ship their own backup.sh so the dump is consistent rather than a copy of files being written to.

Two deliberate exceptions:

  • Model weights are skipped. They are tens of gigabytes and can be downloaded again.
  • Agent data is not. Memories, learned skills and conversations exist nowhere else. See AI-Agents.

🔧 Environment variable overrides

The core installer takes no arguments — everything it publishes or pulls is an environment variable, so you can pin an image or move a port without editing the script:

Variable Default
NPM_IMAGE jc21/nginx-proxy-manager:latest Pin a version: NPM_IMAGE=jc21/nginx-proxy-manager:2.11.3
NPM_HTTP_PORT 80
NPM_HTTPS_PORT 443
NPM_ADMIN_PORT 81 The admin interface
PORTAINER_IMAGE portainer/portainer-ce:latest
PORTAINER_HTTP_PORT 9000
PORTAINER_HTTPS_PORT 9443
PORTAINER_EDGE_PORT 8000 Edge agent
sudo NPM_ADMIN_PORT=8081 PORTAINER_HTTP_PORT=9001 bash install_dockhub.sh

Values are validated before use — an image reference must look like name:tag and a port must be 1–65535, so a typo stops the run instead of being written into a Compose file.

Per-service settings are not env vars: each service asks its questions during deployment and records the answers in its own ~/docker/<service>/.env.


🖥️ Supported systems

OS family Versions
Debian 10 · 11 · 12
Ubuntu 20.04 · 22.04 · 24.04 (x86_64 & ARM64)
Raspberry Pi OS ARM64
RHEL family CentOS · Rocky · AlmaLinux · Fedora
Arch Linux
openSUSE Leap · Tumbleweed

Detected from /etc/os-release, falling back to ID_LIKE for derivatives. If detection fails you get a manual picker — the install never silently guesses wrong.

Minimum: 2 GB RAM and 20 GB disk for the core. Individual services ask for more; the heavy ones say so before they start. A GPU is optional and only relevant to AI.


🛠️ Managing and updating

Every service is a normal Compose project:

cd ~/docker/<service>
docker compose ps          # status
docker compose logs -f     # follow logs
docker compose restart
docker compose pull && docker compose up -d    # update

To reconfigure, rerun its deploy.sh — it reuses what exists. To remove one, use the picker's Remove, which offers to keep or wipe the data and tells you the truth about what it could not delete.

See docs/updating.md before updating anything that holds a database.


📖 Documentation

docs/troubleshooting.md The failures that actually happen — 502s, certificate errors, proxy misconfiguration
docs/cloudflare-tunnel.md Reaching services with no public IP and no port forwarding
docs/updating.md Updating images without losing data
services/<category>/README.md What each category is for, and how its services differ
services/<category>/<service>/README.md Per-service detail, gotchas, and manual steps

🔬 How this project is built

Worth stating, because it explains why the documentation reads the way it does.

Every service here was deployed on a real server before it was committed. Not built from upstream's README and assumed to work — actually run, actually broken, actually fixed. The gap between the two is large and it is where most of this repository's content comes from.

That produced a few habits worth knowing about as a reader:

The documentation records what failed. When a script printed a command that did not exist, or a warning that pointed the wrong way, the fix includes a note saying so. You will find sentences like "an earlier version of this file said the opposite" — those are deliberate. A correction with its reason attached does not get re-broken later.

Self-tests state their own limits. A deploy that ends with "self-test passed" also tells you what the test could not check. A green tick over an unverified claim is worse than no tick.

Numbers come from measurements. Where the documentation gives a figure — a memory cost, a context window, a timing — it was observed on a running system, and it says so.

Trade-offs are printed, not hidden. Where a choice has a real cost — mounting the Docker socket, publishing a port on an API with no authentication, joining a network that widens reach — the prompt names the cost before you answer.


📌 Status

41 of the 42 services are built and deployed on real hardware. The catalogue was closed at 41 on 2026-08-19, with Langflow finishing the Multi-Agent category. SearXNG was added on 2026-08-30 and deployed live the same day — both containers up, all three networks joined, and the JSON API answering 200. Its backup and restore have not yet been exercised, which is the one step still between it and the standard every other service here has met.

Categories, conventions and the shared library (lib/) are stable. Service scripts are added one at a time, each verified on real hardware before it lands.


📜 License

MIT — use it, fork it, change it.

🙌 Author

Ibrahim Aljuhani@IbrahimAljuhani

Issues and pull requests welcome. If you hit something this documentation got wrong, that is the most useful report there is.

About

Self-hosted service catalogue for Linux servers. One script installs Docker, NGINX Proxy Manager and Portainer; a menu deploys 41 services across 15 categories — AI, agents, ERP, storage, VPN, media and more. Each with a proxy route, a backup path, and docs from actually running it. Debian · Ubuntu · RHEL · Arch · openSUSE, x86_64 & ARM64.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages