今日のチュートリアルでは、サーバーをセルフホストしてセットアップする方法を学びます。これにより、あらゆる Web アプリケーションをオンラインでデプロイできるようになります。アプリケーションをオンラインで展開するには、いくつかの方法があります。 2 つの戦略には、VPS、仮想プライベート サーバー、および Vercel、Netlify、WordPress、GoDaddy などの共有マネージド ホスティング プラットフォームの使用が含まれます。
VPS は、他のユーザーと物理的に共有されるサーバー上に専用のサーバー リソースを提供する仮想マシンです。実際には、Web サイトとアプリケーションの中間層ホスティングであり、共有ホスティングと比較してより多くの制御とカスタマイズを提供します。 VPS ホスティング プラットフォームの例には、Hetzner、Akamai、Vultr、Cloudcone などがあります。
一方、マネージド ホスティング プラットフォームを使用すると、Web サイトをホスティングする方が簡単です。このようなプラットフォームは、Web アプリケーションを構築および展開するためのツール、ワークフロー、インフラストラクチャを提供します。これらのプラットフォームは、負荷分散とキャッシュを独自に実行します。これらは、追加の構成を行わずに、Web アプリケーションを迅速に構築してデプロイしたいと考えている開発者に適しています。
いつものように、各戦略の使用には長所と短所があります。最も大きな違いの 1 つは、VPS を使用すると、サーバー全体とそれに付属するすべてのものを制御できるため、完全なカスタマイズが可能になることです。これは、開発環境、ファイアウォール ルール、ホスティングなどのセットアップを意味します。このカスタマイズにより複雑さが増し、すべてを自分で行うため、より多くの技術サポートが必要になります。マネージド ホスティング プラットフォームは、ほとんどのツールが事前に設定されており、サポートとドキュメントが提供されるため、初心者にとって非常にフレンドリーであることを知っておく必要があります。すでに設定および管理されているため、VPS のような高度なカスタマイズはできません。
また、価格差も考慮する必要があります。ほとんどの VPS は有料ですが、サーバーを完全にカスタマイズして軽量にしたり、必要に応じて堅牢にしたりすることもできます。パフォーマンスの点では、どのマネージド ホスティング プラットフォームよりも優れています。後者には無料プランがあるため、違いを確認する必要があります。一般消費者は無料であるため、マネージド ホスティング プラットフォームを求めるでしょう。ただし、より多くのパワーが必要で、1 つのアプリケーション内で高度なアプリケーションをホストしたい場合は、VPS が最適です。
当社の Watchlist Tracker アプリケーションは、映画のウォッチリストを追跡するために使用される、単純だが強力なフルスタック CRUD アプリケーションです。このアプリケーションでは、ユーザーが見たい映画やシリーズを簡単に追加したり、映画のタイトルや評価を更新したり、すでに視聴した映画や追跡したくない映画を削除したりすることもできます。このアプリを使用すると、ユーザーはシンプルなインターフェースにアクセスして興味のある映画を整理し、最新情報を入手できるため、ウォッチリストで常に先を行きたい映画愛好家に適したツールとなります。
アプリがどのようなものかを以下で確認できます:
ホームページ
映画/シリーズアイテムページ
新しいアイテムの追加ページ
アプリケーションの構築を開始する前に、開発環境をセットアップして動作させることが重要です。マシンに以下がインストールされていることを確認してください:
VS Code には優れた無料の SQLite Viewer 拡張機能があり、コマンド ラインの使用と並行して便利です。データベース内のデータをすばやく表示するのに適しています。
当社のウォッチリスト トラッカー アプリは、非常に現代的で先進的な技術スタックを使用して構築されており、優れた開発エクスペリエンスを提供します。 Bun、Hono、Vite、TanStack、Hetzner、DeployHQ などのツールを使用することを選択したのは、これらのツールがすべて開発者に最新のビルド エクスペリエンスを提供するためです。
このプロジェクトで使用するテクノロジーを見てみましょう:
バックエンド
フロントエンド
ホスティングと展開
さて、アプリの構築を始めましょう!このセクションは 2 つの部分に分かれています。最初にバックエンドを作成し、次にフロントエンドを作成します。
watchlist-tracker-app というプロジェクト用にコンピューター上に新しいフォルダーを作成し、そこに cd してください。ここで、次に示すコマンドを使用して、バックエンド用の新しい Bun プロジェクトを作成します。
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
これでプロジェクトがセットアップされるはずです。依存関係をインストールし、構成に取り組み、サーバー コードを記述するだけです。コードエディタでプロジェクトを開きます。
次に、次のコマンドを使用してサーバーの依存関係をインストールします。
bun add hono prisma @prisma/client
ランタイム環境として Bun を、API サーバーとして Hono を、データベース ORM として Prisma を追加しました。
次のコマンドを使用して Prisma ORM と SQLite をセットアップしましょう:
npx prisma init
Prisma はサーバー内で動作するように設定されているはずなので、次のステップでデータベース スキーマを設定します。したがって、prisma/schema.prisma 内のすべてのコードを次のコードに置き換えます:
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 }
データベース スキーマが設定され、SQLite データベース ファイルに接続されています。
次に、この移行スクリプトを実行して SQLite データベースを作成します。
npx prisma migrate dev --name init
無事、Prisma の移行が完了したので、API ファイルで作業できるようになりました。
Hono を使用するメイン API ファイルを作成しましょう。 src/server.ts 内のサーバー ファイルに移動し、次のコードをファイルに追加します。
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;
このファイルを使用すると、サーバーは Bun と Hono を使用し、ポート 8000 で実行されます。また、ウォッチリスト トラッカーのすべての CRUD (作成、読み取り、更新、削除) エンドポイントも用意されています。すべてのデータは SQLite データベース内に保存されます。
残っているのは、サーバーの実行スクリプトと構築スクリプトを作成することだけです。次に、エンドポイントをテストして、期待どおりに動作することを確認します。これらの実行スクリプトを package.json ファイルに追加します:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
OK、ここで bun run start コマンドを実行すると、ターミナルに次のように表示され、サーバーが実行されていることを確認できるはずです。
Server is running on http://localhost:8000
コマンド bun run build を実行すると、本番環境で使用できる dist フォルダーが作成されます。これは、アプリケーションを Hetzner またはオンライン サーバーにデプロイするときに必要になります。
それでは、バックエンド エンドポイントを簡単にテストして、期待どおりに動作することを確認しましょう。次に、フロントエンドの作業を開始できます。テストするエンドポイントは 5 つあります: GET が 2 つ、POST が 1 つ、PUT が 1 つ、DELETE が 1 つです。 Postman を使用して API をテストします。
ウォッチリスト アプリ API POST エンドポイント
方法: POST
エンドポイント: http://localhost:8000/watchlist
これは POST エンドポイントで、映画/シリーズ データを含む JSON オブジェクトをデータベースに送信するために使用されます。
ウォッチリスト アプリ API GET すべてのエンドポイント
メソッド: GET
エンドポイント: http://localhost:8000/watchlist
これはプライマリ GET エンドポイントで、フロントエンドがフェッチするオブジェクトの配列を返します。データを含むオブジェクトの配列を返すか、まだデータベースにデータを送信していない場合は空の配列を返します。
ID エンドポイントによるウォッチリスト アプリ API GET
メソッド: GET
エンドポイント: http://localhost:8000/watchlist/3
これは、ID によってアイテムを取得するための GET エンドポイントです。そのオブジェクトのみを返し、項目が存在しない場合はエラーを表示します。
ウォッチリスト アプリ API PUT エンドポイント
メソッド: PUT
エンドポイント: http://localhost:8000/watchlist/3
これは、ID を使用してアイテムを更新するための PUT エンドポイントです。そのオブジェクトのみを返し、項目が存在しない場合はエラーを表示します。
ウォッチリスト アプリ API DELETE エンドポイント
メソッド: DELETE
エンドポイント: http://localhost:8000/watchlist/3
これは、ID を使用してアイテムを削除するための DELETE エンドポイントです。これは成功オブジェクトを返し、項目が存在しない場合はエラーを表示します。
つまり、API が稼働中です。これで、フロントエンド コードを開始できます。
watchlist-tracker-app のルート フォルダー内にいることを確認し、以下のスクリプトを実行して、すべてのパッケージと依存関係を備えた TypeScript 用に設定された Vite を使用して React プロジェクトを作成します。
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
このスクリプトは基本的に Bun ランタイム環境を使用してプロジェクトをインストールおよびセットアップします。必要なファイルとフォルダーはすべて作成されているので、コードを追加するだけです。スタイルに Tailwind CSS を使用するように Vite プロジェクトを設定し、データを取得する axios とフォームで日付変換を行う dayjs を使用したページ ルーティング用の TanStack Router を使用しました。
このビルド スクリプトのおかげで、作業が大幅に簡単になったので、コードをファイルに追加してみましょう。最初にいくつかの構成ファイルを示します。 tailwind.config.js ファイル内のすべてのコードを次のコードに置き換えます:
bun add hono prisma @prisma/client
このファイルはかなり説明的です。 Tailwind CSS がプロジェクト全体で機能するようにするには、このファイルが必要です。
ここで、src/index.css ファイル内のすべてのコードを次のコードに置き換えます。CSS ファイルで使用できるように、Tailwind ディレクティブを追加する必要があります。
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
これらのディレクティブを追加すると、すべての CSS ファイル内の Tailwind CSS スタイルにアクセスできるようになります。次に、App.css ファイル内の CSS コードは不要になったので、すべて削除します。
さて、最終的な設定ファイルを作成します。その後、ページとコンポーネントの作業に移ります。
次のコードをルート フォルダーの api.ts ファイルに追加します。
bun add hono prisma @prisma/client
このファイルは、フロントエンドがバックエンドで接続する必要があるエンドポイントをエクスポートします。バックエンド API は http://localhost:8000 にあることに注意してください。
わかりました。App.tsx ファイル内のすべてのコードを次の新しいコードに置き換えましょう:
npx prisma init
これはアプリのメイン エントリ ポイント コンポーネントであり、このコンポーネントはすべてのページのルートを保持します。
次に、主要なコンポーネントとページに取り組みます。 3 つのコンポーネント ファイルと 3 ページのファイルがあります。コンポーネントから始めて、次のコードをコンポーネント/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 }
このコンポーネントは、データベースに項目を追加するために使用されます。ユーザーはこのフォーム コンポーネントを使用して POST リクエストをバックエンドに送信します。
次に、components/FormField.tsx のコードを追加しましょう:
npx prisma migrate dev --name init
これはフォームの再利用可能なフォーム フィールド コンポーネントです。複数のフィールドに同じコンポーネントを使用できるため、コードを DRY に保つことができます。つまり、コードベースが小さくなります。
そして最後に、components/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;
このヘッダー コンポーネントにより、各ページにはメイン ナビゲーションを備えたヘッダーがあります。
残っているのは 3 ページだけで、アプリは完成です。したがって、次のコードをpages/AddItem.tsxに追加します:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
これは基本的に、フォーム コンポーネントを含むデータベースに項目を追加するためのページです。
それでは次に、pages/Home.tsx のコードを追加しましょう:
Server is running on http://localhost:8000
ご想像のとおり、これは私たちのホームページとなり、バックエンドに GET リクエストを送信し、データベース内のすべてのアイテムのオブジェクトの配列を取得します。
最後に、pages/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 ..
このページには、ID ごとに個別のアイテム ページが表示されます。データベースの項目を編集および削除するためのフォームもあります。
それだけです。アプリケーションを使用する準備ができました。バックエンドサーバーとクライアントサーバーの両方が実行されていることを確認してください。ブラウザーでアプリが実行されていることが確認できます: http://localhost:5173/.
フォルダー内で次のコマンドを使用して両方のサーバーを実行します:
module.exports = { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, plugins: [], };
わかりました、よくやった。私たちの申請は完了しました!それでは、GitHub にデプロイしてみましょう!
アプリケーションを GitHub にデプロイするのは非常に簡単です。まず、watchlist-tracker-app のルート フォルダー内に .gitignore ファイルを置きます。バックエンド フォルダーまたはクライアント フォルダーから .gitignore ファイルをコピーして貼り付けるだけです。次に、GitHub に移動し (アカウントをお持ちでない場合は作成してください)、watchlist-tracker-app のリポジトリを作成します。
watchlist-tracker-app のルート フォルダー内で、コマンド ラインを使用してコードベースをアップロードします。このコード例を参照して、独自のリポジトリに合わせて変更してください:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
最後に注意すべき重要な点が 1 つあります。コードを Hetzner にアップロードすると、localhost 経由でバックエンドにアクセスできなくなるため、API ルートを更新する必要があります。 const API_URL = 'http://localhost:8000'; という変数があります。上部の 2 つのファイルにあります。ファイルは api.ts とコンポーネント/AddItemForm.tsx です。変数 API URL を以下の URL に置き換えて、コードベースを GitHub に再アップロードします。
bun add hono prisma @prisma/client
これで終わりです。コードベースは GitHub 上でオンラインになっているはずです。これで、Hetzner へのデプロイに取り組むことができます。
ウォッチリスト トラッカー アプリが完成したので、今度はアプリケーションを Hetzner VPS プラットフォームにデプロイします。 Hetzner は有料プラットフォームですが、それが提供する多用途性は比類のないものです。最も安いプランは月額約 4.51 ユーロ/4.88 ドル/3.76 ポンドです。開発者は、学習、練習、運用展開などに使用できるため、自己ホスト型オンライン サーバーを用意する価値は十分にあります。サーバーのサブスクリプションはいつでもキャンセルでき、必要に応じて取り戻すことができます。
ほとんどの VPS は、Linux などの異なるオペレーティング システムを実行できるサーバーであるため、本質的には同じです。各 VPS プロバイダーはインターフェイスとセットアップが異なりますが、基本的な構造はまったく同じです。 Hetzner でアプリケーションをセルフホストする方法を学ぶことで、同じスキルと知識を簡単に再利用して、別の VPS プラットフォームにアプリケーションをデプロイできます。
VPS の使用例としては次のようなものがあります。
Hetzner の現在の価格はここで確認できます:
Hetzner の Web サイトにアクセスし、ページ中央にある赤いサインアップ ボタンをクリックします。または、右上隅にある「ログイン」ボタンをクリックすることもできます。 Cloud、Robot、konsoleH、DNS のオプションを含むメニューが表示されます。いずれかをクリックすると、ログインおよび登録フォーム ページに移動します。
これで、ログインと登録フォームのページが表示されるはずです。登録ボタンをクリックしてアカウントを作成し、サインアッププロセスを完了します。おそらく、PayPal アカウントを使用するか、パスポートを準備して、認証段階に合格する必要があります。
これで、アカウントにログインし、サーバーを作成および購入できるようになります。近くの場所を選択し、イメージとして Ubuntu を選択します。参考としてこの例を参照してください。
[タイプ] で [共有 vCPU] を選択し、サーバーの構成を選択します。少数のリソースのみを必要とする単純なアプリケーションをデプロイしています。必要に応じて、より優れたサーバーを自由に入手できます。それはあなた次第です。専用 vCPU はパフォーマンスが向上しますが、コストが高くなります。 x86 (Intel/AMD) プロセッサと Arm64 (Ampere) プロセッサのどちらかを選択することもできます。
デフォルト設定をそのまま使用できます。以下の例を参照してください。ただし、セキュリティ上の理由から、SSH キーを追加することが重要です。
SSH キーは、従来のパスワードよりも安全なサーバー認証方法を提供します。キーは OpenSSH 形式である必要があり、サーバーの高レベルのセキュリティが確保されます。オペレーティング システムに応じて、Google で「Mac で SSH キーを生成」または「Windows で SSH キーを生成」を検索できます。 Mac で SSH キーを生成するためのクイック ガイドを提供します。
まずターミナル アプリケーションを開き、次のコマンドを入力して、「your_email@example.com」を実際の電子メール アドレスに置き換えます。
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
-b 4096 の部分は、セキュリティを強化するためにキーが 4096 ビットであることを保証します。次に、プロンプトが表示されたらキーを保存します。デフォルトの場所を受け入れることも、カスタムの場所を選択することもできます:
bun add hono prisma @prisma/client
パスフレーズの設定はオプションです。この手順は省略できます。ここで、次のコマンドを実行して SSH キーを SSH エージェントにロードします:
まず、エージェントを起動します:
npx prisma init
次に、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 }
SSH 公開キーをクリップボードにコピーするには、次のコマンドを実行します。
npx prisma migrate dev --name init
これにより公開キーがコピーされ、Hetzner または SSH キーを必要とするその他のサービスに公開キーを追加できるようになります。 SSH キーをこのフォーム ボックスに貼り付けて追加します。
ボリューム、配置グループ、ラベル、またはクラウド構成については、このプロジェクトの範囲外であるため、心配する必要はありません。バックアップは役立ちますが、コストがかかるため、このプロジェクトではオプションです。ファイアウォールは後で実行するので、今は心配する必要はありません。サーバーの名前を選択し、現在の設定でサーバーを作成して購入すると、Hetzner アカウントの準備が整います。
わかりました、いいです。 Hetzner のアカウントができました。次のセクションでは、ファイアウォールを設定し、Linux オペレーティング システムを構成し、アプリケーションをオンラインにします。
Linux OS に SSH 接続する前に、まずファイアウォール ルールを設定しましょう。 SSH を使用できるようにするにはポート 22 を開く必要があります。また、ポート 80 は HTTP(ハイパーテキスト転送プロトコル)を使用するウェブサーバーのデフォルトのネットワーク ポートである TCP ポートであるため、ポート 80 を開く必要があります。 Web ブラウザとサーバー間の通信、Web コンテンツの送受信に使用されます。これが、アプリケーションをオンラインで動作させる方法です。
メイン メニューの [ファイアウォール] に移動し、以下に示す受信ルールを使用してファイアウォールを作成します。
ファイアウォールが機能しているので、Linux 環境をセットアップしてアプリケーションをデプロイできるので、次にそれを行いましょう。
ログイン用の SSH キーを作成したので、リモート Hetzner サーバーへの接続は非常に簡単です。ターミナルまたは VS Code などのコード エディターを使用して接続することもでき、これにより、コマンドラインを使用する必要がなく、ファイルをより簡単に作成できます。 Visual Studio Code リモート - SSH 拡張機能を使用したい場合は、そうすることができます。このプロジェクトでは、ターミナルにこだわります。
ターミナルを開き、次の SSH コマンドを入力してリモート サーバーにログインします。アドレス 11.11.111.111 を、サーバー セクションにある実際の Hetzner IP アドレスに置き換えます:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
サーバーにログインすると、ようこそ画面と IP アドレスなどのその他の個人情報が表示されます。ここでは画面のようこそ部分を示しています:
bun add hono prisma @prisma/client
わかりました、素晴らしいです。これで、アプリケーションをオンラインにする前に、開発環境をセットアップするいくつかのコマンドの実行をついに開始できるようになりました。ちなみに、終了してサーバーへの SSH 接続を閉じたい場合は、「exit」と入力して Enter ボタンをクリックするか、キーボード ショートカット Ctrl D を使用します。
最初に行う必要があるのは、Linux システム上のパッケージを更新してアップグレードすることです。これは 1 つのコマンドで実行できるので、次のコマンドをターミナルに入力して Enter キーを押します:
npx prisma init
次に、残りの開発パッケージと依存関係をインストールする必要があります。最初は Node.js と npm なので、次のコマンドを使用してインストールします。
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 }
次は Nginx で、リバース プロキシとして使用する必要があります。リバース プロキシは、クライアントとバックエンド サーバーの間に配置され、クライアントの要求を適切なバックエンド サーバーに転送し、サーバーの応答をクライアントに返すサーバーです。これは仲介者として機能し、受信リクエストを管理およびルーティングして、パフォーマンス、セキュリティ、およびスケーラビリティを向上させます。したがって、次のコマンドを使用してインストールします:
npx prisma migrate dev --name init
Git が必要になります。そのためには、GitHub からコードを取得し、リモート サーバーにアップロードする必要があります。したがって、次のコマンドを使用してインストールします:
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;
Bun ランタイムはアプリケーションの実行に役立ちます。まず、Bun をインストールする前に、必要に応じて unzip パッケージをインストールする必要があります。その後、Bun をインストールできます。必要なコマンドは次のとおりです:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
bun add hono prisma @prisma/client
同じ Hetzner サーバー上で React フロントエンドとバックエンド サーバーの両方を実行するには、両方のサービスを同時に管理する必要があります。これには通常、PM2 などのプロセス マネージャーをセットアップしてバックエンド サーバーを実行し、Nginx をリバース プロキシとして使用してフロントエンドとバックエンドの両方への受信リクエストを処理することが含まれます。
次のコマンドを使用して PM2 をインストールします:
npx prisma init
そうです、これで Linux 環境のセットアップは完了です。次のセクションでは、コードベースを GitHub からリモート サーバーにダウンロードし、アプリがオンラインで動作するように Nginx サーバーを構成します。
コマンドラインの操作方法をすでに知っていると仮定します。そうでない場合は、Google で調べてください。ディレクトリの変更やファイルの管理を行っていきます。まず、プロジェクトで GitHub リポジトリのクローンを作成し、それをリモート サーバーにコピーします。参考として以下のコマンドを使用してください:
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 }
Web アプリケーション ファイルは /var/www 内に保存されます。ファイルの一覧表示に使用されるコマンド ls と作業ディレクトリの出力に使用されるコマンド pwd を使用すると、Linux OS 上のすべてのファイルを表示できます。 Linux コマンド ラインの詳細については、初心者向けの Linux コマンド ラインに関するこのチュートリアルをご覧ください。
リモート サーバー上にアプリケーションが配置されたので、バックエンドとフロントエンドの実稼働ビルドを作成できます。これを行うには、watchlist-tracker-app プロジェクト内のフォルダー バックエンドとクライアントのルートに cd し、以下に示すコマンドを実行するだけです。
npx prisma migrate dev --name init
ランタイムとして Bun を使用しているため、インストールとビルドの手順には bun コマンドを使用します。
それでは、Nginx サーバーを構成しましょう。 nano ターミナル エディタを使用して、ファイル内にコードを記述します。ターミナルで次のコマンドを実行して、ウォッチリスト トラッカー アプリの Nginx ファイルを開きます:
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;
nano コード エディターに慣れていない場合は、このチートシートを確認してください。
この構成をコピーしてファイルに貼り付け、保存するだけです。必ず、server_name IP アドレスを自分の Hetzner IP アドレスに置き換えてください:
"scripts": { "start": "bun run src/server.ts", "build": "bun build src/server.ts --outdir ./dist --target node" },
Nginx は、リバース プロキシ サーバーの役割を果たすためによく使用されます。リバース プロキシは、クライアント (ユーザーのブラウザ) とバックエンド サーバーの間に位置します。クライアントからリクエストを受信し、それらを 1 つ以上のバックエンド サーバーに転送します。バックエンドがリクエストを処理すると、リバース プロキシはレスポンスをクライアントに転送します。このような設定では、Nginx が受信トラフィックのエントリ ポイントとなり、リクエストを特定のサービス (Vite フロントエンドや API バックエンドなど) にルーティングします。
Vite 製品プレビュー ビルドはポート 4173 で実行され、バックエンド サーバーはポート 8000 で実行されます。これらの値を変更する場合は、この Nginx 構成ファイルでも必ず更新してください。そうしないと、サーバーが機能しません。
Nginx サイトがまだ有効になっていない場合は、次のコマンドを使用して有効にします:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
次に、Nginx 構成をテストして構文エラーがないことを確認し、次のコマンドで Nginx を再起動して変更を適用します。
bun add hono prisma @prisma/client
もうすぐ終わります。あと一歩です。ここでブラウザで Hetzner IP アドレスにアクセスすると、502 Bad Gateway のようなエラーが表示されるはずです。それは、まだ実行中のサーバーがないためです。まず、PM2 を使用して両方のサーバーを同時に実行する必要があります。したがって、アプリケーションが常にオンラインになるように、システムの起動時に PM2 が起動するように設定する必要があります。これを行うには、ターミナルで次のコマンドを実行します。
npx prisma init
次に、バックエンド サーバーとフロントエンド サーバーを実行する必要があります。これらのコマンドは、フォルダーのルート内から実行します。
バックエンドサーバーから始めましょう。ターミナルで次のコマンドを実行します。
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 }
最後に、クライアント フロントエンド サーバーを実行しましょう。ターミナルで次のコマンドを実行します。
npx prisma migrate dev --name init
以下に示すように、コマンド pm2 status を実行して、両方のサーバーがオンラインで実行中であるかどうかを確認できます。他のすべての PM2 コマンドについて詳しくは、PM2 プロセス管理クイック スタートに関するドキュメントをお読みください:
ターミナルでこれらのcurlコマンドを実行することで、サーバーが到達可能かどうかをテストできます。 HTML コードが機能している場合は、HTML コードを返す必要があります:
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;
Hetzner サーバーの IP アドレスに移動します。すべてを正しく実行すると、アプリがデプロイされ、オンラインになっていることがわかります。通常、Web サイトにはドメイン名があり、IP アドレスは検索バーには表示されません。開発者がドメインを購入し、ネームサーバーを変更してホストのサーバーに接続することは非常に一般的です。これはこのチュートリアルの範囲を超えていますが、Google 検索を行うことで簡単にその方法を学ぶことができます。 Namecheap は私の優先ドメイン登録です。
そうです、完成に非常に近づいています。最後のステップは、DeployHQ を使用して展開プロセスを合理化することです。 DeployHQ を使用すると、展開が簡単になり、セキュリティの点でも優れています。オンライン サーバー上のコードベースを更新する従来の方法は、git pull を使用して GitHub リポジトリから最新の変更を取得することです。ただし、git pull を実行することは、git フォルダーが公開される可能性があり、Web サイトが縮小されたり、醜くなったりする可能性が低いため、良い習慣ではありません。
DeployHQ はここで重要な役割を果たします。変更されたファイルを構成されたフォルダーに安全にコピーし、サーバー上の git ログに変更が表示されないようにします。これはトレードオフのように思えるかもしれませんが、展開の安全性を保証するセキュリティ機能です。 Vercel や Netlify などのプラットフォームに精通している場合は、これらの自動デプロイメントが非常に似ていることがわかるでしょう。この場合、VPS 上の任意のオンライン サーバーと連携できるセットアップが完了しました。
言及する価値のあることの 1 つは、オンライン Linux リモート サーバー用に非 root ユーザーを作成することが重要であるということです。 root ユーザーとしてサインインすることが常にベスト プラクティスであるとは限りません。別のユーザーに同様の権限を設定してもらうことをお勧めします。 DeployHQ では、サインインに root ユーザーを使用することも推奨しません。 DeployHQ が機能するには、SSH を使用してアカウントにサインインする必要があります。 DeployHQ SSH 公開キーをオンライン Ubuntu サーバーに配置する必要があるため、DeployHQ アカウントを取得した後でこれを行います。
DeployHQ では、初めてサインアップすると、義務なしで 10 日間、すべての機能に無料でアクセスできます。その後、アカウントは無料プランに戻り、1 つのプロジェクトを 1 日最大 5 回デプロイできるようになります。
まず、DeployHQ Web サイトにアクセスし、以下に表示されるボタンのいずれかをクリックしてアカウントを作成します。
OK、[DeployHQ へようこそ] 画面に [プロジェクトの作成] ボタンが表示されるはずです。ボタンをクリックして、次のようなプロジェクトを作成します:
次の画面では、新しいプロジェクトを作成する必要があります。したがって、名前を付けて、GitHub リポジトリを選択してください。また、プロジェクトのゾーンを選択して、プロジェクトを作成します:
以下に示すように、サーバー画面が表示されるはずです。これは、root ユーザーに依存する必要がないように、リモート サーバー用に別の Linux ユーザーを作成する時期が来たことを意味します。
まず、root ユーザーとしてサーバーにログインし、以下のコマンドを使用して新しいユーザーを作成します。 new_username を、新しいユーザーに使用するユーザー名に置き換えます:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
パスワードの設定を求められ、氏名、部屋番号などの詳細を入力するよう求められます。設定する必要があるのはパスワードのみです。他のプロンプト手順をスキップし、すべて終了するまで Enter キーを押して空白のままにすることができます。
新しいユーザーを sudo グループに追加して、root ユーザーのような管理者権限を付与できるようにすることもお勧めします。ここに示すコマンドを使用してこれを実行します:
mkdir backend cd backend bun init -y mkdir src touch src/server.ts
新しいユーザーにはサーバーへの SSH アクセスが必要です。まず新しいユーザーに切り替えて、次のコマンドを使用してそのユーザー用の .ssh ディレクトリを作成します。
bun add hono prisma @prisma/client
次に、ローカルの公開キーをサーバー上のauthorized_keysに追加する必要があります。そのため、ローカルマシン上で次のコマンドを使用して公開キーをコピーします。
npx prisma init
サーバー上で、authorized_keys ファイルを開き、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 }
コピーした公開キーをこのファイルに貼り付けます。ファイルを保存する前に、サーバー ページから DeployHQ SSH キーをコピーして同じファイルに貼り付けます。 認証にパスワードではなく SSH キーを使用しますか? のチェックボックスをオンにすると、SSH キーが表示されます。ファイルを保存し、次のコマンドを使用してファイルに正しいアクセス許可を設定します:
npx prisma migrate dev --name init
これで、新しいユーザーの SSH ログインをテストできるようになりました。まず、リモート サーバーからログアウトし、再度ログインを試みます。ただし、今回は root ではなく、作成した新しいユーザーを使用します。以下の例を参照してください:
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;
すべてが正しく行われたと仮定すると、新しいユーザーでログインできるはずです。
これで、ようやくサーバー フォームを完成させることができます。フォームに情報を入力してください。以下の例を参照してください:
名前: ウォッチリスト トラッカー アプリ
プロトコル: SSH/SFTP
ホスト名: 11.11.111.111
ポート: 22
ユーザー名: new_username
認証にパスワードではなく SSH キーを使用しますか?: チェック済み
展開パス: /var/www/watchlist-tracker-app
デプロイメント パスは、GitHub リポジトリが存在するサーバー上の場所である必要があります。これで、サーバーを作成できます。問題が発生した場合は、ファイアウォール設定が原因である可能性があるため、「どの IP アドレスをファイアウォールで許可する必要がありますか?」に関するドキュメントをお読みください。
次に示すように、[新しいデプロイメント] 画面が表示されます。
デプロイが成功すると、次の画面が表示されます。
最後のステップは、ローカル リポジトリから GitHub に変更をプッシュするときに、変更がリモート サーバーに自動的にデプロイされるように自動デプロイメントを設定することです。これは、DeployHQ アカウントの左側のサイドバーにある [自動展開] ページから行うことができます。ここの例を参照してください:
これですべて完了です。おめでとうございます。フルスタックの React アプリケーションを構築し、コードベースを GitHub にデプロイし、Linux Ubuntu を実行する VPS でアプリケーションをホストし、DeployHQ を使用して自動デプロイメントを設定する方法を学習しました。開発者のゲームがレベルアップしました!
最新のツールとテクノロジーを使用して、Watchlist Tracker のようなフルスタック CRUD アプリを構築するのは効率的で楽しいものです。バックエンドには Bun、Hono、Prisma ORM、SQLite を使用し、フロントエンドには Vite、Tailwind CSS、TanStack Router を使用して応答性と機能性を高めました。 Hetzner は、ユーザーがどこにいてもアプリの信頼性とパフォーマンスが良好であることを保証します。
DeployHQ によるデプロイメントにより、デプロイメントが非常に簡単になります。更新を Git リポジトリからクラウド サーバーに直接プッシュするだけです。リポジトリに加えた変更はすべて実稼働サーバーに自動的にデプロイされるため、アプリケーションの最新バージョンが稼働します。これにより、自動デプロイメントによりデプロイメントに関連するエラーの数が削減され、時間を節約できるため、あらゆる形式の開発ワークフローに追加する価値があります。
このチュートリアルは、DeployHQ による自動 git デプロイメントを備えた Hetzner のような VPS を使用して、あらゆる種類のアプリケーションを運用環境にデプロイするのに役立ちます。
以上がDeployHQ を使用した React Watchlist Tracker アプリの運用環境へのデプロイの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。