From simple to "the real thing". Pick the method that matches your goal: showing one person quickly is one thing; putting it on the internet forever is another. Commands verified against official docs (GitHub Pages, MDN PWA).
🧭 The big picture
What you end up with: a link to your site/app that you can send to anyone — and, at the top end, a site that installs on a phone like a real app (icon, offline).
The main choice is driven by the goal. There's no "best" method, only a fitting one:
- Show a colleague on the same Wi-Fi right now → locally (1 minute).
- Put it on the internet forever and for free → GitHub Pages (or Netlify/Vercel).
- Quickly toss over a single file/snippet → gist.
- Distribute inside a messenger / make a mini app → Telegram.
- Make it installable and work offline → PWA.
⚠️ An important fork: static or backend? Pages/gist serve static files only (HTML/CSS/JS, a compiled React build). If you have server-side logic or a database — you need a real server (see the "Your own project on a server from scratch" guide).
Step 1. Locally — show it on your own network (1 minute)
What we're doing: starting a simple web server in the project folder and opening it from a phone on the same Wi-Fi via the computer's IP.
cd project/folder
python3 -m http.server 8000 # serve the current folder on port 8000
Find your computer's IP: macOS/Linux — ipconfig getifaddr en0 or ip addr; Windows — ipconfig. On your phone, open http://<computer-IP>:8000.
How to tell it worked: your page opens in the phone's browser (on the same network). In the computer's terminal you can see the request lines (GET ...).
Common mistakes:
- You opened
http://localhost:8000on the phone → doesn't work:localhoston the phone means the phone itself. You need the computer's IP. - It won't open from the phone — the computer's firewall/antivirus is in the way, or you're on different networks (guest Wi-Fi isolates devices).
python3: command not found— install Python (python.org) or usenpx serve(needs Node).💡 Need access from OUTSIDE for a couple of hours (a demo for a client who isn't on your network) — punch a tunnel through:
cloudflared tunnel --url http://localhost:8000orngrok http 8000→ you get a temporary public link with no server.
Step 2. GitHub Pages — free static hosting (forever)
What we're doing: publishing a static site/SPA (HTML/CSS/JS, including a compiled React build) for free.
- Push the project to a public GitHub repository (see the "Git in 15 minutes" guide).
- Repo → Settings → Pages → Source: branch
main, folder/ (root)(or/docs), Save. - About a minute later the site is live at
https://YOUR_USERNAME.github.io/repository-name/.
How to tell it worked: on Settings → Pages a banner appears — "Your site is live at …" — with a link; the link opens (HTTPS, padlock).
Common mistakes:
- Pages serves static files only — a backend/database won't work. Server-side logic needs a server.
- White screen for an SPA on a sub-path: assets are looked up from
/, but the site lives at/repo-name/. Fix it with a relative base (base: "./"in Vite, orhomepagein package.json for CRA). - 404 on SPA routes when you reload — Pages knows nothing about client-side routing. Add
404.html=index.html, or use HashRouter. - The repository is private → Pages may be unavailable on the free plan. Make it public.
💡 Alternatives that are just as free and friendlier to SPAs: Netlify, Cloudflare Pages, Vercel (auto-deploy from git, they sort out the paths for you).
Step 3. gist — quickly share a single file/snippet
What we're doing: sending code/HTML behind a link without setting up a repository.
- https://gist.github.com → paste the code/HTML → Create. You get a link and the option to fork it.
- A single HTML file can be rendered "as a page" through a raw-CDN service (something like githack) — handy for showing a mini demo.
How to tell it worked: the gist link opens and shows your code; through the githack wrapper the HTML renders as a page.
Common mistakes:
- You open "raw" HTML from github.com — it's shown as text, not rendered. You need a raw-CDN renderer (githack) or Pages.
- A secret gist — the link works, but the "secret" part is relative: whoever knows the URL can see it. Don't put anything sensitive there.
Step 4. Telegram — distribute inside the messenger
What we're doing: delivering the service straight into Telegram.
- A ready file (HTML/archive/APK) — just send it to a chat/channel: people download and open it.
- A Telegram Mini App — your web app (on HTTPS!) opens right inside Telegram: in @BotFather you create a bot → set its Web App URL (the link to your site from Step 2). The user taps the button and your app opens.
How to tell it worked: the file downloads and opens on the recipient's side; for a Mini App — the bot's button inside Telegram opens your site.
Common mistakes:
- The Mini App won't open — the URL is not HTTPS (Telegram requires HTTPS) or the site isn't publicly reachable. Publish it on Pages/Netlify first (that gives you HTTPS).
- Telegram compresses/blocks certain file types — send "as a file" (without compression); an APK is sometimes better sent as an archive.
Step 5. PWA — install the site as an app (an icon on the phone)
What we're doing: adding two things so the site installs "as an app" and works offline.
manifest.webmanifest(name, icons,display: standalone) and link it in<head>:
A minimal manifest:<link rel="manifest" href="/manifest.webmanifest">{ "name": "My service", "short_name": "Service", "start_url": "/", "display": "standalone", "icons": [{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }] }- A service worker (caches files for offline use) — register it in your code:
if ('serviceWorker' in navigator) navigator.serviceWorker.register('/sw.js');
How to tell it worked: the browser (Chrome on phone / desktop) shows an "Install app" button or menu item. In DevTools → Application → Manifest there are no errors, and the Service Worker is "activated".
Common mistakes:
- No HTTPS → the PWA won't install. PWAs require HTTPS (it works on
localhostfor testing). That's exactly why "GitHub Pages/Netlify (which gives you HTTPS) + PWA" is such a convenient combination. - Icons in the wrong sizes / a wrong path → no install button. You need at least 192×192 and 512×512, and the paths must actually open.
sw.jsisn't at the root → it doesn't control the scope you need. Put it at the top level of the site.
🧠 For the senior
- CI/CD on Pages: deploy static files via GitHub Actions (
actions/deploy-pages) from a branch/build artifact — cleaner than "a folder out of main"; custom domain + automatic HTTPS in the Pages settings. - SPA details: the correct
base/publicPathfor a sub-path, a404.htmlfallback for history routing, prefetching and bundle splitting; for Vercel/Netlify — rewrites toindex.html. - PWA done properly: generate the sw with Workbox (precache + runtime strategies), versioned cache +
skipWaiting/clients.claim, careful updates (otherwise users get stuck on an old cache — a very common bug). Get the Lighthouse PWA audit into the green. - Tunnels:
cloudflared/ngrokfor demos and webhooks; for something permanent — Cloudflare Tunnel as a named service. - Backend? If you need a server/database, that's a different track: container + reverse proxy + domain (see "Your own project on a server from scratch").
⚠️ Warnings
- A public repository = public code. Before pushing to GitHub Pages, make sure there are no secrets, keys, tokens or private data in the code or its history. A leaked key = a breach.
- A tunnel opens your machine to the internet.
ngrok/cloudflaredgive anyone with the link access to a local port. Don't keep a tunnel open longer than you need, and don't expose sensitive services. - PWA caches get stuck. A badly written service worker can permanently cache an old version for your users. Think through cache invalidation before you publish.
- Static only on Pages/gist. Don't try to hide a "secret" backend key in JS there — it's visible to everyone in the page source.
🆘 Rescue prompt
Help me publish my service, explain it step by step.
WHAT I HAVE: <a static site / a React SPA / a single HTML file / a backend and a database>.
GOAL: <show it on the local network / publish it for free forever / open it in Telegram / make it an installable PWA>.
MY OS: <macOS / Windows>. I'M STUCK ON: <what doesn't work / the error text / a white screen>.
What to do:
1) Recommend the best method for my goal (static vs. needs a server).
2) Walk me through it step by step, give me the commands/files (manifest, sw.js, Pages settings, BotFather).
3) How to check it opens from a phone (and installs as a PWA, if needed).
4) Warn me about secrets in a public repo and about the HTTPS requirement.
💎 Depth and value
- "Done on my machine" ≠ "people have it". As long as the project only lives on your computer, it effectively doesn't exist. Being able to hand over a link turns a side project into a product people actually use.
- A ladder, not a single step. The very same project can be shown in a minute (local network), published forever (Pages), embedded in a messenger (Telegram) and installed on a phone (PWA) — you pick the level to match the situation without rebuilding anything.
- Free all the way to the top. GitHub Pages + PWA give you "a real app with an icon and HTTPS" for 0 ₽. That removes the last excuse — "I have nothing to host it on" — and leaves no barrier between the idea and its users.