Dalam tutorial hari ini, kami akan belajar cara mengehos sendiri dan menyediakan pelayan kami, yang akan membolehkan kami menggunakan mana-mana aplikasi web dalam talian. Terdapat beberapa cara untuk menggunakan aplikasi dalam talian. Dua strategi melibatkan penggunaan VPS, Pelayan Peribadi Maya dan platform pengehosan terurus dikongsi seperti Vercel, Netlify, WordPress, GoDaddy, dll.
VPS ialah mesin maya yang menyediakan sumber pelayan khusus pada pelayan yang dikongsi secara fizikal dengan pengguna lain. Ia sebenarnya pengehosan peringkat pertengahan untuk tapak web dan aplikasi, menawarkan lebih banyak kawalan dan penyesuaian berbanding pengehosan dikongsi. Contoh beberapa platform pengehosan VPS termasuk Hetzner, Akamai, Vultr, Cloudcone.
Sebaliknya, lebih mudah untuk mengehoskan tapak web menggunakan platform pengehosan terurus. Platform sedemikian menyediakan alatan, aliran kerja dan infrastruktur untuk membina dan menggunakan aplikasi web. Platform ini melakukan pengimbangan beban dan caching sendiri. Ia berfungsi dengan baik untuk mana-mana pembangun yang ingin membina dan menggunakan aplikasi web dengan cepat tanpa konfigurasi lanjut.
Seperti biasa, terdapat kebaikan dan keburukan untuk menggunakan setiap strategi. Salah satu perbezaan yang paling ketara ialah apabila menggunakan VPS, anda mendapat penyesuaian lengkap kerana anda mengawal keseluruhan pelayan dan semua yang disertakan bersamanya. Ini bermakna menyediakan persekitaran pembangunan, peraturan tembok api, pengehosan, dll. Penyesuaian ini menambah kerumitan dan anda memerlukan lebih banyak sokongan teknikal kerana anda melakukan semuanya sendiri. Anda harus tahu bahawa platform pengehosan terurus benar-benar mesra kepada pemula kerana kebanyakan alat telah ditetapkan, dan anda mendapat sokongan serta dokumentasi. Kerana ia telah disediakan dan diuruskan, anda tidak akan mendapat tahap penyesuaian yang tinggi yang anda akan dapat daripada VPS.
Selain itu, anda perlu mengambil kira perbezaan harga. Kebanyakan VPS dibayar, walaupun anda boleh menyesuaikan sepenuhnya pelayan anda untuk menjadikannya ringan atau sekuat yang anda perlukan. Dari segi prestasi, itu meletakkannya satu langkah di atas mana-mana platform pengehosan terurus. Yang terakhir ini mempunyai rancangan percuma, jadi anda perlu melihat perbezaannya. Pengguna umum mahukan platform pengehosan terurus kerana ia adalah percuma. Walau bagaimanapun, jika anda inginkan lebih kuasa dan ingin mengehos aplikasi lanjutan dalam satu aplikasi, maka VPS ialah cara untuk digunakan.
Aplikasi Penjejak Senarai Pantau kami ialah aplikasi CRUD tindanan penuh yang ringkas tetapi berkuasa yang akan digunakan untuk menjejaki senarai tontonan filem. Aplikasi ini juga akan membolehkan penggunanya menambah filem atau siri yang mereka ingin tonton dengan mudah, mengemas kini tajuk atau rating filem dan mengalih keluar filem yang telah mereka tonton atau tidak mahu jejaki lagi. Apl ini memberi pengguna akses kepada antara muka yang mudah untuk mengatur dan mengikuti filem yang diminati, menjadikannya alat yang sesuai untuk peminat filem yang ingin kekal di hadapan dalam memantau senarai tontonan mereka.
Anda boleh melihat rupa apl di bawah:
Halaman utama
Halaman Item Filem/siri
Tambah halaman Item Baharu
Sebelum kami mula membina aplikasi, adalah penting untuk menyediakan persekitaran pembangunan anda dan berfungsi. Pastikan anda memasang yang berikut pada mesin anda:
Terdapat sambungan SQLite Viewer percuma yang sangat baik untuk Kod VS, yang juga boleh membantu, di samping menggunakan baris arahan. Ia bagus untuk melihat data dalam pangkalan data anda dengan cepat.
Apl Penjejak Senarai Pantau kami dibina menggunakan timbunan teknikal yang sangat moden dan berfikiran ke hadapan, yang memberikan pengalaman pembangunan yang sangat baik. Saya telah memilih untuk menggunakan alatan seperti Bun, Hono, Vite, TanStack, Hetzner dan DeployHQ kerana semuanya menawarkan pengalaman binaan moden kepada pembangun.
Mari kita lihat teknologi yang akan kami gunakan dalam projek ini:
Belakang
Hadapan
Penghosan dan penggunaan
Baiklah, mari mula membina apl kami! Bahagian ini akan dibahagikan kepada dua bahagian: pertama, kami akan membuat bahagian belakang, dan kemudian kami akan mencipta bahagian hadapan.
Sila buat folder baharu pada komputer anda untuk projek yang dipanggil watchlist-tracker-app dan kemudian cd ke dalamnya. Sekarang, buat projek Bun baharu untuk bahagian belakang dengan menggunakan arahan ini yang ditunjukkan di sini:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Projek kami kini harus disediakan. Kami hanya perlu memasang kebergantungan, bekerja pada konfigurasi, dan menulis beberapa kod pelayan. Buka projek dalam editor kod anda.
Sekarang pasang kebergantungan untuk pelayan kami menggunakan arahan ini:
bun add hono prisma @prisma/client
Kami telah menambahkan Bun sebagai persekitaran masa jalan, Hono sebagai pelayan API kami dan Prisma sebagai ORM pangkalan data kami.
Mari sekarang sediakan Prisma ORM dan SQLite dengan arahan ini:
npx prisma init
Prisma harus dikonfigurasikan untuk berfungsi dalam pelayan kami sekarang, jadi dalam langkah seterusnya, kami akan mengkonfigurasi skema pangkalan data kami. Jadi gantikan semua kod dalam prisma/schema.prisma dengan kod ini:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Skema pangkalan data kami telah disediakan dan ia disambungkan ke fail pangkalan data SQLite kami.
Sekarang jalankan skrip migrasi ini untuk mencipta pangkalan data SQLite:
npx prisma migrate dev --name init
Bagus, kini setelah penghijrahan Prisma selesai, kami boleh mengusahakan fail API kami.
Sekarang mari buat fail API utama kami, yang akan menggunakan Hono. Pergi ke fail pelayan di dalam src/server.ts dan tambahkan kod ini pada fail:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Dengan fail ini, pelayan kami akan menggunakan Bun dan Hono dan dijalankan pada port 8000. Kami juga mempunyai semua titik akhir CRUD (Buat, Baca, Kemas Kini, Padam) untuk penjejak senarai pantau kami. Semua data kami disimpan di dalam pangkalan data SQLite.
Yang tinggal hanyalah mencipta skrip larian dan bina untuk pelayan kami. Kemudian, kita boleh menguji titik akhir untuk memastikan ia berfungsi seperti yang diharapkan. Tambahkan skrip larian ini pada fail package.json kami:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
Ok, sekarang jika anda menjalankan perintah bun run start, anda sepatutnya melihat ini dalam terminal anda mengesahkan bahawa pelayan sedang berjalan:
Server is running on http://localhost:8000
Jika anda menjalankan command bun run build, ia harus mencipta folder dist yang sedia untuk pengeluaran. Kami akan memerlukan ini apabila kami menggunakan aplikasi kami pada Hetzner atau mana-mana pelayan dalam talian.
Baiklah, mari kita uji titik akhir hujung belakang kami dengan cepat untuk memastikan ia berfungsi seperti yang diharapkan. Kemudian, kita boleh mula bekerja pada bahagian hadapan kita. Kami mempunyai lima titik akhir untuk diuji: dua GET, satu POST, satu PUT dan satu DELETE. Saya akan menggunakan Posmen untuk menguji API.
Titik Akhir POST API Apl Senarai Pantau
Kaedah: POST
Titik tamat: http://localhost:8000/watchlist
Ini ialah titik akhir POST kami, yang digunakan untuk menghantar objek JSON dengan data filem/siri ke pangkalan data kami.
API Apl Senarai Pantau DAPATKAN Semua Titik Akhir
Kaedah: DAPATKAN
Titik tamat: http://localhost:8000/watchlist
Ini ialah titik akhir GET utama kami, yang akan mengembalikan susunan objek yang akan diambil bahagian hadapan kami. Ia mengembalikan tatasusunan objek dengan data kami atau tatasusunan kosong jika kami masih belum menghantar sebarang data ke pangkalan data kami.
API Senarai Pantauan DAPATKAN Melalui ID Endpoint
Kaedah: DAPATKAN
Titik tamat: http://localhost:8000/watchlist/3
Ini ialah titik akhir GET kami untuk mendapatkan item mengikut ID mereka. Ia hanya mengembalikan objek itu dan menunjukkan ralat jika item itu tidak wujud.
API Senarai Pantauan PUT Endpoint
Kaedah: MELETAKKAN
Titik tamat: http://localhost:8000/watchlist/3
Ini adalah titik akhir PUT kami untuk mengemas kini item menggunakan ID mereka. Ia hanya mengembalikan objek itu dan menunjukkan ralat jika item itu tidak wujud.
API Senarai Pantauan PADAMKAN Titik Tamat
Kaedah: PADAM
Titik tamat: http://localhost:8000/watchlist/3
Ini ialah titik akhir DELETE kami untuk memadam item menggunakan ID mereka. Ia mengembalikan objek kejayaan dan menunjukkan ralat jika item itu tidak wujud.
Iaitu, API kami berfungsi dan berjalan. Kita boleh mula menggunakan kod bahagian hadapan sekarang.
Pastikan anda berada di dalam folder akar untuk apl penjejak senarai pantau, kemudian jalankan skrip ini di bawah untuk mencipta projek React menggunakan Vite yang disediakan untuk TypeScript dengan semua pakej dan kebergantungan kami:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Skrip ini pada asasnya menggunakan persekitaran masa jalan Bun untuk memasang dan menyediakan projek kami. Semua fail dan folder yang diperlukan telah dibuat, jadi kami hanya perlu menambah kod. Kami telah menyediakan projek Vite kami untuk menggunakan Tailwind CSS untuk penggayaan dan kami mempunyai TanStack Router untuk penghalaan halaman dengan aksios untuk mengambil data dan dayjs untuk melakukan penukaran tarikh dalam borang kami.
Terima kasih kepada skrip binaan ini, tugas kami kini jauh lebih mudah, jadi mari kita mula menambahkan kod pada fail kami. Mula-mula ialah beberapa fail konfigurasi. Gantikan semua kod di dalam fail tailwind.config.js dengan kod ini:
bun add hono prisma @prisma/client
Fail ini cukup penjelasan. Kami memerlukan fail ini supaya Tailwind CSS berfungsi sepanjang projek kami.
Sekarang gantikan semua kod dalam fail src/index.css kami dengan kod ini, kami perlu menambah arahan Tailwind supaya kami boleh menggunakannya dalam fail CSS kami:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Dengan arahan ini ditambah, kami boleh mengakses gaya CSS Tailwind dalam semua fail CSS kami. Seterusnya padamkan semua kod CSS di dalam fail App.css kerana kami tidak memerlukannya lagi.
Baiklah, sekarang untuk fail konfigurasi terakhir, dan kemudian kami boleh bekerja pada halaman dan komponen kami.
Tambahkan kod ini pada fail api.ts dalam folder akar:
bun add hono prisma @prisma/client
Fail ini mengeksport titik akhir, yang bahagian hadapan kami perlu disambungkan pada bahagian belakang kami. Ingat bahawa API bahagian belakang kami terletak di http://localhost:8000.
Baiklah mari kita gantikan semua kod dalam fail App.tsx kami dengan kod baharu ini:
npx prisma init
Ini ialah komponen titik masuk utama kami untuk apl kami dan komponen ini memegang laluan untuk semua halaman kami.
Seterusnya, kami akan mengusahakan komponen dan halaman utama. Kami mempunyai tiga fail komponen dan tiga halaman fail. Bermula dengan komponen tambah kod ini pada fail kami dalam komponen/AddItemForm.tsx:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Komponen ini digunakan untuk menambah item pada pangkalan data kami. Pengguna akan menggunakan komponen borang ini untuk menghantar permintaan POST ke bahagian belakang.
Sekarang mari tambah kod untuk komponen/FormField.tsx:
npx prisma migrate dev --name init
Ini ialah komponen medan borang boleh guna semula untuk borang kami. Ia memastikan kod kami KERING kerana kami hanya boleh menggunakan komponen yang sama untuk berbilang medan yang bermaksud pangkalan kod kami lebih kecil.
Dan akhir sekali mari tambah kod untuk komponen/Header.tsx:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Oleh kerana komponen pengepala ini, setiap halaman mempunyai pengepala dengan navigasi utama.
Yang kami tinggalkan ialah tiga halaman dan kemudian aplikasi kami selesai. Jadi tambahkan kod berikut ini pada halaman/AddItem.tsx:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
Ini pada asasnya adalah halaman untuk menambah item pada pangkalan data kami yang mempunyai komponen bentuk di dalamnya.
Seterusnya mari tambah kod untuk halaman/Home.tsx:
Server is running on http://localhost:8000
Seperti yang anda boleh bayangkan, ini akan menjadi halaman utama kami, yang menghantar permintaan GET ke bahagian belakang, yang kemudiannya mendapatkan semula pelbagai objek untuk semua item dalam pangkalan data kami.
Akhir sekali tambah kod untuk halaman/ItemDetail.tsx:
bun create vite client --template react-ts cd client bunx tailwindcss init -p bun install -D tailwindcss postcss autoprefixer tailwindcss -p bun install @tanstack/react-router axios dayjs cd src mkdir components pages touch api.ts touch components/{AddItemForm,FormField,Header}.tsx pages/{AddItem,Home,ItemDetail}.tsx cd ..
Halaman ini memaparkan halaman item individu mengikut ID mereka. Terdapat juga borang untuk mengedit dan memadam item daripada pangkalan data.
Itu sahaja. Aplikasi kami sedia untuk digunakan. Pastikan kedua-dua bahagian belakang dan pelayan pelanggan sedang berjalan. Anda sepatutnya melihat apl berjalan dalam penyemak imbas di sini: http://localhost:5173/.
Jalankan kedua-dua pelayan dengan arahan ini di dalam folder mereka:
module.exports = { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, plugins: [], };
Ok, syabas. Permohonan kami telah lengkap! Sekarang mari kita gunakannya ke GitHub!
Menggunakan aplikasi kami ke GitHub adalah agak mudah. Mula-mula letakkan fail .gitignore di dalam folder akar untuk apl penjejak senarai pantau kami. Anda hanya boleh menyalin dan menampal fail .gitignore daripada sama ada bahagian belakang atau folder klien. Sekarang pergi ke GitHub anda (buat akaun jika anda tidak mempunyai akaun) dan buat repo untuk apl penjejak senarai pantau anda.
Di dalam folder akar untuk apl senarai pantauan-penjejak gunakan baris arahan untuk memuat naik pangkalan kod anda. Lihat kod contoh ini dan sesuaikan untuk repositori anda sendiri:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Ada satu perkara terakhir yang sangat penting untuk diketahui. Apabila kami memuat naik kod kami ke Hetzner, kami tidak lagi dapat mengakses bahagian belakang melalui localhost, jadi kami perlu mengemas kini laluan API. Terdapat pembolehubah yang dipanggil const API_URL = 'http://localhost:8000'; dalam dua fail di bahagian atasnya. Fail adalah api.ts dan komponen/AddItemForm.tsx. Gantikan URL API berubah dengan yang di bawah dan kemudian muat naik semula pangkalan kod anda ke GitHub.
bun add hono prisma @prisma/client
Itu sahaja yang ada. Pangkalan kod anda kini seharusnya berada dalam talian di GitHub supaya kami kini boleh mengusahakannya untuk mengaturnya kepada Hetzner.
Dengan apl penjejak senarai pantau kami lengkap, kini tiba masanya untuk menggunakan aplikasi kami ke platform Hetzner VPS. Hetzner ialah platform berbayar, tetapi fleksibiliti yang ditawarkannya tiada tandingan. Pelan paling murah ialah sekitar €4.51/$4.88/£3.76 sebulan. Pelayan dalam talian yang dihoskan sendiri adalah berbaloi kerana, sebagai pembangun, anda boleh menggunakannya untuk pembelajaran, latihan, penggunaan pengeluaran dan banyak lagi. Anda sentiasa boleh membatalkan langganan pelayan dan mendapatkannya semula apabila diperlukan.
Kebanyakan VPS pada asasnya adalah sama kerana semuanya adalah pelayan yang boleh menjalankan sistem pengendalian yang berbeza, seperti Linux. Setiap penyedia VPS mempunyai antara muka dan persediaan yang berbeza, tetapi struktur asasnya agak sama. Dengan mempelajari cara mengehos sendiri aplikasi pada Hetzner, anda boleh menggunakan semula kemahiran dan pengetahuan yang sama ini dengan mudah untuk menggunakan aplikasi pada platform VPS yang berbeza.
Sesetengah kes penggunaan untuk VPS termasuk:
Anda boleh melihat rupa harga semasa untuk Hetzner di sini:
Pergi ke tapak web Hetzner dan klik pada butang Daftar Merah di tengah-tengah halaman. Sebagai alternatif, anda boleh klik pada butang Log Masuk di sudut kanan atas. Anda seharusnya melihat menu dengan pilihan untuk Cloud, Robot, konsoleH dan DNS. Klik pada mana-mana satu daripadanya untuk pergi ke halaman borang log masuk dan daftar.
Sekarang, anda sepatutnya melihat halaman borang log masuk dan daftar. Klik butang daftar untuk membuat akaun dan melengkapkan proses pendaftaran. Anda mungkin perlu melepasi peringkat pengesahan sama ada dengan menggunakan akaun PayPal anda atau menyediakan pasport anda.
Anda kini sepatutnya boleh log masuk ke akaun anda dan membuat serta membeli pelayan. Pilih lokasi yang berdekatan dengan anda, dan kemudian pilih Ubuntu sebagai imej. Lihat contoh ini untuk rujukan.
Di bawah Jenis, pilih vCPU kongsi, dan kemudian pilih konfigurasi untuk pelayan anda. Kami menggunakan aplikasi mudah yang hanya memerlukan beberapa sumber. Jika anda mahu, jangan ragu untuk mendapatkan pelayan yang lebih baik—terpulang kepada anda. vCPU yang berdedikasi berprestasi lebih baik tetapi memerlukan lebih banyak wang. Anda juga boleh memilih antara pemproses x86 (Intel/AMD) dan Arm64 (Ampere).
Konfigurasi lalai seharusnya boleh diterima. Lihat contoh di bawah. Namun, atas sebab keselamatan, adalah penting untuk menambah kunci SSH.
Kunci SSH menyediakan cara yang lebih selamat untuk mengesahkan ke pelayan anda daripada kata laluan tradisional. Kunci perlu dalam format OpenSSH, memastikan tahap keselamatan yang tinggi untuk pelayan anda. Bergantung pada sistem pengendalian anda, anda boleh melakukan carian Google untuk "Jana kunci SSH pada Mac" atau "Jana kunci SSH pada Windows." Saya akan memberi anda panduan ringkas untuk menjana kunci SSH pada Mac.
Mula-mula buka aplikasi terminal anda dan kemudian taip arahan berikut menggantikan "email_anda@contoh.com" dengan alamat e-mel sebenar anda:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Bahagian -b 4096 memastikan bahawa kunci adalah 4096 bit untuk meningkatkan keselamatan. Seterusnya simpan kunci selepas digesa untuk berbuat demikian. Anda boleh menerima lokasi lalai atau memilih lokasi tersuai:
bun add hono prisma @prisma/client
Menetapkan frasa laluan adalah pilihan anda boleh melangkau langkah ini. Sekarang, muatkan kunci SSH ke dalam ejen SSH anda dengan menjalankan arahan berikut:
Pertama, mulakan ejen:
npx prisma init
Kemudian, tambah kekunci SSH:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Untuk menyalin kunci awam SSH anda ke papan keratan anda, jalankan:
npx prisma migrate dev --name init
Ini menyalin kunci awam supaya anda boleh menambahkannya pada Hetzner atau mana-mana perkhidmatan lain yang memerlukan kunci SSH. Tampalkan kunci SSH anda ke dalam kotak borang ini dan tambahkannya.
Anda tidak perlu risau tentang Kelantangan, Kumpulan Peletakan, Label atau konfigurasi Awan kerana ia berada di luar skop projek ini. Sandaran boleh membantu, tetapi ia akan menambah kos, jadi ia adalah pilihan untuk projek ini. Kami akan melakukan Firewall kemudian, jadi anda tidak perlu risau mengenainya sekarang. Pilih nama untuk pelayan anda, kemudian teruskan buat dan beli pelayan dengan tetapan semasa anda dan akaun Hetzner anda akan sedia untuk digunakan.
Ok, bagus. Kami kini mempunyai akaun di Hetzner. Dalam bahagian seterusnya, kami akan menyediakan tembok api kami, mengkonfigurasi sistem pengendalian Linux kami dan mendapatkan aplikasi kami dalam talian.
Sebelum kita SSH ke dalam OS Linux kita, mari kita sediakan peraturan tembok api kita dahulu. Kami memerlukan port 22 dibuka supaya kami boleh menggunakan SSH dan kami memerlukan port 80 dibuka kerana port 80 ialah port TCP yang merupakan port rangkaian lalai untuk pelayan web menggunakan HTTP (Hypertext Transfer Protocol). Ia digunakan untuk berkomunikasi antara pelayar web dan pelayan, menghantar dan menerima kandungan web. Beginilah cara kami membuat permohonan kami berfungsi dalam talian.
Navigasi ke Firewall dalam menu utama dan kemudian buat firewall dengan peraturan masuk yang ditunjukkan di bawah:
Kini, dengan tembok api kami berfungsi, kami boleh menyediakan persekitaran Linux dan aplikasi kami digunakan, jadi mari lakukannya seterusnya.
Menyambung ke pelayan Hetzner jauh kami sepatutnya agak mudah kerana kami telah mencipta kunci SSH untuk log masuk. Kami boleh menyambung menggunakan terminal atau editor kod seperti Kod VS, yang akan memberi kami keupayaan untuk melihat dan menyemak imbas kami fail dengan lebih mudah tanpa perlu menggunakan baris arahan. Jika anda ingin menggunakan Visual Studio Code Remote - sambungan SSH, anda boleh berbuat demikian. Untuk projek ini, kami akan kekal dengan terminal.
Buka terminal anda dan taip arahan SSH ini untuk log masuk ke pelayan jauh anda. Gantikan alamat 11.11.111.111 dengan alamat IP Hetzner sebenar anda, yang boleh anda temui di bahagian pelayan:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Anda kini harus log masuk ke pelayan anda, yang memaparkan skrin alu-aluan dan maklumat peribadi lain seperti alamat IP anda. Saya hanya menunjukkan bahagian alu-aluan skrin di sini:
bun add hono prisma @prisma/client
Baiklah, bagus. Kini, kami akhirnya boleh mula menjalankan beberapa arahan yang akan menyediakan persekitaran pembangunan kami sebelum kami mendapatkan aplikasi kami dalam talian. Ngomong-ngomong, jika anda ingin keluar dan menutup sambungan SSH ke pelayan anda, anda boleh menaip keluar diikuti dengan mengklik butang masukkan atau menggunakan pintasan papan kekunci Ctrl D.
Perkara pertama yang perlu kami lakukan ialah mengemas kini dan menaik taraf pakej pada sistem Linux kami. Kita boleh melakukannya dengan satu arahan, jadi taip arahan ini ke dalam terminal dan tekan enter:
npx prisma init
Kini, kami perlu memasang baki pakej pembangunan dan kebergantungan kami. Pertama ialah Node.js dan npm, jadi pasangkannya dengan arahan ini:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Seterusnya ialah Nginx, yang perlu kita gunakan sebagai proksi terbalik. Proksi terbalik ialah pelayan yang terletak di antara pelanggan dan pelayan belakang, memajukan permintaan klien ke pelayan belakang yang sesuai dan kemudian mengembalikan respons pelayan kepada klien. Ia bertindak sebagai perantara, mengurus dan menghalakan permintaan masuk untuk meningkatkan prestasi, keselamatan dan kebolehskalaan. Jadi pasangkannya dengan arahan ini:
npx prisma migrate dev --name init
Kami akan memerlukan Git, yang mana kami perlu menarik kod kami daripada GitHub dan memuat naiknya ke pelayan jauh kami. Jadi pasangkannya dengan arahan ini:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Waktu jalan Bun akan membantu untuk menjalankan aplikasi kami. Pertama, kita perlu memasang pakej unzip seperti yang diperlukan sebelum memasang Bun. Selepas itu, kita boleh memasang Bun. Ini adalah arahan yang kami perlukan:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
bun add hono prisma @prisma/client
Untuk menjalankan kedua-dua bahagian hadapan React dan pelayan bahagian belakang pada pelayan Hetzner yang sama, kami perlu mengurus kedua-dua perkhidmatan secara serentak. Ini biasanya melibatkan penyediaan pengurus proses seperti PM2 untuk menjalankan pelayan hujung belakang dan menggunakan Nginx sebagai proksi terbalik untuk mengendalikan permintaan masuk ke hujung depan dan belakang.
Pasang PM2 dengan menggunakan arahan ini di sini:
npx prisma init
Betul, itu menjaga persediaan persekitaran Linux kami. Dalam bahagian seterusnya, kami akan memuat turun pangkalan kod kami daripada GitHub ke pelayan jauh kami dan mengkonfigurasi pelayan Nginx kami untuk membolehkan apl kami berfungsi dalam talian.
Saya akan menganggap bahawa anda sudah tahu cara menavigasi baris arahan. Jika tidak anda boleh Google. Kami akan menukar direktori dan menguruskan fail. Mulakan dengan mengklon repo GitHub dengan projek anda dan menyalinnya ke pelayan jauh. Gunakan arahan di bawah untuk rujukan:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Fail aplikasi web kami akan disimpan di dalam /var/www. Anda boleh melihat semua fail pada OS Linux anda dengan menggunakan arahan ls yang digunakan untuk menyenaraikan fail dan pwd yang digunakan untuk mencetak direktori kerja. Untuk mengetahui lebih lanjut tentang baris arahan Linux, sila lihat tutorial ini untuk baris arahan Linux untuk pemula.
Jadi sekarang setelah kami mempunyai aplikasi kami pada pelayan jauh kami, kami boleh membuat binaan pengeluaran bahagian belakang dan bahagian hadapan. Untuk melakukan ini, kami hanya perlu memasukkan cd ke akar untuk bahagian belakang folder dan klien di dalam projek senarai pantau-penjejak kami dan jalankan arahan yang ditunjukkan di bawah:
npx prisma migrate dev --name init
Kami menggunakan Bun sebagai masa jalan kami jadi kami akan menggunakan arahan bun untuk langkah pemasangan dan pembinaan.
Baiklah, sekarang mari konfigurasi pelayan Nginx kami. Kami akan menggunakan editor terminal nano untuk menulis kod di dalam fail. Jalankan arahan ini dalam terminal untuk membuka fail Nginx untuk apl penjejak senarai pantau kami:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Jika anda tidak biasa dengan editor kod nano, lihat helaian tipu ini.
Anda hanya perlu menyalin dan menampal konfigurasi ini ke dalam fail dan menyimpannya. Pastikan anda menggantikan alamat IP server_name dengan alamat IP Hetzner anda sendiri:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
Nginx sangat kerap digunakan untuk menjalankan peranan pelayan proksi terbalik. Proksi terbalik terletak di antara klien-pelayar pengguna anda dan pelayan bahagian belakang anda. Ia menerima permintaan daripada pelanggan dan memajukannya kepada satu atau lebih pelayan bahagian belakang. Setelah bahagian belakang memproses permintaan, proksi terbalik memajukan respons kembali kepada pelanggan. Dalam persediaan sedemikian, Nginx akan menjadi titik masuk untuk trafik masuk dan permintaan laluan ke perkhidmatan tertentu, katakan Vite frontend atau API backend.
Binaan pratonton pengeluaran Vite dijalankan pada port 4173 dan pelayan bahagian belakang kami berjalan pada port 8000. Jika anda menukar nilai ini, maka pastikan anda mengemas kininya dalam fail konfigurasi Nginx ini juga; jika tidak, pelayan tidak akan berfungsi.
Dayakan tapak Nginx jika ia belum didayakan dengan arahan ini:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Sekarang uji konfigurasi Nginx untuk memastikan tiada ralat sintaks dan mulakan semula Nginx untuk menggunakan perubahan dengan arahan ini:
bun add hono prisma @prisma/client
Kita hampir selesai. Tinggal selangkah lagi. Jika anda pergi ke alamat IP Hetzner anda sekarang dalam penyemak imbas, anda sepatutnya melihat ralat seperti 502 Bad Gateway. Itu kerana kami belum mempunyai pelayan yang sedang berjalan; pertama, kita perlu menjalankan kedua-dua pelayan secara serentak menggunakan PM2. Jadi, kita perlu menetapkan PM2 untuk bermula pada but sistem supaya aplikasi kita sentiasa dalam talian. Lakukan ini dengan menjalankan arahan ini dalam terminal:
npx prisma init
Kini, kita perlu menjalankan pelayan hujung belakang dan bahagian hadapan. Jalankan arahan ini dari dalam akar folder mereka.
Mari kita mulakan dengan pelayan bahagian belakang, jadi jalankan arahan ini dalam terminal:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Akhir sekali, mari jalankan pelayan bahagian hadapan pelanggan, jadi jalankan arahan ini dalam terminal:
npx prisma migrate dev --name init
Anda boleh menjalankan perintah pm2 status untuk menyemak sama ada kedua-dua pelayan dalam talian dan berjalan, seperti yang ditunjukkan di bawah. Untuk mengetahui tentang semua arahan PM2 yang lain, baca dokumentasi mengenai Permulaan Pantas Pengurusan Proses PM2:
Anda boleh menguji sama ada pelayan boleh dicapai dengan menjalankan arahan curl ini dalam terminal. Anda harus mendapatkan kembali kod HTML jika ia berfungsi:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Pergi ke alamat IP untuk pelayan Hetzner anda. Jika anda melakukan semuanya dengan betul, anda seharusnya melihat apl anda digunakan dan dalam talian! Laman web biasanya mempunyai nama domain, dan alamat IP kekal tersembunyi daripada bar carian. Ia adalah perkara biasa bagi pembangun untuk membeli domain dan kemudian menukar pelayan nama untuk menyambungkannya ke pelayan hos. Ini di luar skop tutorial ini, tetapi anda boleh mempelajari cara melakukannya dengan mudah dengan melakukan carian Google. Namecheap ialah daftar domain pilihan saya.
Betul, kami hampir siap. Sekarang, langkah terakhir ialah menggunakan DeployHQ untuk menyelaraskan proses penggunaan. DeployHQ menjadikan penempatan mudah dan jauh lebih baik untuk tujuan keselamatan. Cara tradisional untuk mengemas kini pangkalan kod pada pelayan dalam talian ialah menggunakan git pull untuk mendapatkan perubahan terkini daripada repo GitHub anda. Walau bagaimanapun, melakukan git pull bukanlah amalan yang baik kerana ia mungkin mendedahkan folder git, dan tapak web kemungkinan besar tidak akan dikecilkan, dijelekkan dan sebagainya.
DeployHQ memainkan peranan penting di sini. Ia menyalin fail yang diubah suai dengan selamat dalam folder yang dikonfigurasikan, memastikan tiada perubahan dapat dilihat dalam log git pada pelayan anda. Ini mungkin kelihatan seperti pertukaran, tetapi ia adalah ciri keselamatan yang meyakinkan anda tentang keselamatan penggunaan anda. Jika anda biasa dengan platform seperti Vercel atau Netlify, anda akan mendapati penggunaan auto ini agak serupa. Dalam kes ini, anda mempunyai persediaan yang boleh berfungsi dengan mana-mana pelayan dalam talian pada VPS.
Satu perkara yang patut dinyatakan ialah penting untuk kami mencipta pengguna bukan root untuk pelayan jauh Linux dalam talian kami. Log masuk sebagai pengguna akar bukanlah amalan terbaik; adalah lebih baik untuk menyediakan pengguna lain dengan keistimewaan yang serupa. DeployHQ juga tidak menggalakkan penggunaan pengguna root untuk log masuk. Untuk membolehkan DeployHQ berfungsi, kami perlu menggunakan SSH untuk log masuk ke akaun kami. Kami akan melakukan ini selepas kami mempunyai akaun DeployHQ kerana kami perlu meletakkan kunci awam SSH DeployHQ kami pada pelayan Ubuntu dalam talian kami.
DeployHQ memberi anda akses percuma kepada semua ciri mereka selama 10 hari tanpa sebarang kewajipan apabila anda mendaftar buat kali pertama. Selepas itu, akaun anda akan kembali kepada pelan percuma yang membolehkan anda menggunakan satu projek sehingga 5 kali sehari.
Mulakan dengan pergi ke tapak web DeployHQ dan buat akaun dengan mengklik salah satu butang yang anda lihat di bawah:
Ok, kini anda sepatutnya melihat selamat datang ke skrin DeployHQ dengan butang Buat projek. Klik butang untuk mencipta projek seperti yang ditunjukkan di sini:
Pada skrin seterusnya, anda perlu mencipta projek baharu. Jadi sila beri nama, dan pilih repo GitHub anda. Selain itu, pilih zon untuk projek anda dan kemudian buat projek:
Anda kini seharusnya melihat skrin pelayan, seperti yang ditunjukkan di bawah. Ini bermakna sudah tiba masanya untuk mencipta pengguna Linux lain untuk pelayan jauh kami supaya kami tidak perlu bergantung pada pengguna root.
Mulakan dengan log masuk ke pelayan anda sebagai pengguna root, dan kemudian buat pengguna baharu dengan arahan ini di bawah. Gantikan new_username dengan nama pengguna yang anda mahu gunakan untuk pengguna baharu:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Anda akan diminta untuk menetapkan kata laluan, dan akan ada gesaan untuk memasukkan butiran seperti nama penuh, nombor bilik, dll. Anda hanya perlu menetapkan kata laluan. Anda boleh melangkau langkah gesaan yang lain dan biarkannya kosong dengan menekan Enter sehingga semuanya hilang.
Adalah idea yang baik untuk menambah pengguna baharu pada kumpulan sudo supaya mereka boleh mempunyai keistimewaan pentadbiran seperti pengguna akar. Lakukan ini dengan arahan yang ditunjukkan di sini:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
Pengguna baharu kini memerlukan akses SSH untuk pelayan. Mula-mula tukar kepada pengguna baharu dan kemudian buat direktori .ssh untuk mereka dengan arahan ini:
bun add hono prisma @prisma/client
Sekarang kita perlu menambah Kunci Awam tempatan kami pada kunci_izin pada pelayan supaya pada mesin tempatan anda menyalin kunci awam anda dengan arahan ini:
npx prisma init
Kini pada pelayan buka fail authorized_keys supaya ia boleh diedit dengan editor nano:
datasource db { provider = "sqlite" url = "file:./dev.db" } generator client { provider = "prisma-client-js" } model WatchlistItem { id Int @id @default(autoincrement()) name String image String rating Float description String releaseDate DateTime genre String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }
Tampal kunci awam yang disalin ke dalam fail ini. Sebelum anda menyimpan fail, salin dan tampal kunci SSH DeployHQ dari halaman pelayan ke dalam fail yang sama. Anda boleh melihat kunci SSH apabila anda menandai kotak untuk Gunakan kunci SSH dan bukannya kata laluan untuk pengesahan?. Sekarang simpan fail dan tetapkan kebenaran yang betul untuk fail dengan arahan ini:
npx prisma migrate dev --name init
Anda kini boleh menguji log masuk SSH untuk pengguna baharu. Mula-mula, log keluar dari pelayan jauh dan kemudian cuba log masuk semula, tetapi kali ini menggunakan pengguna baharu yang anda buat dan bukan root. Lihat contoh di bawah:
import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { PrismaClient } from '@prisma/client'; const app = new Hono(); app.use(cors()); const prisma = new PrismaClient(); app.get('/watchlist', async (c) => { const items = await prisma.watchlistItem.findMany(); return c.json(items); }); app.get('/watchlist/:id', async (c) => { const id = c.req.param('id'); const item = await prisma.watchlistItem.findUnique({ where: { id: Number(id) }, }); return item ? c.json(item) : c.json({ error: 'Item not found' }, 404); }); app.post('/watchlist', async (c) => { const data = await c.req.json(); const newItem = await prisma.watchlistItem.create({ data }); return c.json(newItem); }); app.put('/watchlist/:id', async (c) => { const id = c.req.param('id'); const data = await c.req.json(); const updatedItem = await prisma.watchlistItem.update({ where: { id: Number(id) }, data, }); return c.json(updatedItem); }); app.delete('/watchlist/:id', async (c) => { const id = c.req.param('id'); await prisma.watchlistItem.delete({ where: { id: Number(id) } }); return c.json({ success: true }); }); Bun.serve({ fetch: app.fetch, port: 8000, }); console.log('Server is running on http://localhost:8000'); export default app;
Dengan mengandaikan anda melakukan semuanya dengan betul, anda kini sepatutnya boleh log masuk dengan pengguna baharu anda.
Kini kami akhirnya boleh melengkapkan borang pelayan. Isikan borang dengan maklumat anda lihat contoh di bawah:
Nama: apl penjejak senarai pantau
Protokol: SSH/SFTP
Nama hos: 11.11.111.111
Pelabuhan: 22
Nama pengguna: new_username
Gunakan kunci SSH dan bukannya kata laluan untuk pengesahan?: ditandai
Laluan Deployment: /var/www/watchlist-tracker-app
Laluan pelaksanaan hendaklah lokasi pada pelayan anda di mana repo GitHub anda berada. Kini anda boleh meneruskan dan membuat pelayan. Jika anda menghadapi sebarang masalah maka ia mungkin disebabkan oleh tetapan tembok api anda jadi baca dokumentasi mengenai Alamat IP manakah yang harus saya benarkan melalui tembok api saya?.
Anda kini seharusnya melihat skrin Penerapan Baharu seperti yang ditunjukkan di sini:
Selepas penggunaan yang berjaya, anda harus ditunjukkan dengan skrin ini:
Langkah terakhir ialah menyediakan penggunaan automatik supaya apabila anda menolak perubahan daripada repositori tempatan anda ke GitHub, ia secara automatik digunakan ke pelayan jauh anda. Anda boleh melakukan ini dari halaman Penggunaan Automatik, yang terletak di bar sisi kiri akaun DeployHQ anda. Lihat contoh di sini:
Kita semua sudah selesai; tahniah, anda telah mempelajari cara membina aplikasi React timbunan penuh, menggunakan pangkalan kod ke GitHub, mengehos aplikasi pada VPS yang menjalankan Linux Ubuntu dan menyediakan penggunaan automatik dengan DeployHQ. Permainan pembangun anda telah meningkat tahap!
Ia cekap dan menyeronokkan untuk membina apl CRUD tindanan penuh seperti Penjejak Senarai Pantau dengan alatan dan teknologi moden. Kami menggunakan tindanan teknologi yang cukup kuat: Bun, Hono, Prisma ORM dan SQLite di bahagian belakang, manakala Vite, Tailwind CSS dan TanStack Router di bahagian hadapan membantu menjadikannya responsif dan berfungsi. Hetzner akan memastikan bahawa apl itu boleh dipercayai dan berprestasi baik tidak kira di mana pengguna berada.
Pengerahan oleh DeployHQ menjadikan penggunaan agak mudah. Anda hanya perlu menolak kemas kini terus dari repositori Git anda ke pelayan awan. Sebarang perubahan yang anda buat dalam repositori anda akan digunakan secara automatik ke pelayan pengeluaran anda supaya versi terkini aplikasi anda disiarkan secara langsung. Ini menjimatkan masa kerana penggunaan automatik mengurangkan bilangan ralat yang berkaitan dengan penggunaan, jadi ia patut ditambah pada sebarang bentuk aliran kerja pembangunan.
Tutorial ini sepatutnya membantu anda menggunakan semua jenis aplikasi ke pengeluaran menggunakan VPS seperti Hetzner dengan penggunaan git automatik terima kasih kepada DeployHQ.
Atas ialah kandungan terperinci Menggunakan Apl Penjejak Senarai Pantau React ke Pengeluaran Menggunakan DeployHQ. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!