Switch from localtunnel to cloudflared, fix static file serving

- Replace localtunnel with cloudflared (no interstitial password page)
- Wait for "Registered tunnel connection" before starting bot
- Serve index.html at / instead of directory listing
- Remove localtunnel npm package build from flake.nix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Danny 2026-03-24 20:35:05 +01:00
parent f025e5fd19
commit f2cfe72d63
3 changed files with 20 additions and 22 deletions

View file

@ -19,22 +19,10 @@
aiohttp aiohttp
]); ]);
localtunnel = pkgs.buildNpmPackage {
pname = "localtunnel";
version = "2.0.2";
src = pkgs.fetchFromGitHub {
owner = "localtunnel";
repo = "localtunnel";
rev = "v2.0.2";
hash = "sha256-6gEK1VjF25Kbe2drxbxUKDNJGqZ+OXgkulPkAkMR2+k=";
};
npmDepsHash = "sha256-R9FYkEe93oGF+dR7i1MxwzEW3EM3SasH/B6LLC2CNXM=";
dontNpmBuild = true;
};
in in
{ {
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
packages = [ pythonEnv localtunnel ]; packages = [ pythonEnv pkgs.cloudflared ];
shellHook = '' shellHook = ''
echo "💪 BigBiggerBiggestBot dev shell" echo "💪 BigBiggerBiggestBot dev shell"
echo " Run: python start.py (server + tunnel + bot)" echo " Run: python start.py (server + tunnel + bot)"
@ -46,7 +34,7 @@
apps.default = { apps.default = {
type = "app"; type = "app";
program = toString (pkgs.writeShellScript "run-fitness-bot" '' program = toString (pkgs.writeShellScript "run-fitness-bot" ''
export PATH="${pkgs.lib.makeBinPath [ pythonEnv localtunnel ]}:$PATH" export PATH="${pkgs.lib.makeBinPath [ pythonEnv pkgs.cloudflared ]}:$PATH"
exec ${pythonEnv}/bin/python "$PWD/start.py" exec ${pythonEnv}/bin/python "$PWD/start.py"
''); '');
}; };

View file

@ -202,7 +202,12 @@ def create_app() -> web.Application:
# Serve the webapp/ folder # Serve the webapp/ folder
import pathlib import pathlib
webapp_dir = pathlib.Path(__file__).parent / "webapp" webapp_dir = pathlib.Path(__file__).parent / "webapp"
app.router.add_static("/", webapp_dir, show_index=True)
async def index_handler(request):
return web.FileResponse(webapp_dir / "index.html")
app.router.add_get("/", index_handler)
app.router.add_static("/", webapp_dir)
return app return app

View file

@ -62,13 +62,14 @@ def start_server(port: int, bot_token: str) -> subprocess.Popen:
def start_tunnel(port: int) -> tuple[subprocess.Popen, str]: def start_tunnel(port: int) -> tuple[subprocess.Popen, str]:
print(f" Starting tunnel to port {port}...") print(f" Starting tunnel to port {port}...")
proc = subprocess.Popen( proc = subprocess.Popen(
["lt", "--port", str(port)], ["cloudflared", "tunnel", "--url", f"http://localhost:{port}"],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
text=True, text=True,
) )
url = None url = None
connected = False
deadline = time.time() + 30 deadline = time.time() + 30
while time.time() < deadline: while time.time() < deadline:
line = proc.stdout.readline() line = proc.stdout.readline()
@ -78,16 +79,20 @@ def start_tunnel(port: int) -> tuple[subprocess.Popen, str]:
break break
continue continue
line = line.strip() line = line.strip()
print(f" [tunnel] {line}") if line:
match = re.search(r"https?://\S+", line) print(f" [tunnel] {line}")
if match: if not url:
url = match.group(0) match = re.search(r"https://\S+\.trycloudflare\.com", line)
if match:
url = match.group(0)
if "Registered tunnel connection" in line:
connected = True
break break
if not url: if not url or not connected:
proc.kill() proc.kill()
print("\n Could not get a tunnel URL.") print("\n Could not get a tunnel URL.")
print(" Make sure localtunnel is working: lt --port 8080\n") print(" Make sure cloudflared is installed: cloudflared tunnel --url http://localhost:8080\n")
sys.exit(1) sys.exit(1)
return proc, url return proc, url