Python Runner Web Template


Python Runner Web Template: Build Self-Hosted Python Tools on Your Website (No SaaS Required)

Meta Description (Yoast / RankMath):
Deploy Python tools directly on your website with Python Runner Web Template. Run scripts, generate PDFs, automate workflows, and stay fully self-hosted.


Introduction: Python Tools Belong on Your Website

Most online tools today force creators into a difficult tradeoff:

  • Convenience vs ownership
  • Speed vs control
  • Cloud access vs long-term reliability

The Python Runner Web Template was built to end that tradeoff.

This template allows you to deploy real Python-powered tools directly on your website, without depending on third-party SaaS platforms, expiring dashboards, or external APIs you don’t control.

If you’ve ever wanted to:

  • run Python scripts from a browser
  • generate PDFs or reports for users
  • build internal tools or paid utilities
  • host AI-assisted workflows on your own domain

…this template was built specifically for that purpose.


🌐 What Is the Python Runner Web Template?

The Python Runner Web Template is a ready-to-deploy web interface that connects frontend UI elements (buttons, forms, inputs) to backend Python scripts running on your server.

In short:

It turns Python scripts into web tools.

No frameworks required.
No SaaS dependency.
No forced subscriptions.

You upload it to your hosting, connect scripts, and it works.


⚙️ Core Features

  • 🌐 Browser-based Python execution
  • 🧩 Modular script architecture
  • 📄 PDF & HTML generation via web UI
  • 🖥️ Works on shared hosting (cPanel-friendly)
  • 🔐 No exposed API keys
  • 📂 Clean separation of frontend and scripts
  • 🧠 AI-ready (bring your own logic)

🧠 Why the Web Template Was Built

After building Python Runner (Local), one thing became clear:

People wanted the same power — but accessible through a website.

However, existing solutions had major problems:

  • cloud lock-in
  • usage limits
  • forced subscriptions
  • complex DevOps stacks

The Python Runner Web Template was built to solve this with:

  • simple PHP + Python integration
  • zero vendor lock-in
  • full control over execution and outputs

It’s ideal for creators who want to sell tools, not just scripts.


🖥️ How the Python Runner Web Template Works

At a high level:

  1. User visits a web page
  2. User clicks a button or submits a form
  3. The template triggers a Python script on the server
  4. Python generates output (PDF, HTML, text, data)
  5. The result is returned to the browser or saved

This allows you to create:

  • report generators
  • document builders
  • calculators
  • AI-powered analysis tools
  • internal dashboards

All hosted on your own domain.


📂 Web Template Folder Structure

The template uses a clean, scalable layout:

python-runner-web/
│
├── index.html
├── run.php
├── scripts/
│   ├── generate_pdf.py
│   ├── analyze_data.py
│   └── ai_report.py
│
├── output/
│   ├── pdf/
│   ├── html/
│   └── logs/
│
└── assets/
    ├── css/
    └── js/

This structure makes it easy to:

  • add new tools
  • reuse scripts
  • expand into full apps
  • integrate with member systems

🧩 Web Installation (cPanel / Hosting)

Requirements

  • cPanel or similar hosting
  • Python enabled (most hosts support it)
  • PHP (standard on cPanel)

Installation Steps

  1. Upload the ZIP file to your web directory
    Example: public_html/python-runner-web/
  2. Unzip via File Manager
  3. Set folder permissions: scripts/ → 755 output/ → 755
  4. Open in browser: https://yourdomain.com/python-runner-web/

No database required.
No cron jobs required.
No special server configuration needed.


📄 Generating PDFs, HTML & User Downloads

One of the strongest use cases of the web template is on-demand document generation.

You can build tools that:

  • generate PDFs instantly
  • export HTML reports
  • create structured documents
  • save files per user request

Examples:

  • credit repair letters
  • legal notices
  • sales summaries
  • AI-generated documents
  • educational worksheets

Unlike cloud platforms, files never expire unless you choose to remove them.


🤖 AI-Assisted Web Tools (Without API Exposure)

The Python Runner Web Template is AI-ready, meaning:

  • You can integrate AI logic inside Python
  • API keys stay server-side
  • No client-side exposure
  • No per-request SaaS fees

This is ideal for:

  • AI summarization tools
  • content generators
  • data analysis
  • custom automation

You control:

  • prompts
  • models
  • limits
  • output format

🔒 Security & Ownership Advantages

Cloud-based tools typically:

  • log user behavior
  • limit usage
  • revoke access
  • lock data behind accounts

Python Runner Web Template does none of that.

✔ Scripts live on your server
✔ Users interact with your UI
✔ Files remain accessible
✔ You decide how long data exists

This makes it suitable for:

  • legal tools
  • private business utilities
  • internal dashboards
  • paid member tools

👥 Who Should Use the Web Template?

This template is ideal for:

  • Developers building web-based utilities
  • Entrepreneurs selling downloadable tools
  • Agencies creating client dashboards
  • Educators hosting interactive tools
  • Anyone tired of SaaS dependency

If you already use Python Runner (Local), the web template is the natural next step.


🔁 Python Runner Local vs Web Template

FeatureLocalWeb Template
Offline use
Browser-based
Self-hosted
Sell as tool⚠️
User interaction

Many users choose both, which is why the Python Runner Bundle exists.


🔗 How It Fits the Studio1Live Ecosystem

The Python Runner Web Template powers tools like:

  • JD Sales GEN (report automation)
  • AI Web Build Kit (site generators)
  • Credit Repair Tools
  • Internal Admin Dashboards

It’s not a one-off script — it’s infrastructure.


👉 Download Python Runner Web Template

If you want to:

  • run Python from the browser
  • build sellable web tools
  • stay fully self-hosted
  • avoid SaaS lock-in

This template was built for you.

🔗 Download Python Runner Web Template:
👉 https://fixyourowncredit.studio1live.com/downloads/downloads/python-runner-web-template/

🔗 View All Studio1Live Templates:
👉 https://studio1live.com/templates/


Final Thought

The Python Runner Web Template gives you something most platforms don’t:

Freedom to build tools that last.

No subscriptions.
No platform risk.
Just tools that work — on your site.

How to build this on your own. You can purchase it and resell if you like. Follows the code instructions below.

Option 1) Flask app via cPanel “Setup Python App” (clean + safe)

Folder layout

/home/<USER>/python/py_build/
  app.py
  requirements.txt
  scripts/            ← uploaded .py files will live here
  uploads/            ← temp upload area (auto-created)
/home/<USER>/python/py_build/venv/   ← created by cPanel or you

requirements.txt

Flask==3.0.0

app.py (single file, ready to paste)

import os, re, subprocess, shlex, time
from pathlib import Path
from flask import Flask, request, redirect, url_for, render_template_string, flash, send_from_directory

# --- CONFIG ---
BASE_DIR = Path(__file__).resolve().parent
SCRIPTS_DIR = BASE_DIR / "scripts"
UPLOADS_DIR = BASE_DIR / "uploads"
PYTHON_BIN = os.environ.get("PY_BUILD_PYTHON", sys.executable) if 'sys' in globals() else "python3"
TIMEOUT_SECONDS = 20
MAX_OUTPUT_BYTES = 200_000  # ~200 KB

SCRIPTS_DIR.mkdir(exist_ok=True)
UPLOADS_DIR.mkdir(exist_ok=True)

ALLOWED = re.compile(r"^[A-Za-z0-9_\-\.]+\.py$")  # only .py, no subpaths

app = Flask(__name__)
app.secret_key = os.environ.get("PY_BUILD_SECRET", "change-me-please")

HTML = """
<!doctype html>
<title>Studio1Live — Python Builder</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
 body{font-family:system-ui,Segoe UI,Arial,sans-serif;padding:20px;max-width:900px;margin:auto;}
 h1{font-size:1.4rem;margin:0 0 12px}
 .row{display:flex;gap:16px;flex-wrap:wrap}
 form, .card{border:1px solid #ddd;border-radius:12px;padding:16px}
 .list{flex:1 1 420px}
 .runout{white-space:pre-wrap;background:#111;color:#eee;padding:12px;border-radius:12px;overflow:auto;max-height:400px}
 button{cursor:pointer;border:1px solid #333;border-radius:10px;padding:8px 14px;background:#111;color:#fff}
 input[type=file]{display:block;margin:8px 0}
 .muted{color:#666}
 .name{font-weight:600}
 .actions{display:flex;gap:8px}
</style>
<h1>Studio1Live — Python Runner</h1>

<div class="row">
  <form method="post" enctype="multipart/form-data" action="{{ url_for('upload') }}">
    <div><b>Upload a .py file</b></div>
    <input type="file" name="file" accept=".py" required>
    <button>Upload</button>
    <div class="muted">Files are stored in <code>scripts/</code>. Only .py allowed.</div>
  </form>

  <div class="list">
    <div class="card">
      <b>Available scripts</b>
      <ul>
      {% for f in files %}
        <li>
          <span class="name">{{ f }}</span>
          <div class="actions">
            <form method="post" action="{{ url_for('run_script') }}" style="display:inline">
              <input type="hidden" name="filename" value="{{ f }}">
              <button>Run</button>
            </form>
            <a href="{{ url_for('download_script', filename=f) }}">Download</a>
          </div>
        </li>
      {% else %}
        <li class="muted">No scripts yet. Upload above.</li>
      {% endfor %}
      </ul>
    </div>
  </div>
</div>

{% with messages = get_flashed_messages() %}
  {% if messages %}
    <div class="card" style="margin-top:16px">
      {% for m in messages %}
        <div>{{ m|safe }}</div>
      {% endfor %}
    </div>
  {% endif %}
{% endwith %}

{% if output %}
  <div class="card" style="margin-top:16px">
    <b>Output — {{ filename }}</b>
    <div class="runout">{{ output }}</div>
  </div>
{% endif %}
"""

def list_scripts():
    return sorted([p.name for p in SCRIPTS_DIR.glob("*.py") if ALLOWED.match(p.name)])

@app.route("/", methods=["GET"])
def home():
    return render_template_string(HTML, files=list_scripts(), output=None, filename=None)

@app.route("/upload", methods=["POST"])
def upload():
    file = request.files.get("file")
    if not file or not file.filename:
        flash("No file provided.")
        return redirect(url_for('home'))
    name = os.path.basename(file.filename)
    if not ALLOWED.match(name):
        flash("Invalid filename. Only .py allowed.")
        return redirect(url_for('home'))
    temp = UPLOADS_DIR / name
    file.save(temp)
    dest = SCRIPTS_DIR / name
    temp.replace(dest)
    flash(f"Uploaded <b>{name}</b> to scripts.")
    return redirect(url_for('home'))

@app.route("/download/<path:filename>")
def download_script(filename):
    if not ALLOWED.match(filename):
        return "Invalid filename", 400
    return send_from_directory(SCRIPTS_DIR, filename, as_attachment=True)

@app.route("/run", methods=["POST"])
def run_script():
    filename = request.form.get("filename","")
    if not ALLOWED.match(filename):
        flash("Invalid filename.")
        return redirect(url_for('home'))
    script_path = SCRIPTS_DIR / filename
    if not script_path.exists():
        flash("File not found.")
        return redirect(url_for('home'))

    # Run safely with timeout; no args; isolated cwd
    try:
        cmd = [PYTHON_BIN, str(script_path.name)]
        result = subprocess.run(
            cmd,
            cwd=SCRIPTS_DIR,
            capture_output=True,
            text=True,
            timeout=TIMEOUT_SECONDS
        )
        out = (result.stdout or "") + ("\n" + result.stderr if result.stderr else "")
        if len(out.encode("utf-8")) > MAX_OUTPUT_BYTES:
            out = out[:MAX_OUTPUT_BYTES] + "\n...\n[truncated]"
    except subprocess.TimeoutExpired:
        out = f"[Error] Timed out after {TIMEOUT_SECONDS}s."
    except Exception as e:
        out = f"[Error] {e}"

    return render_template_string(HTML, files=list_scripts(), output=out, filename=filename)

# cPanel WSGI entry point:
# In "Setup Python App", set:
#   Application startup file: app.py
#   Application entry point: app

cPanel steps

  1. Open Setup Python App → Create app (Python 3.9+), Application URL: /py_build on studio1live.com.
  2. Point App Directory to /home/<USER>/python/py_build.
  3. Startup file: app.pyEntry point: app.
  4. Click “Enter to virtual environment” → run: pip install -r /home/<USER>/python/py_build/requirements.txt
  5. Restart the app.
  6. Visit: https://studio1live.com/py_build
    • Upload .py files
    • Click Run next to any file

🔒 Security notes: this allows executing uploaded Python in your account. Keep it private or protect with HTTP Auth. The app enforces a 20s timeout and only allows .py names (no paths).


Option 2) One-file PHP page that calls Python (works on any cPanel)

If you don’t have “Setup Python App”, use PHP to run Python.

Folder layout

/home/<USER>/public_html/py_build/
  index.php
  scripts/          ← uploaded .py live here
  uploads/          ← temp

PHP page: public_html/py_build/index.php

<?php
// Simple Python runner (upload + list + run) via PHP.
// Set your python binary (venv recommended):
$PYTHON = '/usr/local/bin/python3'; // or '/home/<USER>/python/venv/bin/python'
$BASE = __DIR__;
$SCRIPTS = $BASE . '/scripts';
$UPLOADS = $BASE . '/uploads';
@mkdir($SCRIPTS, 0755, true);
@mkdir($UPLOADS, 0755, true);

function allowed($name) {
  return preg_match('/^[A-Za-z0-9_\-\.]+\.py$/', $name);
}

$msg = '';
$out = '';
$runFile = '';

if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_FILES['file'])) {
  if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
    $name = basename($_FILES['file']['name']);
    if (!allowed($name)) {
      $msg = "Invalid filename.";
    } else {
      $tmp = $UPLOADS . '/' . $name;
      move_uploaded_file($_FILES['file']['tmp_name'], $tmp);
      rename($tmp, $SCRIPTS . '/' . $name);
      $msg = "Uploaded <b>$name</b> to scripts.";
    }
  } else {
    $msg = "Upload error.";
  }
}

if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['run'])) {
  $runFile = basename($_POST['run']);
  if (allowed($runFile) && file_exists($SCRIPTS . '/' . $runFile)) {
    $cmd = escapeshellcmd($PYTHON) . ' ' . escapeshellarg($runFile);
    $descriptorspec = [
      0 => ["pipe", "r"],
      1 => ["pipe", "w"],
      2 => ["pipe", "w"]
    ];
    $proc = proc_open($cmd, $descriptorspec, $pipes, $SCRIPTS);
    if (is_resource($proc)) {
      fclose($pipes[0]);
      $stdout = stream_get_contents($pipes[1]); fclose($pipes[1]);
      $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]);
      $code = proc_close($proc);
      $out = $stdout . ($stderr ? "\n".$stderr : '');
      if (strlen($out) > 200000) $out = substr($out, 0, 200000) . "\n...\n[truncated]";
    } else {
      $out = "[Error] Could not execute.";
    }
  } else {
    $out = "Invalid file.";
  }
}

$files = array_values(array_filter(scandir($SCRIPTS), function($f){
  return allowed($f);
}));
?>
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Studio1Live — Python Runner</title>
<style>
 body{font-family:system-ui,Segoe UI,Arial,sans-serif;padding:20px;max-width:900px;margin:auto;}
 h1{font-size:1.4rem;margin:0 0 12px}
 .row{display:flex;gap:16px;flex-wrap:wrap}
 form, .card{border:1px solid #ddd;border-radius:12px;padding:16px}
 .list{flex:1 1 420px}
 .runout{white-space:pre-wrap;background:#111;color:#eee;padding:12px;border-radius:12px;overflow:auto;max-height:400px}
 button{cursor:pointer;border:1px solid #333;border-radius:10px;padding:8px 14px;background:#111;color:#fff}
 input[type=file]{display:block;margin:8px 0}
 .muted{color:#666}
 .name{font-weight:600}
 .actions{display:flex;gap:8px}
</style>
</head>
<body>
<h1>Studio1Live — Python Runner</h1>

<div class="row">
  <form method="post" enctype="multipart/form-data">
    <div><b>Upload a .py file</b></div>
    <input type="file" name="file" accept=".py" required>
    <button>Upload</button>
    <div class="muted">Saved to <code>scripts/</code>. Only .py allowed.</div>
  </form>

  <div class="list">
    <div class="card">
      <b>Available scripts</b>
      <ul>
        <?php if (!$files): ?>
          <li class="muted">No scripts yet. Upload above.</li>
        <?php else: foreach ($files as $f): ?>
          <li>
            <span class="name"><?=htmlspecialchars($f)?></span>
            <div class="actions">
              <form method="post" style="display:inline">
                <input type="hidden" name="run" value="<?=htmlspecialchars($f)?>">
                <button>Run</button>
              </form>
              <a href="<?= 'scripts/' . rawurlencode($f) ?>" download>Download</a>
            </div>
          </li>
        <?php endforeach; endif; ?>
      </ul>
    </div>
  </div>
</div>

<?php if ($msg): ?>
  <div class="card" style="margin-top:16px"><?=$msg?></div>
<?php endif; ?>

<?php if ($out): ?>
  <div class="card" style="margin-top:16px">
    <b>Output — <?=htmlspecialchars($runFile)?></b>
    <div class="runout"><?=htmlspecialchars($out)?></div>
  </div>
<?php endif; ?>

</body>
</html>

Set $PYTHON to your venv Python if you have one (e.g. /home/<USER>/python/venv/bin/python).
Then go to https://studio1live.com/py_build/ to use it.


Which one do I recommend?

  • If you have “Setup Python App” in cPanel → Flask (Option 1) is cleaner and isolates Python nicely.
  • If you don’t → the PHP page (Option 2) works everywhere and is literally drop-in.

Quick reminders

  • That python-3.13.1-amd64.exe is a Windows installer — not for cPanel Linux. Ignore it here.
  • Running arbitrary uploaded Python is powerful but risky. Keep the page private (restrict by IP or add a simple password) and never run untrusted code.
  • I set a 20-second timeout and output truncation to avoid runaway scripts.

If you tell me your real cPanel username (or just the last subfolder in your home path) I’ll pre-fill the absolute paths in the files so you can paste and go.

i was thinking to hide the upload folder, it can run only the files i upload on the server/file manager end ,

Thought for 8s

Great idea. Easiest, safest setup: no web uploads at all. You’ll place scripts using cPanel’s File Manager (or SFTP), and the web page will only list & run those server-side files.

Below are two minimal setups (Flask or PHP) with uploads removed and the scripts folder hidden outside public_html.


Folder layout (both options)

/home/<USER>/python/py_build/          ← app lives here (outside public_html)
/home/<USER>/python/py_build/scripts/  ← your private .py files (no web access)

/home/<USER>/public_html/py_build/     ← only the web endpoint lives here (if PHP option)
/home/<USER>/public_html/              ← public site files
  • Put your .py scripts into: /home/<USER>/python/py_build/scripts/
  • That folder is not web-reachable.
  • The UI will only list & run files found there.
  • You can further restrict access to the UI with Basic Auth (instructions below).

Option A — Flask app (cPanel » Setup Python App)

requirements.txt

Flask==3.0.0

app.py (no upload route; list+run only; token-protected run)

import os, re, subprocess
from pathlib import Path
from flask import Flask, request, render_template_string, redirect, url_for

# Adjust these
BASE_DIR = Path(__file__).resolve().parent
SCRIPTS_DIR = BASE_DIR / "scripts"  # OUTSIDE public_html
PYTHON_BIN = os.environ.get("PY_BUILD_PYTHON", "python3")  # or full path to your venv/bin/python
RUN_SECRET = os.environ.get("PY_BUILD_SECRET", "set-a-long-random-secret")
TIMEOUT_SECONDS = 20
MAX_OUTPUT_BYTES = 200_000

ALLOWED = re.compile(r"^[A-Za-z0-9_\-\.]+\.py$")

app = Flask(__name__)

HTML = """
<!doctype html><meta name=viewport content="width=device-width, initial-scale=1">
<title>Studio1Live — Python Runner</title>
<style>
 body{font-family:system-ui,Segoe UI,Arial,sans-serif;padding:20px;max-width:900px;margin:auto}
 .card{border:1px solid #ddd;border-radius:12px;padding:16px;margin:10px 0}
 button{cursor:pointer;border:1px solid #333;border-radius:10px;padding:8px 14px;background:#111;color:#fff}
 .runout{white-space:pre-wrap;background:#111;color:#eee;padding:12px;border-radius:12px;overflow:auto;max-height:420px}
 .muted{color:#666}
</style>
<h1>Studio1Live — Python Runner</h1>
<div class="card">
  <b>Available scripts (server-managed)</b>
  <form method="post" action="{{ url_for('run') }}">
    <select name="filename">
      {% for f in files %}<option value="{{f}}">{{f}}</option>{% endfor %}
      {% if not files %}<option>(none found)</option>{% endif %}
    </select>
    <input type="password" name="token" placeholder="Run token" required>
    <button>Run</button>
    <div class="muted">Scripts folder: {{ scripts_dir }}</div>
  </form>
</div>
{% if output is not none %}
  <div class="card">
    <b>Output — {{ filename }}</b>
    <div class="runout">{{ output }}</div>
  </div>
{% endif %}
"""

def list_scripts():
    SCRIPTS_DIR.mkdir(exist_ok=True)
    return sorted([p.name for p in SCRIPTS_DIR.glob("*.py") if ALLOWED.match(p.name)])

@app.get("/")
def home():
    return render_template_string(HTML, files=list_scripts(), output=None, filename=None, scripts_dir=str(SCRIPTS_DIR))

@app.post("/run")
def run():
    token = request.form.get("token","")
    if token != RUN_SECRET:
        return redirect(url_for("home"))

    name = request.form.get("filename","")
    if not ALLOWED.match(name):
        return render_template_string(HTML, files=list_scripts(), output="[Error] Invalid filename.", filename=name, scripts_dir=str(SCRIPTS_DIR))

    script_path = SCRIPTS_DIR / name
    if not script_path.exists():
        return render_template_string(HTML, files=list_scripts(), output="[Error] File not found.", filename=name, scripts_dir=str(SCRIPTS_DIR))

    try:
        result = subprocess.run([PYTHON_BIN, script_path.name], cwd=SCRIPTS_DIR, capture_output=True, text=True, timeout=TIMEOUT_SECONDS)
        output = (result.stdout or "") + ("\n"+result.stderr if result.stderr else "")
    except subprocess.TimeoutExpired:
        output = f"[Error] Timed out after {TIMEOUT_SECONDS}s."
    except Exception as e:
        output = f"[Error] {e}"

    if len(output.encode("utf-8")) > MAX_OUTPUT_BYTES:
        output = output[:MAX_OUTPUT_BYTES] + "\n...\n[truncated]"

    return render_template_string(HTML, files=list_scripts(), output=output, filename=name, scripts_dir=str(SCRIPTS_DIR))

# cPanel "Setup Python App":
#   App Directory: /home/<USER>/python/py_build
#   Startup file: app.py
#   Entry point: app
#   Environment variables (set in cPanel):
#     PY_BUILD_PYTHON = /home/<USER>/.venv/bin/python   (if using a venv)
#     PY_BUILD_SECRET = <long random token>

Steps:

  1. In cPanel → Setup Python App: create app (Python 3.9+), App Directory /home/<USER>/python/py_build.
  2. Set Startup file: app.py and Entry point: app.
  3. Click Enter to virtual environmentpip install Flask==3.0.0.
  4. Set two Environment Variables (in the app page):
    • PY_BUILD_SECRET = long random string (you type this to run scripts)
    • PY_BUILD_PYTHON = path to your desired Python (optional)
  5. Restart the app.
  6. Map URL to your app (cPanel usually does this). Visit: https://studio1live.com/py_build
  7. Place scripts in /home/<USER>/python/py_build/scripts/ via File Manager/SFTP.
  8. On the page: choose script → enter token → Run.

Option B — PHP page (no uploads, no public script access)

Folder: /home/<USER>/public_html/py_build/

index.php

<?php
// List+Run only. No uploads. Scripts live outside public_html.
$PYTHON = '/usr/local/bin/python3'; // or '/home/<USER>/python/venv/bin/python'
$SCRIPTS_DIR = '/home/<USER>/python/py_build/scripts';
$RUN_SECRET = 'set-a-long-random-secret';

function allowed($name){ return preg_match('/^[A-Za-z0-9_\-\.]+\.py$/', $name); }

$files = [];
if (is_dir($SCRIPTS_DIR)) {
  foreach (scandir($SCRIPTS_DIR) as $f) if (allowed($f)) $files[] = $f;
}
$out = ''; $runFile = '';

if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['filename'], $_POST['token'])) {
  if ($_POST['token'] !== $RUN_SECRET) {
    $out = "[Error] Unauthorized.";
  } else {
    $runFile = basename($_POST['filename']);
    if (allowed($runFile) && file_exists("$SCRIPTS_DIR/$runFile")) {
      $cmd = escapeshellcmd($PYTHON).' '.escapeshellarg($runFile);
      $desc = [0=>["pipe","r"],1=>["pipe","w"],2=>["pipe","w"]];
      $proc = proc_open($cmd, $desc, $pipes, $SCRIPTS_DIR);
      if (is_resource($proc)) {
        fclose($pipes[0]);
        $stdout = stream_get_contents($pipes[1]); fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]);
        $code = proc_close($proc);
        $out = $stdout . ($stderr ? "\n".$stderr : '');
        if (strlen($out) > 200000) $out = substr($out, 0, 200000)."\n...\n[truncated]";
      } else { $out = "[Error] Could not execute."; }
    } else { $out = "Invalid file."; }
  }
}
?>
<!doctype html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Studio1Live — Python Runner</title>
<style>
 body{font-family:system-ui,Segoe UI,Arial,sans-serif;padding:20px;max-width:900px;margin:auto}
 .card{border:1px solid #ddd;border-radius:12px;padding:16px;margin:10px 0}
 button{cursor:pointer;border:1px solid #333;border-radius:10px;padding:8px 14px;background:#111;color:#fff}
 .runout{white-space:pre-wrap;background:#111;color:#eee;padding:12px;border-radius:12px;overflow:auto;max-height:420px}
 .muted{color:#666}
</style>
<h1>Studio1Live — Python Runner</h1>
<div class="card">
  <form method="post">
    <label><b>Script</b>
      <select name="filename">
        <?php foreach ($files as $f): ?>
          <option value="<?=htmlspecialchars($f)?>"><?=htmlspecialchars($f)?></option>
        <?php endforeach; ?>
      </select>
    </label>
    <label> <b>Token</b>
      <input type="password" name="token" required>
    </label>
    <button>Run</button>
    <div class="muted">Scripts folder: <?=htmlspecialchars($SCRIPTS_DIR)?></div>
  </form>
</div>

<?php if ($out): ?>
  <div class="card">
    <b>Output — <?=htmlspecialchars($runFile)?></b>
    <div class="runout"><?=htmlspecialchars($out)?></div>
  </div>
<?php endif; ?>

What this does

  • Shows a dropdown of .py files in /home/<USER>/python/py_build/scripts/
  • Requires a token to run
  • Executes with a timeout inherited from PHP execution limits
  • No upload or download; everything stays private

Extra hardening (recommended)

  1. Basic Auth on /py_build (PHP option) or the Flask route.
    In /home/<USER>/public_html/py_build/.htaccess: AuthType Basic AuthName "Restricted" AuthUserFile /home/<USER>/.htpasswd Require valid-user Then create .htpasswd in your home dir with htpasswd or an online generator.
  2. Whitelist specific scripts: replace the dropdown with a hardcoded list of allowed filenames.
  3. Logging: append date + filename + exit code to a private log file in your home dir.
  4. Permissions: scripts/ should be owned by your user and set to 700 if you want to restrict even more.

Your workflow (no uploads over web)

  • Use cPanel File Manager or SFTP to put *.py into: /home/<USER>/python/py_build/scripts/
  • Go to:
    • Flask: https://studio1live.com/py_build
    • PHP: https://studio1live.com/py_build/
  • Choose a script → enter token → Run → see output.

Security

👍

Let’s clarify what’s happening and why I suggested the token:


🔍 What the token is for

The token isn’t about other files on your server — it’s about web access.

If someone knows (or guesses) that studio1live.com/py_build exists, and there’s a “Run” button that executes any .py file in /py_build/scripts, that person could:

  • Visit that page,
  • Pick one of your script names (which are listed),
  • Click “Run” — and your server would execute that code.

Even though they can’t upload new .py files, they could still run the existing ones if the page doesn’t require any kind of key, password, or token.

So:

  • The token (or password) simply makes sure only you can run code.
  • It’s not about hidden folders or blocking the file system — your /py_build/scripts/ folder is already secure (since it’s outside public_html).

✅ Simplest secure setup (what you want)

  • /home/<USER>/python/py_build/scripts/ → you upload .py files here via File Manager.
  • /home/<USER>/public_html/py_build/ → has your runner page (index.php or Flask app).
  • The page lists only those files, and only you can run them (via token or HTTP password).

You can protect it in one of three easy ways:

Option 1: Keep the token (easiest)

Only someone with the token can execute any file.

Think of it as a quick password check before running.

Option 2: Use cPanel password protection

Go to cPanel → Directory Privacy, find /public_html/py_build/, and add a username/password.
That’s classic .htaccess protection — no need for a token in the page.

Option 3: Hard-code allowed scripts

If you just need to run 2–3 known scripts, the page can skip the dropdown and have fixed “Run A / Run B” buttons — nobody can trigger others.


Leave a Reply

Your email address will not be published. Required fields are marked *