作ったHTMLファイルをダブルクリックで開いたら、読み込んだはずのJavaScriptが動かなかった。そんな経験はありませんか?
ブラウザでファイルを直接開くと、アドレス欄はfile://で始まります。この状態では、ブラウザの安全上の制限でfetch()などの一部の機能がうまく動かないことがあるのです。
こういうときに役立つのが、Pythonに最初から入っているhttp.serverモジュールです。インストールは不要で、コマンドを1行打つだけで手元にWebサーバーが立ち上がります。
この記事では、http.serverの基本的な使い方から、Pythonコードで起動する方法、そして意外と知られていない落とし穴までを順番に見ていきます。サンプルの実行結果は、手元のPython 3.11で確かめたものです。
そもそもhttp.serverは何をしてくれるのか¶
まずは、http.serverがどんな道具なのかを押さえておきましょう。ひと言でいうと、指定したフォルダの中身をブラウザから見られるようにする小さなWebサーバーです。
Webサーバーとは、ブラウザからのお願いを受け取って、ファイルやページを返すプログラムのことです。サーバーという言葉自体がまだぼんやりしている方は、先にこちらを読んでおくとイメージがつかみやすくなります。
【関連記事】そもそもサーバーって何?Pythonアプリを公開する前に知りたい基礎知識
http.serverは標準ライブラリの一部なので、Pythonが入っていればそのまま使えます。pipで何かを追加する必要はありません。
ただし、公式ドキュメントには本番環境での利用は推奨しないという警告がはっきり書かれています。基本的なセキュリティチェックしか実装していないからです。
つまり、http.serverは自分のパソコンで動作を確かめるための道具だと考えてください。この前提を頭に入れておくと、あとで出てくる落とし穴の話もすっと理解できます。
python -m http.serverで今すぐサーバーを立てる¶
さっそく動かしてみましょう。公開したいフォルダにターミナルで移動して、次のコマンドを実行します。
python -m http.server
macOSやLinuxではpython3、Windowsではpyと打つ場合もあります。実行すると、次のような表示が出て待ち受け状態になります。
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
0.0.0.0の部分は、環境によっては::と表示されることもあります。どちらも、すべての接続口で待ち受けているという意味です。
この状態で、ブラウザのアドレス欄にhttp://localhost:8000/と入力してみてください。フォルダの中身が一覧で表示されるはずです。
-mは、モジュールをスクリプトとして実行するためのオプションです。pipをpython -m pipで動かすのと同じ仕組みだと考えるとわかりやすいでしょう。
止めたいときは、ターミナルでCtrl+Cを押します。表示が消えてプロンプトが戻れば、サーバーは停止しています。
index.htmlがあるとページが表示される¶
フォルダの中にindex.htmlという名前のファイルがあると、一覧ではなくそのページが表示されます。これはhttp.serverの中で使われているSimpleHTTPRequestHandlerが、index.htmlとindex.htmを優先して探す作りになっているためです。
つまり、自作のWebページのフォルダでサーバーを立てれば、トップページがそのまま開きます。HTMLやCSS、JavaScriptの練習には、これだけで十分なことも多いはずです。
アクセスするたびにログが流れる¶
ブラウザでページを開くと、ターミナルに1行ずつログが表示されます。誰がいつ、どのファイルを要求し、どんな結果だったかが記録されていきます。
127.0.0.1 - - [27/Oct/2026 20:12:06] "GET / HTTP/1.1" 200 -
末尾の200は、ちゃんと返せたことを表すステータスコードです。画像が表示されないときは、ここが404になっていないかを見ると原因がすぐにわかります。
よく使うオプションを表で整理する¶
http.serverのコマンドには、いくつかのオプションがあります。Python 3.11でpython -m http.server --helpを実行すると確認できる主なものを、表にまとめました。
| オプション | 意味 | 既定値 | 追加されたバージョン |
|---|---|---|---|
| ポート番号(例: 8080) | 待ち受けるポート | 8000 | 当初から |
| -b / --bind | 待ち受けるアドレス | すべてのインターフェース | 3.4 |
| -d / --directory | 公開するフォルダ | 今いるフォルダ | 3.7 |
| -p / --protocol | 準拠するHTTPのバージョン | HTTP/1.0 | 3.11 |
| --cgi | CGIサーバーとして動かす | 無効 | 非推奨 |
組み合わせると、次のような書き方ができます。ポート8080で、publicフォルダだけを、自分のパソコンからのアクセスに限って公開する例です。
python -m http.server 8080 --bind 127.0.0.1 --directory public
--directoryを使えば、わざわざcdで移動しなくても公開するフォルダを指定できます。プロジェクトの中のビルド結果のフォルダだけを見たいときに便利です。
また、Python 3.14では--tls-certなどのオプションが加わり、HTTPSで配信することもできるようになりました。証明書の準備が必要なので、学習の段階ではまずHTTPで慣れておけば十分です。
Pythonのコードからサーバーを起動する¶
コマンドだけでなく、Pythonのプログラムの中からサーバーを立てることもできます。テストのために一時的にサーバーを動かしたい場面などで役立つ書き方です。
次のコードは、siteフォルダを配信するサーバーを別スレッドで起動し、自分でアクセスして中身を確かめてから止める例です。
import threading
import urllib.request
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
# siteフォルダだけを配信するハンドラーを作る
handler = partial(SimpleHTTPRequestHandler, directory="site")
server = ThreadingHTTPServer(("127.0.0.1", 8000), handler)
# serve_forever()は止まるまで戻らないので、別スレッドで動かす
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
print("起動しました: http://127.0.0.1:8000/")
with urllib.request.urlopen("http://127.0.0.1:8000/") as res:
print(res.status, res.headers["Content-Type"])
print(res.read().decode("utf-8"))
server.shutdown() # serve_forever()のループを止める
server.server_close() # 使っていたポートを解放する
siteフォルダに<h1>hello</h1>と書いたindex.htmlを置いて実行すると、200 text/htmlのあとにHTMLの中身が表示されました。
ここで少しだけ見慣れない書き方が出てきたので、ポイントを2つに分けて説明します。
partialで公開するフォルダを渡している¶
HTTPServerは、ハンドラーのクラスそのものを受け取り、アクセスのたびに中で呼び出します。そのため、directory="site"のような引数を自分で渡すタイミングがありません。
そこでfunctools.partialを使い、引数をあらかじめ埋め込んだ呼び出し方を作って渡しています。partialの考え方は、こちらの記事でくわしく紹介しています。
【関連記事】Pythonのfunctoolsとは?lru_cacheやpartialで関数を速く短くする使い方を初心者向けに解説
ThreadingHTTPServerを選んでいる理由¶
ThreadingHTTPServerは、アクセスごとにスレッドを分けて処理するサーバーで、Python 3.7で追加されました。ふつうのHTTPServerは1件ずつ順番に処理するので、ブラウザが同時に何本も接続してくると待たされることがあります。
ちなみに、python -m http.serverで起動したときも、内部ではThreadingHTTPServerをもとにしたサーバーが使われています。コードで書くときも、特に理由がなければこちらを選んでおけば安心です。
.envや.gitまで丸見えになる落とし穴¶
ここからが今回いちばん伝えたい話です。http.serverは、公開したフォルダの中のファイルを隠しファイルも含めて区別なく配信します。
試しに、先ほどのsiteフォルダにSECRET=abcと書いた.envを置いて、http://127.0.0.1:8000/.envにアクセスしてみました。結果は200で、中身のSECRET=abcがそのまま返ってきました。
これがプロジェクトのフォルダだったらどうなるでしょうか?APIキーを書いた.envも、変更履歴の詰まった.gitフォルダも、URLさえ打てば誰でも読めてしまいます。
APIキーを.envで管理する方法そのものは、とても良い習慣です。だからこそ、そのフォルダをうっかり公開しないように気をつけたいところです。
【関連記事】環境変数とは?PythonでAPIキーを安全に扱う.envと os.environ の基本を初心者向けに解説
さらに注意したいのが、待ち受けるアドレスの既定値です。--bindを指定しないとすべてのインターフェースで待ち受けるので、同じWi-Fiにつながった他の人のパソコンからもアクセスできる可能性があります。
カフェや勉強会の会場で何気なくサーバーを立てると、手元のファイルを周りに配っているのと同じ状態になりかねません。対策は次の表のとおりです。
| 起きること | 対策 |
|---|---|
| 隠しファイルまで配信される | 公開用のフォルダを分けて--directoryで指定する |
| 同じネットワークの他人から見える | --bind 127.0.0.1を付けて自分専用にする |
| 立てたまま忘れてしまう | 確認が終わったらすぐCtrl+Cで止める |
私は10年ほどエンジニアとして開発に関わってきましたが、以前、社内の共有ネットワークで後輩がプロジェクト全体をhttp.serverで公開したままにしていたことがありました。たまたま気づいて止めましたが、設定ファイルにはテスト用のパスワードが書かれていて、ひやりとしたのを覚えています。
公開するフォルダは必要なものだけに絞る。これを習慣にしておけば、この落とし穴はほとんど避けられます。
よくあるエラーとつまずきポイント¶
http.serverはシンプルな道具ですが、初めて使うときに引っかかりやすい場面がいくつかあります。代表的なものを見ていきましょう。
Address already in useと言われたら¶
サーバーを立てようとしたら、次のようなエラーで止まることがあります。これはLinuxでの表示で、OSによってメッセージは少し変わります。
OSError: [Errno 98] Address already in use
これは、使おうとしたポートを別のプログラムがすでに使っているという意味です。前に立てたサーバーを止め忘れていることが多いので、別のターミナルを確認してみてください。
すぐに試したいだけなら、python -m http.server 8001のようにポート番号を変えるのがいちばん手軽です。
変更したのにページが変わらない¶
HTMLを書き換えたのに表示が古いままのときは、ブラウザのキャッシュが原因のことがよくあります。強制再読み込みをするか、開発者ツールでキャッシュを無効にしてから確かめましょう。
http.serverには、ファイルの変更を検知して自動で再読み込みする機能はありません。そうした便利さが欲しくなったら、専用の開発用ツールを検討するタイミングです。
日本語のファイルが文字化けする¶
テキストファイルを開いたときに日本語が化ける場合は、ファイルの文字コードとブラウザの解釈が食い違っていることがあります。HTMLなら、先頭に<meta charset="utf-8">を書いておくのが確実です。
http.serverとWebフレームワークの使い分け¶
最後に、http.serverがどこまで使える道具なのかを整理しておきます。ファイルを返すだけなら十分ですが、ログイン機能やデータベースとのやり取りが必要になると話が変わります。
| 目的 | 向いている道具 |
|---|---|
| 作ったHTMLやCSSを手元で確かめる | http.server |
| 同じ部屋の人にファイルを一時的に渡す | http.server(短時間だけ) |
| フォームやログインのあるWebアプリを作る | FlaskやDjangoなどのフレームワーク |
| インターネットにサービスを公開する | Webサーバーと本番用の実行環境 |
Webアプリを作りたくなったら、次の一歩としてFlaskに触れてみるのがおすすめです。ルーティングやテンプレートなど、http.serverにはない仕組みが一通りそろっています。
【関連記事】PythonのFlaskとは?WebアプリをPythonで動かす仕組みを初心者向けに解説
http.serverで、ブラウザとサーバーがリクエストとレスポンスをやり取りする様子を一度体験しておく。それだけで、フレームワークの説明が驚くほど読みやすくなります。
実際、私が新人のころにWebの仕組みがやっと腹落ちしたのも、ターミナルに流れるアクセスログを眺めていたときでした。
まとめ¶
今回は、Python標準のhttp.serverについて、基本の使い方から落とし穴まで見てきました。ポイントをもう一度振り返っておきましょう。
python -m http.serverの1行で、今いるフォルダを配信するWebサーバーが立ち上がります。ポートは--なしの数字で、公開フォルダは--directoryで、待ち受けるアドレスは--bindで指定できます。
Pythonのコードから使うときは、ThreadingHTTPServerとpartialの組み合わせが定番です。テストの中で一時的にサーバーを動かしたい場面で活躍します。
そして何より、http.serverは手元での確認専用だということを忘れないでください。隠しファイルまで配信されること、既定ではネットワーク上の他の人からも見えることを意識して、--bind 127.0.0.1と専用フォルダで使うのが安全です。
まずは自分のHTMLファイルを用意して、http://localhost:8000/で開いてみてください。ターミナルに流れるログを眺めるだけでも、Webの仕組みがぐっと身近に感じられるはずです。
ここまでお読みいただきありがとうございました。