Skip to content

DarthVibe/Executarr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Executarr

Simple deployment and management dashbaord of *Arr or STARR media stack with a Go + React dashboard. Deploy on Debian/Ubuntu. Arch in development, use at own risk here. Feel free to make this better in your own repo. I have not tested with anything other than Mullvad Wireguard at this point.

NOTE: READ FIRST

This is a "vibe" coded project born from frustations born of building and reworking a compose.yml file for weeks to get services to run correctly. Top that with needing to watch logs for issues and trying to combine time frames to see what dropped where. So I created a dashboard to glance at running services first that allowed easy access to the service I wanted to access. From there, I wanted to change my VPN config easier. Then I wanted to stop, start, or restart services. Then came the log views. Finally, I asked Claude Opus 4.5 to help build a deployment and make it look pretty.

File structure is based off of TRASH Guides.

Known issues:

"Update All" seems to hang

Disk usage is reporting whole disk and not data directory

ProtonVPN Free WG configs not configuring properly on Gluetun

VPN NOTE

IPv6 will hang Gluetun, remove it before from WireGuard Address before saving or in your config files. In Mullvad, Generate Key -> Select Country and Server -> Advanced Settings -> Tunnel Traffic: IPv4 Only -> Download Zip. This will make sure it works from the start.

If it crashes:

sudo docker compose -f /opt/executarr/compose/docker-compose.yml restart gluetun

Quick Start

git clone https://github.com/darthvibe/Executarr
cd Executarr
chmod +x deploy.sh
sudo bash deploy.sh

That's it. The script detects your OS, installs dependencies, creates the restricted user, builds the directory structure, writes credentials, and starts the dashboard.


Architecture

┌─────────────────────────────────────────────────────┐
│                   Host Machine                       │
│                                                      │
│  ┌─────────────┐   ┌────────────────────────────── ┐ │
│  │  deploy.sh  │   │  /opt/executarr/              │ │
│  │  (root)     │   │  ├── compose/                 │ │
│  └─────────────┘   │  │   ├── docker-compose.yml   │ │
│         │          │  │   ├── gluetun.env  ← secret│ │
│         │          │  │   └── .env         ← secret│ │
│         ▼          │  ├── config/                  │ │
│  ┌─────────────┐   │  │   ├── dashboard.json←secret│ │
│  │ executarr   │   │  │   ├── ports.json           │ │
│  │ (sys user)  │   │  │   └── <service>/           │ │
│  │ no shell    │   │  └── logs/                    │ │
│  │ docker grp  │   └────────────────────────────── ┘ │
│  └─────────────┘                                     │
│                                                      │
│  /mnt/data/                                          │
│  ├── torrents/{books,movies,music,tv}                │
│  ├── usenet/incomplete                               │
│  ├── usenet/complete/{books,movies,music,tv}         │
│  └── media/{books,movies,music,tv}                   │
└─────────────────────────────────────────────────────┘

VPN Routing

The following services use network_mode: service:gluetun — all their traffic exits through the Gluetun tunnel:

  • Radarr, Sonarr, Jackett, FlareSolverr, qBittorrent, Dispatcharr

SABnzbd (Usenet) connects directly — Usenet is encrypted SSL by default.


Services & Ports

Service Default Port VPN Routed Web UI
Executarr 8081 No http://host:8081
Gluetun 8888 HTTP proxy (optional)
Radarr 7878 http://host:7878
Sonarr 8989 http://host:8989
Jackett 9117 http://host:9117
FlareSolverr 8191 http://host:8191
qBittorrent 8080 (web) http://host:8080
Dispatcharr 6969 No http://host:6969
SABnzbd 8090 No http://host:8090
Plex 32400 No http://host:32400/web
Emby 8096 No http://host:8096

Port conflicts are detected at dashboard startup and automatically reassigned. A warning banner appears in the UI.


Directory Structure

/mnt/data/                          ← configurable at deploy time
├── torrents/
│   ├── books/
│   ├── movies/
│   ├── music/
│   └── tv/
├── usenet/
│   ├── incomplete/
│   └── complete/
│       ├── books/
│       ├── movies/
│       ├── music/
│       └── tv/
└── media/
    ├── books/
    ├── movies/
    ├── music/
    └── tv/

All services mount /mnt/data as /data inside their containers, keeping paths consistent.


Security Model

System User (executarr)

  • Created as a system account with --system
  • Shell: /usr/sbin/nologin — cannot log in interactively
  • No password set — account is locked
  • Not in sudo, wheel, or admin groups — zero privilege escalation
  • Only group membership: docker — required to manage containers
  • File ownership: root:executarr with 2775 (setgid) permissions

Secrets

File Contains Permissions
compose/gluetun.env Mullvad WireGuard private key 640 (root:executarr)
compose/.env PUID/PGID/TZ 640 (root:executarr)
config/dashboard.json bcrypt password hash, session secret 640 (root:executarr)

None of these files are ever placed inside docker-compose.yml.

Dashboard Auth

  • Passwords stored as bcrypt hashes only (cost factor 12)
  • Sessions: 256-bit random tokens, stored in-memory, 8-hour TTL
  • Cookies: HttpOnly, SameSite=Strict
  • Security headers on all responses: X-Frame-Options: DENY, CSP, X-Content-Type-Options

Docker Socket

  • Mounted read-only (/var/run/docker.sock:ro) in the dashboard container
  • Lifecycle actions go through docker compose CLI (respects dependency ordering)

Plex vs Emby vs Jellyfin

Both are defined in docker-compose.yml but gated behind Compose profiles:

  • plex profile → starts Plex
  • emby profile → starts Emby
  • jellyfin profile → starts Jellyfin

The dashboard Media Server panel toggles between them. Only one can be active at a time.


File Layout

executarr/
├── deploy.sh                   ← One-click bootstrap (run as root)
├── .gitignore                  ← Protects secrets from git
├── README.md
│
├── dashboard/
│   ├── Dockerfile              ← Multi-stage: Node → Go → slim runtime
│   ├── go.mod
│   ├── cmd/server/
│   │   ├── main.go             ← Entry point, graceful shutdown
│   │   ├── config.go           ← Config loader, structured logger
│   │   ├── router.go           ← HTTP route wiring
│   │   └── handlers.go         ← Request handlers + middleware
│   ├── internal/
│   │   ├── auth/auth.go        ← bcrypt auth, session management
│   │   ├── compose/manager.go  ← docker compose CLI wrapper
│   │   ├── docker/client.go    ← Docker SDK: list services/status
│   │   ├── ports/ports.go      ← Port collision detection
│   │   └── system/monitor.go   ← Disk usage stats
│   └── web/
│       ├── embed.go            ← Go embed directive for React dist/
│       └── src/
│           ├── src/
│           │   ├── App.jsx               ← Router + auth context
│           │   ├── api.js                ← API client (all fetch calls)
│           │   ├── pages/
│           │   │   ├── LoginPage.jsx
│           │   │   └── DashboardPage.jsx
│           │   └── components/
│           │       ├── Header.jsx
│           │       ├── ServiceGrid.jsx   ← Service cards + start/stop/restart
│           │       ├── DiskPanel.jsx     ← Disk usage visualisation
│           │       ├── MediaServerPanel.jsx ← Plex/Emby selector
│           │       └── PortConflictBanner.jsx
│           └── index.html
│
├── compose/
│   ├── docker-compose.yml      ← All services (generated by deploy.sh)
│   ├── gluetun.env             ← VPN credentials (SECRET — never commit)
│   └── .env                    ← PUID/PGID/TZ (SECRET — never commit)
│
├── config/
│   ├── dashboard.json          ← Admin creds + session secret (SECRET)
│   └── ports.json              ← Port registry (auto-updated on conflict)
│
└── scripts/
    ├── create-user.sh          ← Restricted user creation
    └── hashpw.go               ← bcrypt hash utility (deploy-time only)

About

All in One Dashboard for STARR services

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages