このページ内での表記:「ホストOSの対話環境」は背景色を黄色(lightyellow)で表す。「Conainer 内の root 権限の対話環境」は背景色を水色(azure)であらわす。「Conainer 内の一般ユーザ権限の対話環境」は背景色を赤色(#ffeeee)であらわす。「他のPCの対話環境」は紫色(#eeeeff)で表す。
$ mkdir -p ~/doc/docker/ubuntu24_sshd_https $ cd ~/doc/docker/ubuntu24_ssd_https
Dockerfile |
# ゲストOS: Ubuntu 24.04 LTS FROM ubuntu:24.04 # Change Your Own UNAME, UID, GID, PASS ENV UNAME=guest ENV UID=3000 ENV GID=3000 ENV PASS=password ENV SSHD_PORT=22 # 必要なパッケージのインストール RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y \ sudo \ bash \ openssh-server \ supervisor \ apache2 \ libapache2-mod-php \ php-fpm \ net-tools iputils-tracepath traceroute iputils-ping curl iproute2 \ cron certbot \ && rm -rf /var/lib/apt/lists/* # SSH 設定: パスワード認証を有効化 RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config && \ sed -i "s/^#Port.*/Port ${SSHD_PORT}/" /etc/ssh/sshd_config && \ mkdir /var/run/sshd # Apache 設定: ServerName エラー防止 RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf # PHP 設定 RUN sed -i 's/^;date\.timezone =.*/date\.timezone = "Asia\/Tokyo"/' /etc/php/8.3/apache2/php.ini # PHP-FPM によるPHPの高速化 RUN sed -i \ '/<\/VirtualHost>/i <FilesMatch "\\.php$">\n SetHandler "proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost/"\n</FilesMatch>' \ /etc/apache2/sites-available/default-ssl.conf RUN a2enmod proxy_fcgi setenvif RUN a2enconf php8.3-fpm # supervisord の設定ファイルを設置する (Daemon 起動用) RUN mkdir -p /var/log/supervisor COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # ポート開放 EXPOSE 22 80 # Copy Shell Script "entrypoint.sh" COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD [] |
entrypoint.sh |
#!/bin/bash set -e if [ ! -f /var/app/.initialized ]; then ######## First Time ######## echo "First run. Setting up ..." mkdir -p /var/app touch /var/app/.initialized # ユーザーが存在しない場合のみ作成する if id "${UNAME}" &>/dev/null; then echo "User ${UNAME} already exists. Skipping creation." else # 同名グループが無ければ作成 if ! getent group "${UNAME}" &>/dev/null; then echo "Creating group ${UNAME} with GID=${GID}" groupadd -g ${GID} ${UNAME} else echo "Group ${UNAME} already exists. Skipping group creation." fi echo "Creating user ${UNAME} with UID=${UID}, GID=${GID}" useradd -m -u ${UID} -g ${GID} -s /bin/bash ${UNAME} echo "${UNAME}:${PASS}" | chpasswd adduser ${UNAME} sudo fi # ホームディレクトリの Owner が root:root になることがあるので変更する。 chown -v ${UNAME}:${UNAME} /home/${UNAME} # SSHD のポート番号を変更する sed -i "s/^Port.*/Port ${SSHD_PORT}/" /etc/ssh/sshd_config else ######## Second Time or Later ######## echo "Starting for the second time or later ..." fi # supervisord start (background) /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf & # Execute Commands in CMD if [ "$#" -gt 0 ]; then exec "$@" else echo "No command provided. Starting bash ..." exec bash fi |
supervisord.conf |
# supervisord の設定ファイル [supervisord] nodaemon=true logfile=/var/log/supervisor/supervisord.log [program:sshd] command=/usr/sbin/sshd -D -e stdout_logfile=/var/log/sshd_stdout.log stderr_logfile=/var/log/sshd_stderr.log autostart=true autorestart=true [program:php-fpm] command=/usr/sbin/php-fpm8.3 -F autostart=true autorestart=true stdout_logfile=/var/log/php-fpm.log stderr_logfile=/var/log/php-fpm.err [program:apache2] command=/usr/sbin/apachectl -D FOREGROUND autostart=true autorestart=true [program:cron] command=/usr/sbin/cron -f autostart=true autorestart=true |
$ docker build -t ubuntu24-sshd-https . ... 成功
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu24-sshd-https latest d12fc3012451 2 hours ago 329MB ...
コンテナに永続的なファイルシステムを提供するために、1777 のパーミッションでフォルダを作っておく。 skicky bit が on (1777) のフォルダには、 「誰でもファイルを作成できるが、作成した本人だけがファイルを変更したり消したりできる」 という特徴がある。
$ sudo mkdir -p /home/docker ← ディレクトリを作成する $ sudo chmod 1777 /home/docker ← 誰でもファイルを作成できるが、作成した本人にしか消去できないモードに設定する $ ls -ld /home/docker ← ディレクトリのsticky bit が on になっていることを確認する。 drwxrwxrwt 3 root root 4096 4月 26 15:47 /home/docker
「アクセスしてきたクライアントの正しいIPアドレスがContainer 上の httpdサーバ (apache2) に伝わる」ように macvlan を使って「Container に物理 NIC と同じネットワークの独立した IP アドレスを与える」ことにする。
$ netstat -nr カーネルIP経路テーブル 受信先サイト ゲートウェイ ネットマスク フラグ MSS Window irtt インタフェース 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eno1 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 192.168.12.0 0.0.0.0 255.255.255.0 U 0 0 0 eno1
$ ifconfig ... eno1: flags=4163mtu 1500 inet 192.168.12.3 netmask 255.255.255.0 broadcast 192.168.12.255 inet6 2409:11:3920:6400:5a47:caff:fe71:3b7d prefixlen 64 scopeid 0x0 inet6 2409:11:3920:6400:4c1a:ff8c:eab1:41c9 prefixlen 64 scopeid 0x0 inet6 fe80::5a47:caff:fe71:3b7d prefixlen 64 scopeid 0x20 ether 58:47:ca:71:3b:7d txqueuelen 1000 (イーサネット) ...
$ docker network ls NETWORK ID NAME DRIVER SCOPE ebbd998b2086 bridge bridge local 17420af9f271 host host local 557533733a33 macvlan_net macvlan local a3538f29efc6 none null local
$ docker network create -d macvlan \ --subnet=192.168.12.0/24 \ --gateway=192.168.12.1 \ -o parent=eno1 \ --ip-range=192.168.12.192/28 \ macvlan_net
$ docker network ls NETWORK ID NAME DRIVER SCOPE ebbd998b2086 bridge bridge local 17420af9f271 host host local 557533733a33 macvlan_net macvlan local a3538f29efc6 none null local
$ docker network ls --no-trunc NETWORK ID NAME DRIVER SCOPE ebbd998b20868aea17c1e9f3cd85edb3c7c0ce9181edfe9b308284604275e136 bridge bridge local 17420af9f27199ef5081c56e85910d913c73ae8f3885e48e4ed0b09a06d48016 host host local 557533733a33e84ca9eb665736f6a273414778f30a3e744411596008728b0b2b macvlan_net macvlan local a3538f29efc60166d3f639d42894eff9f902649036619190011c3a66b262a06a none null local
$ docker network inspect macvlan_net [ { "Name": "macvlan_net", "Id": "557533733a33e84ca9eb665736f6a273414778f30a3e744411596008728b0b2b", "Created": "2025-05-18T13:38:38.53151226+09:00", "Scope": "local", "Driver": "macvlan", "EnableIPv4": true, "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "192.168.12.0/24", "IPRange": "192.168.12.192/28", "Gateway": "192.168.12.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "65cf25b6ca3756fd9babc1b29d9b1a30d493c9ee85a713b530a91e999f9c35de": { "Name": "ubuntu24-sshd-httpd-vlan193", "EndpointID": "f8525f08c56d699552c023cdd7a589c2dd177ed575085d15b44eea960f83df3e", "MacAddress": "a6:a6:4d:50:7a:0d", "IPv4Address": "192.168.12.193/24", "IPv6Address": "" } }, "Options": { "parent": "eno1" }, "Labels": {} } ]
Image ubuntu24-sshd-https を用いて、 macvlan_net ネットワークに接続する、 新しい Container ubuntu24-sshd-https-vlan193 を生成する。
--network macvlan_net
オプションを追加することにより、
この Container はホストOSのネットワークを共有する。-p
オプションは指定しない。
ホストOSのネットワークを共有した場合、port forwarding はできないため。$ docker run --name ubuntu24-sshd-https-vlan193 --restart always \ -e UNAME=www -e UID=2000 -e GID=2000 \ --network macvlan_net \ --ip 192.168.12.193 \ --cap-add=NET_ADMIN \ -v /home/docker/httpd:/mnt/hostos \ -it ubuntu24-sshd-https起動オプション
環境変数名 | 値 |
---|---|
UNAME | www |
UID | 2000 |
GID | 2000 |
マウントポイント | |
---|---|
ホストOS | ゲストOS |
/home/docker/hhtpd | /mnt/hostos |
First run. Setting up ... Creating group www with GID=2000 Creating user www with UID=2000, GID=2000 info: Adding user `www' to group `sudo' ... ownership of '/home/www' retained as www:www No command provided. Starting bash ... root@74996e43a896:/# 2025-05-25 04:58:18,756 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message. 2025-05-25 04:58:18,759 INFO RPC interface 'supervisor' initialized 2025-05-25 04:58:18,759 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2025-05-25 04:58:18,759 INFO supervisord started with pid 41 2025-05-25 04:58:19,763 INFO spawned: 'apache2' with pid 44 2025-05-25 04:58:19,765 INFO spawned: 'cron' with pid 45 2025-05-25 04:58:19,766 INFO spawned: 'php-fpm' with pid 46 2025-05-25 04:58:19,768 INFO spawned: 'sshd' with pid 48 2025-05-25 04:58:20,787 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2025-05-25 04:58:20,788 INFO success: cron entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2025-05-25 04:58:20,788 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2025-05-25 04:58:20,788 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) # ← Container 内の対話環境 (root 権限の bash) が動く
# passwd www New password: 新しいパスワード ← 新しいパスワードを入力する(エコーバックされない) Retype new password: 新しいパスワード ← もう一度新しいパスワードを入力する(エコーバックされない)
# apt updateifconfig, netstat, arp をインストールする
# apt install -y net-toolstraceroute をインストールする
$ apt install -y iputils-tracepath tracerouteping をインストールする
$ sudo apt install -y iputils-pingcurl をインストールする
$ sudo apt install -y curlip をインストールする
$ sudo apt install -y iproute2
netstat
コマンドを用いて、ルーティング情報を調べる。
→
Container が接続しているネットワークは 192.168.12.0/24で、
デフォルトのルーティング先が 192.168.12.1 であることがわかる$ netstat -nr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eth0 192.168.12.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
ifconfig
でContainer のIPアドレスを調べる。
→ 192.168.12.193 であることがわかる。$ ifconfig eth0: flags=4163mtu 1500 inet 192.168.12.193 netmask 255.255.255.0 broadcast 192.168.12.255 ether 8a:9e:8a:00:aa:16 txqueuelen 0 (Ethernet) RX packets 5434 bytes 30400112 (30.4 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 4498 bytes 300984 (300.9 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73 mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 1000 (Local Loopback) RX packets 8 bytes 1058 (1.0 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 1058 (1.0 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# iptables -L bash: iptables: command not found # ufw status bash: ufw: command not found
# apt update # apt install -y ufwufw を有効化する
# ufw enable Status: active
# ufw allow from 0.0.0.0/0 to any port 22 proto tcp Rule added # ufw allow from 0.0.0.0/0 to any port 80 proto tcp Rule added # ufw allow from 0.0.0.0/0 to any port 443 proto tcp Rule added外部からのアクセスはデフォルトで禁止にする。
# ufw default deny incomingファイアウォールの設定状況を見る
# ufw status Status: active To Action From -- ------ ---- 22/tcp ALLOW Anywhere 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere
$ ssh www@192.168.12.193[注意] パスワードを迅速に変更しておくこと。
# apt -y install certbot![]()
--webroot でWebサーバの公開ディレクトリ配下を認証用に一時領域に使う -w DocumentRoot -d 証明書を取得する対象の FQDN (= Fully Qualified Domain Name)
# certbot certonly --webroot -w /var/www/html -d ynitta.netSaving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): y7anitta@gmail.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: n
Account registered. Requesting a certificate for ynitta.net Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/ynitta.net/fullchain.pem Key is saved at: /etc/letsencrypt/live/ynitta.net/privkey.pem This certificate expires on 2023-09-01. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - If you like Certbot, please consider supporting our work by: * Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate * Donating to EFF: https://eff.org/donate-le - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker container ではsystemd が動作していないので systemctl が使えない。 そのため、cron を使って certbot を定期的に実行する。
# which cron/usr/sbin/cron
# ps aux | grep cronroot 44 0.0 0.0 4192 2340 pts/0 S 04:10 0:00 /usr/sbin/cron -f root 1223 0.0 0.0 3528 1740 pts/0 S+ 04:19 0:00 grep --color=auto cron
# apt install -y vim$ export EDITOR=vi
![]()
0 2 * * * certbot renew --quiet --deploy-hook "service apache2 restart"
2025/06/02 時点でここまで編集中。
[問題点] システムにより、supervisorctl による apache2 の再起動がうまくいかないことがある。 変更する必要あり。
[解決方法] apache2 の再起動に必要な環境変数が設定されていないことが問題の原因。 したがって、次のようなscriptを用意しておいて、 supervisord ではこのスクリプトを使って apache2 を起動するように記述すればよい。
---------------- start-apache2.sh #!/bin/bash source /etc/apache2/envvars exec apache2 -D FOREGROUND ------------------------ ------------------/etc/supervisor/conf.d/supervisord.conf への追加 [program:apache2] #command=/usr/sbin/apache2 -D FOREGROUND # ERROR for not loading /etc/apache2/envvars command=/usr/local/bin/start-apache2.sh autostart=true autorestart=true stopasgroup=true killasgroup=true stdout_logfile=/var/log/apache2_stdout.log stderr_logfile=/var/log/apache2_stderr.log ------------------------
# a2enmod sslConsidering dependency mime for ssl: Module mime already enabled Considering dependency socache_shmcb for ssl: Enabling module socache_shmcb. Enabling module ssl. See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates. To activate the new configuration, you need to run: service apache2 restart
/etc/apache2/sites-available/default-ssl.confの変更点 |
*** default-ssl.conf.ORG Sun May 25 05:46:24 2025 --- default-ssl.conf Sun May 25 05:48:02 2025 *************** *** 1,5 **** <VirtualHost *:443> ! ServerAdmin webmaster@localhost DocumentRoot /var/www/html --- 1,5 ---- <VirtualHost *:443> ! ServerAdmin y7anitta@gmail.com DocumentRoot /var/www/html *************** *** 28,35 **** # /usr/share/doc/apache2/README.Debian.gz for more info. # If both key and certificate are stored in the same file, only the # SSLCertificateFile directive is needed. ! SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem ! SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key # Server Certificate Chain: # Point SSLCertificateChainFile at a file containing the --- 28,35 ---- # /usr/share/doc/apache2/README.Debian.gz for more info. # If both key and certificate are stored in the same file, only the # SSLCertificateFile directive is needed. ! SSLCertificateFile /etc/letsencrypt/live/ynitta.net/cert.pem ! SSLCertificateKeyFile /etc/letsencrypt/live/ynitta.net/privkey.pem # Server Certificate Chain: # Point SSLCertificateChainFile at a file containing the *************** *** 38,44 **** # the referenced file can be the same as SSLCertificateFile # when the CA certificates are directly appended to the server # certificate for convinience. ! #SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt # Certificate Authority (CA): # Set the CA certificate verification path where to find CA --- 38,44 ---- # the referenced file can be the same as SSLCertificateFile # when the CA certificates are directly appended to the server # certificate for convinience. ! SSLCertificateChainFile /etc/letsencrypt/live/ynitta.net/chain.pem # Certificate Authority (CA): # Set the CA certificate verification path where to find CA |
# a2ensite default-sslEnabling site default-ssl. To activate the new configuration, you need to run: service apache2 reload
# a2enmod sslConsidering dependency mime for ssl: Module mime already enabled Considering dependency socache_shmcb for ssl: Module socache_shmcb already enabled Module ssl already enabled
# service apache2 restart* Restarting Apache httpd web server apache2 [ OK ]
supervisord.conf の変更点 |
diff -c -r ubuntu24_sshd_https/supervisord.conf ubuntu24_sshd_https_supervisor/supervisord.conf *** ubuntu24_sshd_https/supervisord.conf 2025-05-24 16:46:25.000000000 +0900 --- ubuntu24_sshd_https_supervisor/supervisord.conf 2025-05-25 13:55:02.353051752 +0900 *************** *** 1,8 **** --- 1,19 ---- # supervisord の設定ファイル + [unix_http_server] + file=/var/run/supervisor.sock ; ソケットファイルの場所 + chmod=0700 + [supervisord] nodaemon=true logfile=/var/log/supervisor/supervisord.log + pidfile=/var/run/supervisord.pid + + [rpcinterface:supervisor] + supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + + [supervisorctl] + serverurl=unix:///var/run/supervisor.sock [program:sshd] command=/usr/sbin/sshd -D -e |