A lightweight self hosted remote control panel for your own Windows laptop. Runs quietly in the background (no console window), exposes a small web dashboard styled like a terminal, and tunnels it to the internet via ngrok so you can reach it from your phone.
Lock, sleep, shutdown/restart, adjust volume & brightness, sync the clipboard, pop up an on-screen message, take a live screenshot of your laptop screen directly on your mobile, or close an open window....all from your browser btw !
| Login | Dashboard |
|---|---|
![]() |
![]() |
| Features | Processes & Security |
|---|---|
![]() |
![]() |
- No console window — detaches on startup, runs via
waitress, logs to file - System tray icon — open dashboard, copy token, restart tunnel, exit
- Per-device sessions — log in once per device, revoke access per device
- Second password gate for extra-sensitive actions
- Every action is sandboxed — one failing feature (e.g. no battery, no
pycaw) never takes the rest of the app down
-
Put
laptop_controller.py,requirements.txt,setup.bat, andstartup_launcher.vbsin the same folder (e.g.,C:\pcpuppet). -
Double-click
setup.batonce — this installs all required Python packages automatically.Note: If you see a Windows SmartScreen warning, click "More info" and "Run anyway" — this is just because the script installs Python packages.
The setup script requires Python 3.8 or higher. If you don't have Python:
- Download Python from python.org
- During installation, make sure to check "Add Python to PATH"
- Restart your computer after installation
ngrok creates a public URL that tunnels to your local PC, so you can access it from anywhere (even on different networks like mobile data or public WiFi).
Option A: Using ngrok's Free Tier (Recommended)
-
Go to ngrok.com
-
Download
ngrok.exefor Windows -
Place
ngrok.exein one of these locations:- Easiest: Put it in the same folder as
laptop_controller.py - Or: Put it in
C:\Windows\System32\ - Or: Put it anywhere and set the
NGROK_PATHenvironment variable
- Easiest: Put it in the same folder as
-
Create a free ngrok account (required for persistent URLs):
- Go to ngrok.com/signup
- Sign up with email (free tier gives you 1 static domain)
- Copy your authtoken from the dashboard
-
Configure ngrok with your authtoken (one-time setup):
- Open Command Prompt as Administrator
- Navigate to where
ngrok.exeis located - Run:
ngrok config add-authtoken YOUR_AUTH_TOKEN_HERE - (Replace
YOUR_AUTH_TOKEN_HEREwith your actual token from ngrok dashboard)
-
Get your static domain (optional but recommended):
- In ngrok dashboard, go to "Cloud Edge" → "Domains"
- Claim a free static domain like
yourname.ngrok-free.app - This URL will stay the same every time you start the app
OR keep the free dynamic URL:
- Every time you start the app, ngrok generates a random URL
- You'll need to check the URL each time (via dashboard or logs)
Option B: Using a Pre-configured ngrok Path
If ngrok.exe is not in your PATH, set the NGROK_PATH environment variable:
- Press
Win + R, typesysdm.cpl, and go to "Advanced" → "Environment Variables" - Under "System variables", click "New"
- Variable name:
NGROK_PATH - Variable value: Full path to
ngrok.exe(e.g.,C:\Users\YourName\ngrok.exe) - Click OK and restart your computer
-
Double-click
startup_launcher.vbsto start the app.- No window appears — it runs silently in the background
- Look for the
>_icon in your system tray (bottom-right corner of screen)
-
Find your access token:
- Right-click the tray icon → "Copy Access Token"
- OR open
C:\Users\YourUsername\AppData\Local\LaptopController\controller.log - Look for the line:
Access token: YOUR_TOKEN_HERE
-
Open the dashboard:
- Right-click tray icon → "Open Dashboard"
- OR visit:
http://127.0.0.1:5000/?token=YOUR_TOKEN_HERE - (Replace
YOUR_TOKEN_HEREwith the token from step 2)
-
Get the public URL:
- In the dashboard, click the "show" button next to the URL
- OR check
controller.logfor the line:Public URL: https://xxxx.ngrok.io - OR right-click tray icon → "Open Dashboard" and check the URL at the top
-
On your phone:
- Open a browser (Chrome, Firefox, Safari)
- Enter the ngrok URL (e.g.,
https://yourname.ngrok-free.app) - Enter your access token on the login screen
- You're in! You can now control your PC from anywhere
- Press
Win + R - Type
shell:startupand press Enter - Create a shortcut to
startup_launcher.vbsin that folder - The app will now start automatically when you log in
If the app doesn't start or you can't access it locally:
- Windows may ask for firewall permission — click "Allow"
- If not, manually allow port 5000:
- Press
Win + R, typewf.msc(Windows Firewall) - Click "Inbound Rules" → "New Rule"
- Select "Port" → Next
- Enter
5000→ Next → "Allow the connection" - Name it "pcpuppet" → Finish
- Press
Everything generated at runtime — your token, session data, and logs —
lives outside the repo, in %LOCALAPPDATA%\LaptopController\:
| File | Contents |
|---|---|
config.json |
your access token + local security password |
sessions.json |
active device sessions |
controller.log |
full activity log, including your token on first run |
Just edit (or delete) config.json in %LOCALAPPDATA%\LaptopController\
and restart the app:
- Delete the file entirely → a brand new random token and password are generated on next launch.
- Edit
"token"or"security_password"directly → set your own values, save, restart.
The whole app is one file, organized in numbered sections
(# --- 1. Logging, # --- 2. Config, etc.), which makes it easy to find
where to plug something in. To add a new remote action:
- Add a case to
execute_command()(search forelif command ==) — this is wherelock,sleep,shutdown, etc. all live. Follow the same pattern: readparamfrom the request if you need input, do the thing, return ajsonify(...)response. - Add a button to
HTML_TEMPLATE— find the relevant.winpanel (or add a new one) and add a button callingsendCommand('your_command')from the<script>section. - Wrap anything that touches an optional dependency (like
sbcorgw) in the@safe(...)decorator, or checkif xyz is None:first — this keeps one broken feature from crashing the whole app on machines missing that dependency.
Need a new standalone endpoint instead? Add a new @app.route(...)
function next to the existing ones (/api/status, /api/apps, etc.) — auth
is handled globally by check_auth(), so any new route is protected
automatically unless you explicitly exempt it there.
Want a new optional dependency? Import it in a try/except block like
screen_brightness_control or pygetwindow are, set it to None on
failure, and add it to requirements.txt.
A few things that would slot into the existing structure without much rework:
- Change Windows password — a new branch in execute_command() for "change_password"
that runs
net user <username> <new_password>hidden (no console window, no shell exposure) so you can reset a Windows user's password from your phone. Requires admin privileges. - File browser / file transfer — a new
/api/filesroute usingos.listdir+send_fileto browse and download files from your PC, or upload files to it. Add a.winpanel with a folder list and an<input type="file">. - Webcam snapshot — same pattern as
take_screenshot_bytes(), but grabbing a frame fromcv2.VideoCapture(0)instead ofImageGrab.grab(). Handy as a "who's at my desk" check. - Run arbitrary shortcuts/scripts — a dropdown of pre-approved
.bat/.exepaths (don't accept freeform shell input from the client — keep it to a fixed whitelist you define server-side) so you can trigger things like "open VS Code" or "start backup script" remotely. - Battery/CPU alert push — a background thread that checks
psutil.sensors_battery()/psutil.cpu_percent()on a timer and, if a threshold is crossed, callsshow_popup_message()or pings a service like Pushover/ntfy so your phone gets notified without you opening the dashboard. - Scheduled actions — add a
schedule(pip package) job or a simple timer thread so you can queue "lock at 11pm" or "shutdown in 2 hours" from the dashboard, instead of only the fixed-t 5inexecute_command(). - Multi-factor for dangerous commands — require the
security_password(not just the session token) specifically forshutdown/restart, by checking it inside those branches ofexecute_command()— right now the second password only guards/api/security/unlock, not individual commands.
If you build one of these, it'll fit the same pattern described above: a
branch in execute_command() (or a new route) plus a button/panel in
HTML_TEMPLATE.
- This exposes real control over your PC to anyone with the token — treat the token like a password.
- The ngrok URL is public by default; anyone who has both the URL and the token can reach the dashboard. Revoke sessions you don't recognize from the dashboard, or regenerate the token if you suspect it's leaked.
- If
pystrayfails to load (missing tray icon support), the app still runs headless in the background — you just won't get a tray icon; use Task Manager to stop it (pythonw.exe), or add a stop mechanism of your choice. - Samajhne wale ko ishara ☕
See requirements.txt. Optional features degrade gracefully if a package
is missing — you'll just lose that one feature (e.g. no pycaw → no volume
control, falls back to media-key simulation).
MIT
Prasad




