かんたんHTTPサーバー構築3選(Python/Java/BusyBox)+α

Posted by 雅楽斎 on Thursday, April 13, 2023

TOC

ローカルでHTTPサーバーを建てる

ローカルやLAN内でHTTPサーバーを建てて動作確認をしたい時の簡単な手順をまとめました。

まずは追加インストールする必要なく使える可能性の高いPython(3)、Javaで開発をする人ならインストールしている可能性の高いJava1、組み込みで使われることの多いBusyBoxのHTTPサーバー機能の3つとNGINXを一番シンプルにHTTPサーバーとして使う場合のDockerでの使い方についてまとめました。

動作確認はRaspberry Pi 4上のUbuntu Server 22.04 LTSで行っています。

試しにJava SEのJavadocを展開してブラウザから見れるようにする

具体的にローカルやLAN内でHTTPサーバーで何を見るかというと、JavaのJavadocなんかはクラス名の検索では古いバージョンがたくさん引っかかって時間がかかったりする2ものなので、今回はこれをブラウザから見れることを確認します。

$ mkdir ~/javadoc19
$ cd ~/javadoc19
$ wget http://download.oracle.com/docs/cds/javase/jp/19.zip
$ unzip 19.zip 

Python

http.server — HTTP servers — Python 3.11.3 documentation

今やどんなLinux環境でもデフォルトでインストールされていると言っても過言ではないPythonは、http.serverモジュールを指定して実行することでHTTPサーバーを構築できます。

引数で色々指定可能です。以下で指定しない場合の引数はbindするポート番号を記載します(デフォルト8000)

  • -b/--bind IPアドレス bindするIPアドレスを指定します。指定しない場合はすべてのインタフェースをbindします(3.4で追加、3.8でIPv6アドレスにも対応)
  • -d/--directory ルートディレクトリ 指定したディレクトリをHTTPサーバーのrootにします(3.7で追加)
  • -p/--protocol HTTP/1.1 使用するHTTPのバージョンを指定します。デフォルトではHTTP/1.0になっています(3.11で追加)

    $ python3 -m http.server 8000 -b 0 -d ~/javadoc19/
    Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
    

F72954_01→APIドキュメントと進むといつものJavadocが表示されます。

index.htmlがない場合はディレクトリリストが表示されます。停止する場合はCtrl+cで止まります。

Java(Java18以降)

JEP 408: Simple Web Server

JavaにはJava6で導入されたcom.sun.net.httpserverパッケージがありましたが、Java18でコマンド一つで簡易HTTPサーバーを実行できるようにJEP408が追加されました。jwebserverコマンドとしても実行可能です。3

Ubuntu 22.04でのインストール

Ubuntu 22.04ではJava19まで標準のパッケージがあります(universeに入っています)

$ apt-cache policy openjdk-19-jdk
openjdk-19-jdk:
  インストールされているバージョン: (なし)
  候補:               19.0.2+7-0ubuntu3~22.04
  バージョンテーブル:
     19.0.2+7-0ubuntu3~22.04 500
        500 http://ports.ubuntu.com/ubuntu-ports jammy-updates/universe arm64 Packages
        500 http://ports.ubuntu.com/ubuntu-ports jammy-security/universe arm64 Packages

Ubuntuのパッケージでは現在もJDKとJREが分けて管理されているので、開発にJava19を使う予定がない場合はJREをインストールするとダウンロードサイズとストレージを節約できます。

#  apt-get install openjdk-19-jre

既に他のJavaバージョンをインストールしている場合は実行されるjavaコマンドのパスを確認しましょう。

$ update-alternatives --list java
/usr/lib/jvm/java-11-openjdk-arm64/bin/java
/usr/lib/jvm/java-17-openjdk-arm64/bin/java
/usr/lib/jvm/java-18-openjdk-arm64/bin/java
/usr/lib/jvm/java-19-openjdk-arm64/bin/java
/usr/lib/jvm/java-8-openjdk-arm64/jre/bin/java
$ update-alternatives --config java
alternative java (/usr/bin/java を提供) には 5 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
* 0            /usr/lib/jvm/java-19-openjdk-arm64/bin/java      1911      自動モード
  1            /usr/lib/jvm/java-11-openjdk-arm64/bin/java      1111      手動モード
  2            /usr/lib/jvm/java-17-openjdk-arm64/bin/java      1711      手動モード
  3            /usr/lib/jvm/java-18-openjdk-arm64/bin/java      1811      手動モード
  4            /usr/lib/jvm/java-19-openjdk-arm64/bin/java      1911      手動モード
  5            /usr/lib/jvm/java-8-openjdk-arm64/jre/bin/java   1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:

また、LTSであるJava8/11/17を既に別の用途で使っている場合はデフォルト実行はそっちを指すように変更して、Java18以降はフルパスで実行するようにするほうが長期的に見て安全です。

# update-alternatives --config java
alternative java (/usr/bin/java を提供) には 5 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
* 0            /usr/lib/jvm/java-19-openjdk-arm64/bin/java      1911      自動モード
  1            /usr/lib/jvm/java-11-openjdk-arm64/bin/java      1111      手動モード
  2            /usr/lib/jvm/java-17-openjdk-arm64/bin/java      1711      手動モード
  3            /usr/lib/jvm/java-18-openjdk-arm64/bin/java      1811      手動モード
  4            /usr/lib/jvm/java-19-openjdk-arm64/bin/java      1911      手動モード
  5            /usr/lib/jvm/java-8-openjdk-arm64/jre/bin/java   1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 2
update-alternatives: /usr/bin/java (java) を提供するためにマニュアルモードで /usr/lib/jvm/java-17-openjdk-arm64/bin/java を使います

JavaのHTTPサーバー機能/jwebserverコマンド引数は以下の通り。

  • -b/--bind-address IPアドレス bindするIPアドレスを指定します。デフォルトは127.0.0.1または::1。全てのインタフェースを指定する場合は-b 0.0.0.0または-b ::
  • -d/--directory ルートディレクトリ 指定したディレクトリをHTTPサーバのrootにします。デフォルトはカレントディレクトリ
  • -o/--output ログレベル 出力フォーマットを指定します。ログレベルはnone/info/verboseで、デフォルトはinfo
  • -p/--port ポート番号 listenするポート番号を指定します。デフォルトは8000

    $ /usr/lib/jvm/java-19-openjdk-arm64/bin/java -m jdk.httpserver -b 0 -d ~/javadoc19/
    /home/hogehoge/javadoc19およびサブディレクトリを0.0.0.0 (すべてのインタフェース)ポート8000で使用します
    URL http://192.168.1.210:8000/
    
    

F72954_01→APIドキュメントと進むといつものJavadocが表示されます。

index.htmlがない場合はディレクトリリストが表示されます。停止する場合はCtrl+cで止まります。

BusyBox

BusyBox - The Swiss Army Knife of Embedded Linux

組み込み向けで使われることの多いBusyBoxはHTTPサーバーとしても機能します。Python/Javaと比べてサーバーサイドでのプログラム実行も可能ですが、ここではシンプルなHTTPサーバーとしてbusyboxを実行します。

指定できる引数は相当多いのですが、今回は簡易HTTPサーバーで使うものだけ取り上げます。

  • -f daemonとして起動しない(おそらくフォアグラウンドの略)
  • -p (IPアドレス:)ポート番号 bindする(IPアドレスと)ポート番号を指定します。デフォルトは80
  • -h ルートディレクトリ 指定したディレクトリをHTTPサーバのrootにします。デフォルトはカレントディレクトリ

Ubuntu 22.04でのインストール

# apt-get install busybox
$ busybox httpd -f -p 8000 -h ~/javadoc19/

busyboxはindex.htmlがなかった場合にディレクトリリストを表示してくれる機能がないので、html(今回の場合 http://192.168.1.210:8000/F72954_01/docs/api/index.html )を直接ブラウザから叩く必要があります。

停止する場合はCtrl+cで止まります。

NGINX(Dockerで)

上で記載したPython/Java/BusyBoxはコマンドを実行してHTTPサーバを動作させるというものでしたが、OSを再起動しても使い続けたい場合など、継続性の手間を考慮すると普通のHTTPサーバをdockerで動かすというのも一つの方法になると思います。

今回はNGINXを(よくあるリバースプロキシではなく)シンプルなHTTPサーバとして実行し、ルートディレクトリは任意のディレクトリ、起動・終了をdocker-composeで制御する場合を考えてみます。

一般ユーザーで実行する場合はRootless Dockerで

一般ユーザーでdockerを使う場合、dockerグループを作って作業ユーザーをdockerグループに追加するという手順も取れますが、今回はRootless Dockerを使えるようにして作業します。手順は以下の通り。

Dockerをrootlessに変更してrootユーザーの呪縛から開放される

標準的な設定からの変更箇所

NGINXは色々な用途に使うことができるため設定項目も多いのですが、今回は単純によくある設定から少ない変更で済ませるため、以下の3つの要素でdocker-composeから制御するようにします。

  • docker-compose.yml
  • default.conf (docker-compose.ymlと同じディレクトリに配置)
  • ルートディレクトリ(Rootless Dockerの実行ユーザーで読み取れるようにする)

docker-compose.yml

version: "3"
services:
  nginx:
    image: nginx:stable
    container_name: nginx00
    ports:
      - "8080:80"
    restart: unless-stopped
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf
      - /mnt/usbhdd1/var/docker-nginx:/usr/share/nginx/html

services-nginxの下の要素について以下のようにしています。

  • image→nginx:stable dockerhubを見ると、現在1.23.4がmainlineとして、1.24がstableとして公開されているので、1.24を選択(Debian Bullseye)
  • ports→8080:80 実ポート番号として公開するのは8080
  • volumes(1つ目)→./default.conf:/etc/nginx/conf.d/default.conf docker-compose.ymlと同じディレクトリにdefault.confを置いて、コンテナから見た/etc/nginx/conf.d/default.confとして読み込む
  • volumes(2つ目)→/mnt/usbhdd1/var/docker-nginx:/usr/share/nginx/html HTTPサーバーのドキュメントルートとして、実ファイルシステムの /mnt/usbhdd1/var/docker-nginx ディレクトリを読み込む

default.conf

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

デフォルトのdefault.confからの変更は以下の通りです。

  • location / にautoindex on他を設定(index.htmlがない場合にディレクトリリストを表示する)

確認事項は以下の通りです。

  • listenに指定するポート番号が80になっている(コンテナ内のポート番号をdocker-compose.ymlで8080に対応させるポート番号になっている)
  • location /のrootが /usr/share/nginx/html になっている(docker-compose.ymlのvolumesとしてドキュメントルートに対応させるディレクトリになっている)

ドキュメントルートにするディレクトリはdocker-compose upの前にディレクトリを作る

ドキュメントルートのディレクトリは先にディレクトリを作らないとdockerにその名前でファイル(ディレクトリではない)を作られてしまうので、予めディレクトリを作っておきます。

また、このディレクトリ配下のファイルはRootless Dockerの実行ユーザー(私の場合は166535)が読み込めるパーミッションでないと表示できるようにならないので、一般ファイルは644、ディレクトリは755にするのが無難です。

コンテナの実行

初回はコンテナをdockerhubからダウンロードするので、時間がかかるため、-dを付けずに起動するのがいいでしょう。

$ docker-compose up
Creating network "docker-nginx_default" with the default driver
Creating nginx00 ... done
Attaching to nginx00
nginx00  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx00  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx00  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx00  | 10-listen-on-ipv6-by-default.sh: info: IPv6 listen already enabled
nginx00  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx00  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx00  | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: using the "epoll" event method
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: nginx/1.22.1
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: OS: Linux 5.15.0-1026-raspi
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: start worker processes
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: start worker process 23
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: start worker process 24
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: start worker process 25
nginx00  | 2023/04/09 02:22:27 [notice] 1#1: start worker process 26

こんな感じの表示になったら起動しているので、試しにブラウザからアクセスするとログが表示されます。

nginx00  | 172.25.0.1 - - [09/Apr/2023:02:25:25 +0000] "GET / HTTP/1.1" 200 457 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" "-"

コンテナ動作を確認できたらCtrl+cで止めます。

^CGracefully stopping... (press Ctrl+C again to force)
Stopping nginx00 ... done

動作確認ができたら2回目以降は非同期実行でいいでしょう。

$ docker-compose up -d
Starting nginx00 ... done

docker-compose.ymlにrestart: unless-stoppedを記載しているので、OSを再起動しても自動的にコンテナを起動します。

スポンサーリンク


  1. ただし現時点で最新LTSのJava17の後になるJava18以降なので、手動でセットアップする必要がある場合が多いと思います [return]
  2. ただし現時点でJava20のJavadocは英語しかないので、Java19の日本語のJavadocを見ます [return]
  3. jwebserverコマンドはUbuntuのopenjdkパッケージには入っていないので、jwebserverコマンドを使わない方法を記載します [return]

comments powered by Disqus