Astro is a content-first web framework that ships zero JS by default. Tunnel it to share static sites, test SSR endpoints, or demo island components on real devices.
Quick Start
npm install -g mekong-cli
mekong auth YOUR_TOKEN# Terminal 1
npm run dev # Astro starts on http://localhost:4321
# Terminal 2
mekong 4321
# → https://happy-tiger-a1b2c3d4.mekongtunnel.devOr together:
npx concurrently "astro dev" "mekong 4321"package.json Scripts
{
"scripts": {
"dev": "astro dev",
"tunnel": "mekong 4321",
"dev:share": "concurrently \"astro dev\" \"mekong 4321\""
}
}Custom Port
// astro.config.mjs
import { defineConfig } from 'astro/config'
export default defineConfig({
server: { port: 3000 },
})mekong 3000Auto-Tunnel Integration
// astro.config.mjs
import { defineConfig } from 'astro/config'
import { createTunnel } from 'mekong-cli'
let tunnel
export default defineConfig({
integrations: [
{
name: 'mekong-tunnel',
hooks: {
'astro:server:start': async ({ address }) => {
const port = address.port
tunnel = await createTunnel({ port })
console.log(`\n ➜ Tunnel: ${tunnel.url}\n`)
},
'astro:server:done': async () => {
if (tunnel) await stopTunnel(tunnel.id)
},
},
},
],
})Astro SSR + API Endpoints
When using SSR mode (output: 'server'), Astro endpoints are reachable through the tunnel:
// src/pages/api/contact.ts
import type { APIRoute } from 'astro'
export const POST: APIRoute = async ({ request }) => {
const data = await request.json()
// Process contact form...
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json' },
})
}mekong 4321
# POST https://your-tunnel.mekongtunnel.dev/api/contactStatic Site Preview
Astro can generate fully static sites. Tunnel your dev server for a live preview:
# Static mode (default)
npm run dev
mekong 4321
# Share the URL — anyone can view your static siteOr build and preview the static output:
npm run build
npm run preview # Serves on localhost:4321
mekong 4321React / Vue / Svelte Islands
Astro supports UI framework islands. They work normally through the tunnel:
---
// src/pages/index.astro
import ReactCounter from '../components/ReactCounter.tsx'
import VueWidget from '../components/VueWidget.vue'
---
<h1>Astro Islands</h1>
<ReactCounter client:load />
<VueWidget client:idle />mekong 4321
# All islands hydrate correctly through the tunnelEnvironment Variables
# .env
PUBLIC_SITE_URL=https://happy-tiger-a1b2c3d4.mekongtunnel.dev
STRIPE_SECRET_KEY=sk_test_...// Access in .astro files
const siteUrl = import.meta.env.PUBLIC_SITE_URL
// Server-only env (SSR mode)
const stripeKey = import.meta.env.STRIPE_SECRET_KEYWebhook Endpoint (SSR)
// src/pages/webhooks/stripe.ts
import type { APIRoute } from 'astro'
import Stripe from 'stripe'
export const POST: APIRoute = async ({ request }) => {
const stripe = new Stripe(import.meta.env.STRIPE_SECRET_KEY)
const body = await request.text()
const sig = request.headers.get('stripe-signature')!
const event = stripe.webhooks.constructEvent(
body, sig, import.meta.env.STRIPE_WEBHOOK_SECRET
)
// handle event...
return new Response('OK')
}Adapters + Tunnel
Astro SSR requires an adapter. The tunnel works with all of them locally:
npm install @astrojs/node # Node.js adapter for local SSR// astro.config.mjs
import node from '@astrojs/node'
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
server: { port: 4321 },
})npm run dev
mekong 4321Tips
- Astro's dev server port is
4321by default (not3000or5173) - Content collections and MDX work normally through the tunnel
- For static output (
output: 'static'), no server-side code runs — the tunnel serves HTML/CSS/JS files as-is