4-1. WEB&アプリサーバーの設計
4-2. Nginx 初期セットアップ
4-3. SSLサーバー証明書の取得と自動更新
4-4. Node.js サーバーの初期設定
4-5. はじめてのAPIプログラミング
4-6. ExpressフレームワークでAPIプログラミング
4-7. バックエンドAPIアプリの永続化
4-8. 天気を取得するAPIアプリを実行する
WEBアプリは、スマホやPCのアプリ画面(WEBフロントエンド)、データを処理するしくみ(バックエンドAPIアプリ)、そしてデータを保存する場所(データベース)の3つの役割に分かれています。
バックエンドAPIアプリには、たとえばログイン機能(/login)やユーザー情報を検索する機能(/users)などの機能を持たせることができます。API=サーバー側で動くアプリ。
本章では、まず「こんにちは」といったメッセージを返す簡単な機能から始めて、少しずつデータベースに接続して情報を読み出すしくみまでをコーディングで体験します。
前提:WEB/APPサーバーは、ドメイン・DNSが設定されていること。つまり、Linuxユーザー名とドメイン名を使って、SSH接続できる状態になっていること。

4-1. WEB/APPサーバーの設計
本学習プロジェクトでは、WEBフロントエンドとバックエンドAPIサーバーは1台のLinuxサーバーにまとめてホスティングします。
そのため、バックエンドAPIサーバーを準備する前に、WEBサーバーのHTTPSによる暗号化通信を先に設定する方が簡単かつ実用的です。
さらに1つのWEBサーバーに複数のWEBサイトをホスティングするマルチサイト設定も体験します。
なお、WEB&アプリサーバーのことを略して「WEB/APPサーバー」と表記する場合もあります。APPはApplicationの略ですね。
WEB&アプリサーバーの構成
- WEBサーバーには、Nginxという、WEBページを配信するためのソフトウェアをインストールします
- APIサーバーには、Node.jsという、データを処理するアプリ用のソフトウェアをインストールします

4-2. Nginx 初期セットアップ
Nginx のインストール
$ sudo apt update
$ sudo apt install nginx
Nginx 起動と自動起動
$ sudo systemctl start nginx
$ sudo systemctl enable nginx
動作確認
$ curl http://localhost
# 成功するとhtmlソースが表示される
<html><title>welcome to nginx! ...
マルチWEBサイトを設定する
$ sudo nano /etc/nginx/sites-available/ドメイン名(例:web.hogehoge.com)
# ファイルに追記する設定値
server {
listen 80;
server_name web.hogehoge.com;
location /site1 {
root /home/ユーザ名/www1;
index index.html;
}
location /site2 {
root /home/ユーザ名/www2;
index index.html;
}
}
Nginx ユーザ(www-data)が wwwディレクトリにアクセスできるようにする
#サブディレクトリ含め全て[rwx,r-x,r-x]
$ sudo chmod -R 755 /home/ユーザ名/www
# 親フォルダにも実行権限を追加
$ sudo chmod 701 /home/ユーザ名
# 所有者を追加
$ sudo chown -R ユーザ名:www-data /home/ユーザ名/www
WEBを有効化する
# 該当サイトが表示されるか検査
$ ls -l /etc/nginx/sites-enabled/
# 無効ならば
$ sudo ln -s /etc/nginx/sites-available/web.hogehoge.com /etc/nginx/sites-enabled
# Nginxを再起動する
$ sudo systemctl reload nginx
4-3. SSLサーバー証明書の取得と自動更新
前提:インターネット公開済みサーバー。ドメイン取得&DNS設定済み。TCP80(http)でアクセスできること。
無料 Let’s Encrypt を使う。
Let’s Encrypt のクライアント[certbot]をインストール
$ sudo apt install certbot python3-certbot-nginx -y
Nginx 設定を更新
$ sudo nano /etc/nginx/sites-available/default
ファイルの中身
server {
listen 80;
server_name hogehoge.com www.hogehoge.com;
root /home/ユーザ名/www;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Nginx 再起動
$ sudo systemctl restart nginx
TLS証明書を取得
$ sudo certbot --nginx -d hogehoge.com -d www.hogehoge.com
自動更新できるか検査
$ sudo certbot renew --dry-run
# 応答例:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ome.funnygeekjp.com.conf
Simulating renewal of an existing certificate for ome.funnygeekjp.com
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/ome.funnygeekjp.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
念のため更新日時も確認
$ systemctl list-timers | grep certbot
応答例:
Mon 2025-08-25 03:51:58 JST 5h 55min Sun 2025-08-24 21:53:43 JST 3min 1s ago certbot.timer certbot.service
証明書の存在を検査
$ cd /etc/letsencrypt/live/aaa.hogehoge.com/
cert.pem サーバー証明書
chain.pem 中間証明書
fullchain.pem サーバー証明書と中間証明書を結合したもの
privkey.pem 秘密鍵
Nginx 設定ファイルにSSL証明書の場所を教える
$ sudo nano /etc/nginx/sites-available/aaa.hogehoge.com
追加する内容:
server {
listen 443 ssl;
server_name aa.hogehoge.com;
ssl_certificate /etc/letsencrypt/live/aa.hogehoge.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/aa.hogehoge.com/privkey.pem;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
TCP80→443 リダイレクトも追加する:
server {
listen 80;
server_name ome.funnygeekjp.com;
return 301 https://$host$request_uri;
}
4-4. Node.js サーバーの初期設定
OSパッケージを更新
$ sudo apt update && sudo apt upgrade -y
nvm (node Version Manager)をダウンロードしてインストールする
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
インストールできたことを検査する
$ nvm --version # 例えば 0.40.3が表示される
Node.jsをダウンロードしてインストールする
$ nvm install 24
Downloading and installing node v24.7.0...
Node.jsのバージョンを確認する
$ node -v # 例えば "v24.7.0"が表示される。
npmのバージョンを確認する
$ npm -v # 例えば "11.5.1"が表示される。
4-5. はじめてのAPIプログラミング
新しいファイル[hello.js]を作成し、下記コードを記述します。ポート番号は、任意設定し、ファイアウォールで許可すること。
$ cd ~/app
$ nano hello.js
// Node.js の HTTPモジュールをインポート
const http = require('http');
// Appサーバーを作成
const server = http.createServer((req, res) => {
res.statusCode = 200; // HTTPステータスコード(成功: 200)
res.setHeader('Content-Type', 'text/html; charset=utf-8;'); // 応答するコンテンツタイプ:
res.end('こんにちは。かのです。'); // レスポンスに文字列を返す
});
// サーバーをポート3001で起動
const PORT = 3001;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
Node.js で はじめてのAPIを起動します。
$ cd ~/app
$ node hello.js
ブラウザでAPIにアクセスします
http://サーバーのIPアドレス:3001/
もしくは
http://サブドメイン:3001/
成功した場合の例

APIを改造
URLのクエリパラメータ[/?text=”たらーん”]を取得して、テキストの値を処理できることを体験します。
http.createServer() 関数を下記の通り改造します。
// Appサーバーを作成
const server = http.createServer((req, res) => {
const parsedUrl = new URL(req.url, `http://${req.headers.host}`);
const text = parsedUrl.searchParams.get('text') || '(テキストなし)'; // GETメソッドを使う
res.statusCode = 200; // HTTPステータスコード(成功: 200)
res.setHeader('Content-Type', 'text/html; charset=utf-8;'); // 応答するコンテンツタイプ(text/html)と文字コード:
res.write(`${text}\n`);
res.end('こんにちは。かのです。'); // レスポンスに文字列を返す
});
ブラウザのURLでクエリパラメータを指定してAPIにアクセスします
http://サーバーのIPアドレス:3001/?text="たらーん"
もしくは
http://サブドメイン:3001/?text="たらーん"
成功した場合の例

4-6. ExpressフレームワークでAPIプログラミング
Expressは、Node.jsでWebアプリやAPIを作るときに使う便利なツール(フレームワーク)です。
たとえば「このURLにアクセスされたらこう返す」「このデータを受け取って保存する」といった処理を、シンプルなコードで書けるようになります。
Expressモジュールをインストールします
$ npm init -y
$ npm install express
新しいファイル[hello-express.js]を作成し、下記コードを記述します
$ cd ~/app
$ nano hello-express.js
// 必要なモジュールを読み込む
const express = require('express');
const app = express();
// ルート "/" にアクセスしたときのレスポンス
app.get('/', (req, res) => {
res.send('いえーい');
});
// サーバーをポート3000で起動
const PORT = 3000;
app.listen(PORT, () => {
console.log(`API待ち受け http://localhost:${PORT}/`);
});
Node.js で はじめてのAPIを起動します。
$ cd ~/app
$ node hello-express.js
ブラウザでAPIにアクセスします

APIを改造
URI(Uniform Resource Identifier)を追加します。Web上の機能を表すものです。
Webブラウザやアプリは、このURIを使って目的のデータやサービスにアクセスします。
URIには、プロトコル・ホスト名・パス・クエリなどが含まれ、これらを組み合わせてリソースを一意に指定します。
app.get()関数を追加します。
app.get('/weather', (req, res) => {
const weatherOptions = ['晴れ', 'くもり', '雨'];
const randomWeather = weatherOptions[Math.floor(Math.random() * weatherOptions.length)];
res.send(randomWeather);
});
ブラウザで追加したURIにアクセスします。何度かリロードして、表示されるテキストが変わることを検査します

app.get()関数を少しだけ解説
app.get()はExpressモジュールの機能です。HTTPのGETリクエストを処理するルーティングメソッドのこと。
app.get(‘/’, (req, res) => { }); という形式で記述し、reqが入力、resが出力。RequestとResponseですね。
- res.send()は、データをまとめて送信し、自動終了する。
- res.write()は、データを分割して送信できる。複数回実行できる。res.end()と組み合わせないとレスポンスが終了しない。
- res.end()は、データを送信しつつ、レスポンスを終了する。
例:
app.get('/hello', (req, res) => {
res.send('こんにちは!'); // これ1行でOK
});
app.get('/stream', (req, res) => {
res.write('ページの先頭\n'); // 書いて
res.write('途中の内容\n'); // 書いて
res.end('最後の行'); // ここで終了
});
レスポンスの応用例:
- JSON形式で送る:
res.send({ message: 'こんにちは', status: 200 });
- 配列で送る:
res.send(['Apple', 'Banana', 'Orange']);
- 画像などバイナリデータを送る:
const fs = require('fs');
const file = fs.readFileSync('./image.png');
res.send(file); // バイナリデータとして送信
- HTML形式で送る:
res.send('<h1>こんにちは</h1><p>ここがメッセージです</p>');
- ステータスコードと一緒に送る:
res.status(404).send('Not Found');
- 変数を送る:
res.write( `${req.query.text}\n`);
4-7. バックエンドAPIアプリの永続化
APIアプリを毎回[$ node app.js]で起動していると、APIアプリを止めている間は、使いたいときに使えません。
プロセス管理[pm2]を使うと、アプリを永続的に実行できます。アプリをバックグランドで動作させたり、OS再起動後も自動起動したりできます。
$ npm install -g pm2 # pm2のインストール
$ pm2 start app.js --name my-app # app.jsというコードを、my-appという名前で起動
$ pm2 save # 現在の設定を保存
$ pm2 startup # OS起動時にpm2を自動起動する
アプリのコードを変更したら再起動が必要です。
$ pm2 restart my-app
pm2で起動しているアプリの一覧を表示する
$ pm2 list
アプリを停止する
$ pm2 stop my-app # 名前で停止
$ pm2 stop 0 # プロセスIDで停止
pm2によるアプリの起動を削除する。
$ pm2 delete my-app # 指定したアプリを削除
$ pm2 delete all # 全て削除
4-8. 天気を取得するAPIアプリを実行する
const express = require('express');
const axios = require('axios');
const app = express();
// weathercode を日本語に変換するマップ
const weatherMap = {
0: '快晴☀️',
1: '晴れ☀️',
2: '薄曇り⛅',
3: '曇り☁️',
45: '霧',
48: '霧(霧雨)',
51: '弱い霧雨',
53: '中程度の霧雨',
55: '強い霧雨',
61: '弱い雨🌂',
63: '中程度の雨☂️',
65: '強い雨☔',
71: '弱い雪',
73: '中程度の雪',
75: '強い雪',
80: 'にわか雨🌧️',
81: '強いにわか雨⛈️',
82: '激しいにわか雨⛈️',
95: '雷雨',
96: '雷雨(弱い雹)',
99: '雷雨(強い雹)'
};
app.get('/weather', async (req, res) => {
try {
const latitude = 35.789;
const longitude = 139.263;
const url = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true`;
const response = await axios.get(url);
const weather = response.data.current_weather;
const description = weatherMap[weather.weathercode] || '不明';
res.send(`天気: ${description}, 気温: ${weather.temperature}℃`);
} catch (error) {
res.status(500).send('天気情報の取得に失敗しました');
}
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`API待ち受け http://localhost:${PORT}/`);
});
この章は以上です
