Repository navigation
Getting Started
Generated from
docs/GETTING-STARTED.mdin the repository. Edit it there; this wiki is rebuilt on every change.
Four ways to run EdgeShell: local development, Docker, the production Docker
stack, and a production host (EC2 or bare metal) with run.py.
python run.py --dev # on Windows and macOS --dev is the defaultrun.py bootstraps a venv, installs dependencies, generates a .env with
random keys if missing, and starts the dev server. Default login is
admin / admin123. The first sign-in sets up two-factor authentication (any
authenticator app; save the backup codes), a new password and a personal
email.
Development uses a dev-only fallback for secrets so you can start instantly. Production does not (see below).
cp .env.example .env
python -c "import secrets; print('SECRET_KEY=' + secrets.token_hex(32))"
python -c "import secrets; print('CREDENTIAL_KEY=' + secrets.token_hex(32))"
# paste both into .env, then:
docker compose up -d # pulls devprincekumar/edgeshell (amd64 or arm64)- App is served on
http://<host>:5000, health at/healthz. - Data persists in named volumes
edgeshell_instanceandedgeshell_uploads. - SQLite and plain HTTP: good for trying it out. For production use section 3 or 4.
- Networking to reach nodes over the mesh is covered in VPN-NETWORK.md.
docker/compose.yaml runs EdgeShell, MariaDB 11.4
(internal network only), privacyIDEA for 2FA, and nginx as the only public
entry point, with certbot for Let's Encrypt once a domain is set. All state
lives in ./data on the host and only ports 80 and 443 are exposed.
Step-by-step instructions, backups and upgrades are on the
Docker Hub page and in
docker/DOCKERHUB.md.
On Ubuntu 22.04, 24.04 or 26.04, or Debian 12, with Tailscale already up, a DNS record pointing at the host and ports 80 and 443 open:
git clone https://github.com/855princekumar/edgeshell.git
cd edgeshell
cp .env.example .env
nano .env # EDGESHELL_DOMAIN and LETSENCRYPT_EMAIL
python3 run.py # asks for sudo; re-run any time to updateOn Linux, run.py without --dev hands over to deploy/provision.py, which:
- Installs system packages: MariaDB, Nginx, PHP-FPM, phpMyAdmin, certbot, ufw.
- Creates the
edgeshellsystem user and copies the code to/opt/edgeshell(root-owned, read-only to the app). - Builds the virtualenv and generates
SECRET_KEYandCREDENTIAL_KEYif absent. - Secures MariaDB, creates the database and least-privilege users, and migrates an existing SQLite database once.
- Configures Nginx for your domain only, with a Let's Encrypt certificate and HSTS.
- Binds phpMyAdmin to the Tailscale IP only.
- Enables the host firewall (ufw): inbound only for your SSH port, 80, 443,
41641/udp and the Tailscale interface (
EDGESHELL_FIREWALL=offskips it). - Installs, enables and starts the systemd units, then checks health and audits every listening port.
| Unit | Role |
|---|---|
edgeshell.service |
Gunicorn on 127.0.0.1, Restart=always, starts on boot |
edgeshell-heartbeat.timer |
Posts a VPN status sample every minute |
edgeshell-watchdog.service |
Hits /healthz, restarts the app after 3 failures |
Users sign in at the domain; they do not need the mesh. The full guide, security group rules and troubleshooting are in DEPLOY-EC2.md.
- Change the admin password.
- Create per-person accounts with the right role (see RBAC.md).
- Configure the VPN backend in settings (Tailscale by default).
- Add nodes (single, or bulk via Import CSV).
- Run Test All, then Check OpenRemoteGUI, to confirm reachability.
If login fails with "CSRF session token is missing" when you open the app at
a LAN IP (like http://10.x.x.x:5000) but works at http://localhost:5000, the
cause is the secure session cookie. Production marks the cookie Secure
(HTTPS-only). Browsers accept it on localhost even over HTTP, but drop it on a
LAN IP over plain HTTP, so no session is stored and the CSRF token goes missing.
| Situation | Setting |
|---|---|
| Local or LAN testing over HTTP |
FLASK_ENV=development or SESSION_COOKIE_SECURE=false
|
| Production behind HTTPS (reverse proxy / ALB) |
FLASK_ENV=production and SESSION_COOKIE_SECURE=true
|
run.py --dev uses development, so LAN HTTP works out of the box. The
production installer sets SESSION_COOKIE_SECURE to match: true once the
certificate is issued, false while the host is served over plain HTTP.
Installed with run.py:
sudo mariadb-dump --single-transaction edgeshell | gzip > ~/edgeshell-$(date +%F).sql.gz
git pull && python3 run.py # update
git checkout <previous-tag> && python3 run.py # roll back the code
gunzip -c ~/edgeshell-YYYY-MM-DD.sql.gz | sudo mariadb edgeshell # and the dataDocker: change EDGESHELL_TAG in .env and run docker compose up -d.
deploy/update.sh and deploy/rollback.sh belong to the older
deploy/install.sh layout (releases recorded under releases/). They do not
apply to hosts installed with run.py.
Repository · Docker Hub · Report a security problem · MIT licence
Start
Deploy
- Deploy on AWS EC2
- Run on Any Cloud
- Configuration
- MQTT Heartbeat
- VPN and Network
- Database Migration
Use
How it is built
Project
Decision records