> For the complete documentation index, see [llms.txt](https://docs.haikaldev.my.id/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.haikaldev.my.id/coding-and-hosting/hosting-website.md).

# Hosting Website

*"Bikinin website"* di AI-Haikaru tidak berhenti di berkas — **berakhir di URL yang bisa dibuka siapa pun**.

## Alur utama — satu kalimat

```
Kamu : bikinin aku website portofolio yang keren, terus hostingin
Bot  : [create workspace] → [write index.html + style.css + script.js]
       → [publish] → "Udah tayang! 🌐 https://proj.haikaldev.my.id/site/masbro/portofolio/"
```

Setelah tayang:

* **Edit lewat chat** → *"ganti warnanya jadi gelap"* → refresh browser → berubah. **Tidak perlu publish ulang.**
* *"turunin website-nya"* → `unpublish` → link jadi 404. Berkas tetap utuh; publish lagi kapan saja.
* `/ws publish`, `/ws unpublish`, `/ws link` — jalur cepat tanpa AI.

## Tayang itu opt-in

{% hint style="danger" %}
Workspace **tidak otomatis** jadi website. Janji workspace pribadi adalah *"hanya pemilik yang bisa membaca"* — kalau tiap workspace langsung bisa dibuka lewat URL, janji itu batal diam-diam.

Maka: hanya `publish`, oleh yang berhak menulis, yang menayangkan. Sebelum itu `/site/<id>/` menjawab **404 yang identik** dengan workspace yang tidak pernah ada — orang luar bahkan tidak bisa tahu proyeknya eksis.
{% endhint %}

Dan sekali tayang: **siapa pun yang tahu link-nya bisa membuka**. Bot menyebutkan ini saat mengirim link. Jangan taruh data pribadi di situs yang tayang.

## URL cantik ala GitHub Pages

Alamat bawaan berbentuk ID acak: `/site/k3n8x2mQ7pLd/`. Bisa diganti jadi milikmu:

```
Kamu : aku mau dipanggil masbro
Bot  : [tawaran] mau sekalian klaim username "masbro"?
       nanti alamat semua situsmu jadi /site/masbro/<proyek>/
Kamu : boleh!
Bot  : [username masbro diklaim]
```

Aturannya persis GitHub Pages:

| Alamat                     | Isi                                                                |
| -------------------------- | ------------------------------------------------------------------ |
| `/site/masbro/portofolio/` | workspace "portofolio" milik masbro                                |
| `/site/masbro/`            | workspace yang **bernama "masbro"** → halaman utama pribadi        |
| `/site/k3n8x2mQ7pLd/`      | bentuk ID — **tetap hidup selamanya**, link lama tidak pernah mati |

Ketentuan username: minimal 3 karakter (huruf/angka/strip), satu orang satu nama, tidak bisa merebut milik orang lain, dan kata sistem (`site`, `api`, `config`, …) ditolak. Ganti username = nama lama terlepas dan bisa diambil orang lain.

{% hint style="warning" %}
**Rename workspace yang sedang tayang mengubah alamatnya** — nama adalah bagian dari URL. Bot selalu mengirim link baru setelah rename: link bentuk-nama yang lama mati, **bentuk-ID tetap jalan**.
{% endhint %}

## Foto & media dari chat ke website

Media yang sudah ada di percakapan bisa langsung jadi aset situs lewat action `attach`:

```
[kirim foto]  "pakai ini buat hero section-nya"
[reply foto]  "masukin ke galeri, namain img/kucing.jpg"
              "pakai foto profil grup buat halaman utamanya"
```

Atau manual: reply medianya → `/ws attach img/hero.jpg`

Detail perilaku yang menyelamatkanmu dari sesore debugging:

{% hint style="success" %}

* **Byte disimpan utuh** — bukan lewat konversi string yang merusak biner
* **Ekstensi dikoreksi otomatis** dari isi sebenarnya. Foto WhatsApp sering WebP walau kamu menyebutnya `.png`; nama berkasnya disesuaikan **dan bot memberitahumu**
* Sumber dicoba berurutan: media di pesan ini → di pesan yang di-reply → media terakhir di chat (termasuk gambar yang barusan dibuat bot)
* **Foto profil grup hanya diambil kalau diminta eksplisit** — tidak pernah ikut tebakan otomatis
* Batas media 8 MB per berkas
  {% endhint %}

Format yang dilayani situs: HTML/CSS/JS, gambar (PNG/JPG/WebP/GIF/SVG/AVIF/ICO), font (WOFF/WOFF2/TTF/OTF), audio (MP3/WAV/OGG/Opus/M4A), video (MP4/WebM), PDF, JSON/XML/CSV, sampai model 3D (OBJ/MTL/GLB/glTF).

## React & situs tanpa build step

Situs yang ditulis bot berjalan **tanpa build**: HTML/CSS/JS biasa, atau React langsung di browser.

```html
<script type="module">
  import React from 'https://esm.sh/react@18';
  import { createRoot } from 'https://esm.sh/react-dom@18/client';
  ...
</script>
```

{% hint style="info" %}
Kalau suatu hari ada folder `dist/` (hasil build) berisi `index.html`, situs **otomatis menyajikan `dist/`** alih-alih akar workspace — fondasi untuk dukungan Vite yang direncanakan.
{% endhint %}

### Batasan halaman yang tayang

Halaman disajikan **ter-sandbox**. Alasan keamanannya di [Keamanan](/referensi/keamanan.md):

|   | Perilaku                                                                                                               |
| - | ---------------------------------------------------------------------------------------------------------------------- |
| ✅ | JavaScript situsmu sendiri jalan normal, termasuk module & import dari esm.sh                                          |
| ❌ | `localStorage` / `sessionStorage` / cookie **tidak bisa dipakai** — state hidup di variabel JS dan hilang saat refresh |
| ❌ | Situs tidak bisa membaca API bot (`/api/status` dsb.) — memang itu tujuannya                                           |

Bot sudah tahu batasan ini dan **tidak akan menulis kode yang menyentuhnya**.

## Domain & port sendiri

{% tabs %}
{% tab title="Menumpang port utama" %}

```
http://host:PORT/site/<username>/<proyek>/
```

Nol konfigurasi — langsung jalan begitu bot hidup.
{% endtab %}

{% tab title="Port khusus situs" %}
Set `SITE_PORT` di `.env`, lalu arahkan domain publik (mis. `proj.haikaldev.my.id`) ke port itu lewat reverse proxy.

Yang mendengarkan di sana adalah **app terpisah yang hanya tahu situs** — `/config` dan QR login **tidak ikut** ke domain publik.

Bonus: alamat bisa tanpa awalan `/site` → `proj.haikaldev.my.id/masbro/`

Panduan reverse proxy + Cloudflare: [Deploy di Pterodactyl](/tentang/deploy-pterodactyl.md).
{% endtab %}
{% endtabs %}

`PUBLIC_BASE_URL` menentukan bentuk link yang dikirim bot.

## Terkait

* Fondasinya: [Workspace Coding](/coding-and-hosting/workspace.md)
* Kenapa sandbox & 404-nya seragam: [Keamanan](/referensi/keamanan.md)
* *"Situs putih polos"* / *"502"*: [Troubleshooting](/referensi/troubleshooting.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.haikaldev.my.id/coding-and-hosting/hosting-website.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
