Merancang Context Loading yang Efisien untuk AI Co...
Mengatasi 403 Forbidden Saat Deploy Next.js ke Hostinger dengan output: “standalone”
Ditulis oleh : adigarst, 30 Juli 2026

Saya baru saja mengalami masalah yang cukup membingungkan ketika mencoba melakukan deployment aplikasi Next.js ke Hostinger Web App Hosting.
Proses build berhasil. Tidak ada vulnerability. Dashboard Hostinger menunjukkan deployment telah selesai dan aplikasi berstatus Running.
Namun, ketika domain dibuka, halaman yang tampil justru:
403 Forbidden Access to this resource on the server is denied!
Hal yang membuat masalah ini semakin membingungkan adalah aplikasi berjalan normal di localhost. Halaman utama bisa dibuka, endpoint API bekerja, dan production build selesai tanpa error.
Setelah melakukan pemeriksaan satu per satu, ternyata masalahnya bukan pada domain, SSL, kode halaman, atau environment variables.
Masalahnya ada pada cara Next.js menghasilkan paket deployment.
Solusi yang akhirnya berhasil adalah menambahkan:
output: "standalone"
ke dalam konfigurasi Next.js.
Artikel ini menjelaskan proses diagnosisnya, alasan solusi tersebut bekerja, dan langkah-langkah yang bisa dicoba ketika mengalami masalah serupa.
Daftar isi
Gejala yang Terjadi
Berikut kondisi deployment pada saat masalah muncul:
- repository GitHub berhasil terhubung ke Hostinger,
- framework terdeteksi sebagai Next.js,
- proses
npm installberhasil, - proses
next buildberhasil, - tidak ada vulnerability dari
npm audit, - deployment berstatus Completed,
- aplikasi berstatus Running,
- domain dan SSL sudah aktif,
- tetapi halaman utama tetap menampilkan
403 Forbidden.
Build log terlihat normal:
Creating an optimized production build ... Compiled successfully Generating static pages ... Finalizing page optimization ... Route (app) ┌ ○ / ├ ○ /_not-found └ ƒ /api/health
Secara sekilas, tidak ada tanda bahwa deployment mengalami kegagalan.
Memastikan Aplikasi Berjalan di Localhost
Sebelum mengubah konfigurasi hosting, langkah pertama yang sebaiknya dilakukan adalah memastikan aplikasi memang dapat berjalan dalam mode production di komputer lokal.
Jalankan:
npm run build npm run start
Kemudian buka:
http://127.0.0.1:3000
Pada kasus saya, halaman utama berhasil ditampilkan.
Endpoint API juga bekerja:
http://127.0.0.1:3000/api/health
Respons yang diterima:
{
"status": "ok",
"runtime": "nextjs",
"timestamp": "2026-07-30T05:16:50.459Z"
}Hasil ini membuktikan bahwa:
- source code dapat dikompilasi,
- Next.js dapat dijalankan dalam mode production,
- halaman utama bekerja,
- route dinamis bekerja,
- masalah kemungkinan berada pada proses packaging atau runtime hosting.
Build Berhasil Belum Tentu Runtime Berhasil
Salah satu pelajaran penting dari masalah ini adalah:
Build yang berhasil tidak selalu berarti aplikasi server-side sudah memiliki runtime yang dapat menerima request.
Perintah berikut:
next build
memang menghasilkan folder .next.
Namun, folder .next pada konfigurasi default belum tentu menjadi paket deployment mandiri yang dapat langsung dijalankan oleh setiap platform hosting.
Pada banyak server, aplikasi Next.js default dijalankan menggunakan:
next start
Perintah tersebut masih mengandalkan struktur repository, package Next.js, dan dependency yang tersedia dalam environment server.
Hostinger menyediakan managed Web App Hosting yang menangani build, runtime Node.js, process management, routing, dan integrasi GitHub. Aplikasi Next.js yang menggunakan SSR, API route, atau fitur server-side memerlukan proses Node.js yang terus berjalan.
Memeriksa Struktur File Deployment
Langkah diagnosis berikutnya adalah membuka File Manager Hostinger.
Pada deployment yang bermasalah, struktur root hanya berisi:
.builds/ public_html/ DO_NOT_UPLOAD_HERE
Tidak ada folder:
nodejs/
Di dalam public_html, justru terdapat isi build .next, seperti:
public_html/ ├── server/ ├── static/ ├── cache/ ├── build-manifest.json ├── routes-manifest.json └── file build Next.js lainnya
File .htaccess yang tersedia juga tidak meneruskan request ke runtime Node.js.
Isinya hanya berupa perlindungan terhadap folder build:
RewriteRule ^\.builds - [F,L]
Artinya, Apache menerima request dari browser, tetapi tidak memiliki aplikasi Node.js yang menjadi tujuan request tersebut.
Hasilnya adalah 403 Forbidden.
Membandingkan dengan Deployment Next.js yang Berhasil
Untuk mencari perbedaannya, saya membandingkan struktur tersebut dengan aplikasi Next.js lain yang berhasil berjalan di akun Hostinger yang sama.
Deployment yang berhasil memiliki struktur:
.builds/ nodejs/ public_html/
Di dalam folder nodejs, terdapat:
nodejs/ ├── .next/ ├── node_modules/ ├── public/ ├── tmp/ ├── package.json ├── server.js ├── console.log └── stderr.log
Sementara itu, public_html hanya berisi .htaccess.
Isi .htaccess mengarahkan request ke aplikasi Node.js melalui Passenger:
PassengerAppRoot /home/username/domains/example.com/nodejs PassengerAppType node PassengerNodejs /path/to/node PassengerStartupFile server.js PassengerBaseURI / PassengerRestartDir /home/username/domains/example.com/nodejs/tmp
Alur request pada deployment yang benar menjadi:
Browser ↓ Apache ↓ .htaccess ↓ Passenger ↓ nodejs/server.js ↓ Next.js
Hostinger juga menjelaskan bahwa build aplikasi backend seperti Next.js ditempatkan di folder nodejs, sedangkan .htaccess di public_html digunakan untuk routing menuju runtime tersebut.
Akar Masalahnya: Tidak Ada Paket Standalone
Setelah membuka server.js dari deployment yang berhasil, ditemukan konfigurasi berikut:
"output": "standalone"
Di sinilah penyebab utama ditemukan.
Repository yang mengalami 403 belum menggunakan:
output: "standalone"
Akibatnya, Next.js hanya menghasilkan output build default dan Hostinger tidak memperoleh paket runtime mandiri yang berisi server.js.
Tanpa server.js, Hostinger tidak membentuk struktur runtime yang seharusnya digunakan Passenger untuk menjalankan aplikasi.
Solusi: Aktifkan Next.js Standalone Output
Buat atau edit file next.config.mjs di root repository:
/** @type {import("next").NextConfig} */
const nextConfig = {
output: "standalone",
};
export default nextConfig;Struktur sederhananya:
project/ ├── app/ ├── package.json ├── package-lock.json └── next.config.mjs
Apabila menggunakan format CommonJS pada next.config.js, bentuknya dapat ditulis sebagai:
/** @type {import("next").NextConfig} */
const nextConfig = {
output: "standalone",
};
module.exports = nextConfig;Gunakan salah satu format yang sesuai dengan repository. Tidak perlu membuat keduanya.
Apa yang Dilakukan output: "standalone"?
Ketika konfigurasi standalone aktif, Next.js melakukan output file tracing.
Next.js menganalisis file, import, dependency, dan package yang benar-benar dibutuhkan aplikasi saat production. Kemudian Next.js menghasilkan paket runtime minimal di:
.next/standalone/
Strukturnya kurang lebih:
.next/
└── standalone/
├── server.js
├── package.json
├── node_modules/
└── .next/File server.js tersebut dibuat otomatis oleh Next.js. Kita tidak perlu menulis custom server sendiri.
Next.js menjelaskan bahwa standalone output membuat folder deployment berisi file yang diperlukan, dependency terpilih, serta server minimal yang dapat dijalankan tanpa menggunakan next start.
Menguji Standalone Output di Localhost
Setelah menambahkan konfigurasi, hapus hasil build lama dan jalankan build ulang:
rm -rf .next npm run build
Periksa apakah file berikut sudah terbentuk:
test -f .next/standalone/server.js test -f .next/standalone/package.json test -d .next/standalone/node_modules
Jalankan standalone server:
PORT=3001 \ HOSTNAME=127.0.0.1 \ node .next/standalone/server.js
Kemudian buka:
http://127.0.0.1:3001
Pada kasus saya, halaman utama berhasil mengembalikan HTTP 200 dan endpoint API bekerja normal.
Catatan tentang file statis
Dokumentasi Next.js menyebutkan bahwa folder public dan .next/static tidak otomatis disalin ke folder standalone. Platform deployment dapat menangani proses tersebut sendiri. Untuk deployment manual, keduanya dapat disalin ke:
.next/standalone/public .next/standalone/.next/static
Push ke GitHub dan Biarkan Hostinger Melakukan Deployment Ulang
Setelah standalone berhasil diuji secara lokal:
git add next.config.mjs git commit -m "fix(deploy): enable Next.js standalone output" git push origin main
Apabila auto-deployment Hostinger aktif, push ke branch yang terhubung akan memicu deployment baru secara otomatis.
Pastikan build log kembali berhasil:
Compiled successfully Generating static pages Finalizing page optimization
Setelah deployment selesai, buka domain.
Pada kasus saya, halaman yang sebelumnya menampilkan:
403 Forbidden
akhirnya berubah menjadi halaman Next.js yang benar.
Endpoint dinamis juga berhasil diakses:
https://example.com/api/health
Responsnya:
{
"status": "ok",
"runtime": "nextjs"
}Struktur Deployment Setelah Berhasil
Setelah standalone output diterapkan, Hostinger membentuk struktur yang lebih tepat:
.builds/ nodejs/ public_html/
Folder nodejs berisi:
nodejs/ ├── .next/ ├── node_modules/ ├── package.json ├── server.js └── file runtime lainnya
Sementara itu, public_html/.htaccess meneruskan request ke nodejs/server.js melalui Passenger.
Dengan demikian, request tidak lagi berhenti di Apache dan dapat diproses oleh Next.js.
Mengapa Redeploy Saja Tidak Menyelesaikan Masalah?
Sebelum menemukan akar masalah, saya sempat melakukan redeploy tanpa mengubah kode.
Build kembali berhasil, tetapi website tetap 403.
Hal ini terjadi karena redeploy hanya membangun ulang konfigurasi repository yang sama.
Selama repository belum menghasilkan standalone runtime, hasil deployment tetap tidak memiliki server.js yang dibutuhkan.
Jadi, urutannya bukan hanya:
Redeploy
melainkan:
Tambahkan output: "standalone" ↓ Build dan uji lokal ↓ Commit ↓ Push ↓ Deploy ulang
Dokumentasi Hostinger menyatakan redeployment dapat membuat ulang .htaccess, tetapi apabila paket aplikasi yang dibutuhkan belum terbentuk, regenerasi routing saja belum tentu menyelesaikan penyebab dasarnya.
Checklist Troubleshooting 403 Next.js di Hostinger
Ketika mengalami masalah serupa, gunakan checklist berikut.
1. Pastikan aplikasi berjalan lokal
npm run build npm run start
2. Pastikan route utama mengembalikan HTTP 200
curl -I http://127.0.0.1:3000
3. Periksa build log Hostinger
Pastikan tidak ada:
Build failed Module not found Environment variable missing Out of memory
4. Periksa struktur file Hostinger
Deployment server-side yang benar seharusnya memiliki:
nodejs/ public_html/.htaccess
5. Periksa apakah server.js tersedia
nodejs/server.js
6. Tambahkan standalone output
const nextConfig = {
output: "standalone",
};7. Pastikan artefak lokal terbentuk
.next/standalone/server.js
8. Push dan deploy ulang
git push origin main
9. Uji halaman dan endpoint dinamis
https://example.com/ https://example.com/api/health
10. Jangan langsung mengedit .htaccess secara manual
Pada managed Web App Hosting, .htaccess dan konfigurasi Passenger sebaiknya dihasilkan oleh platform deployment.
Edit manual dapat hilang ketika deployment berikutnya dijalankan.
Apakah Semua Proyek Next.js Harus Menggunakan Standalone?
Tidak selalu.
Output default Next.js tetap valid dan dapat dijalankan menggunakan:
next build next start
pada server atau platform yang memang dikonfigurasi untuk menjalankan struktur repository secara penuh.
Standalone lebih relevan ketika aplikasi perlu dikemas menjadi paket runtime yang:
- lebih portabel,
- memiliki
server.js, - hanya membawa dependency yang dibutuhkan,
- dijalankan oleh container, Passenger, atau platform deployment tertentu,
- tidak bergantung pada seluruh repository production.
Jadi, output: "standalone" bukan pengganti semua metode deployment.
Namun, untuk kasus Hostinger Web App dengan gejala build berhasil tetapi domain 403 dan folder nodejs tidak terbentuk, konfigurasi ini layak menjadi pemeriksaan utama.
Standalone Bukan Static Export
Perlu dibedakan antara:
output: "standalone"
dan:
output: "export"
standalone tetap menjalankan server Node.js.
Fitur seperti berikut tetap dapat digunakan:
- server-side rendering,
- Route Handlers,
- API endpoint,
- Server Components,
- autentikasi server-side,
- koneksi database,
- halaman dinamis.
Sementara output: "export" menghasilkan website statis tanpa runtime Node.js.
Apabila aplikasi menggunakan API route atau fitur backend Next.js, jangan mengganti standalone dengan static export hanya untuk menghindari masalah runtime.
Kesimpulan
Masalah 403 pada deployment Next.js di Hostinger dapat terlihat seperti masalah domain, permission, SSL, atau .htaccess.
Namun, pada kasus yang saya alami, akar masalahnya adalah aplikasi belum menghasilkan paket runtime standalone.
Build memang berhasil, tetapi Hostinger tidak memperoleh:
server.js
yang diperlukan untuk menjalankan Next.js melalui Passenger.
Solusinya adalah menambahkan:
const nextConfig = {
output: "standalone",
};Setelah build ulang, pengujian lokal, commit, dan deployment baru, Hostinger berhasil membentuk runtime Node.js dan website dapat diakses secara normal.
Ringkasnya:
Build sukses + website 403 ↓ Periksa folder nodejs dan server.js ↓ Tambahkan output: "standalone" ↓ Build dan uji lokal ↓ Deploy ulang ↓ Website berhasil diakses
Semoga pengalaman ini membantu pengguna Hostinger lain yang mengalami kondisi serupa.
Salam Berkarya!
Putu Adi.
Keywords : Next.js output standalone, deploy Next.js ke Hostinger, Hostinger Web App, Next.js server.js, Next.js Passenger, error 403 Hostinger



