diff --git a/dist_zip/.gitignore b/dist_zip/.gitignore
new file mode 100644
index 00000000..0f20387e
--- /dev/null
+++ b/dist_zip/.gitignore
@@ -0,0 +1,3 @@
+fc2blog_dist_*
+fc2blog/
+test_vm/fc2.zip
\ No newline at end of file
diff --git a/dist_zip/Makefile b/dist_zip/Makefile
new file mode 100644
index 00000000..2761c66b
--- /dev/null
+++ b/dist_zip/Makefile
@@ -0,0 +1,19 @@
+.PHONY:
+build:
+ make clean
+ git clone --depth=1 --branch=main https://github.com/uzulla/fc2blog.git fc2blog
+ rm -rf fc2blog/.git
+ cd fc2blog && php ../../composer.phar install --no-dev --optimize-autoloader
+ cd fc2blog && zip -r ../fc2blog_dist_`git rev-parse --short HEAD`.zip app public
+
+.PHONY:
+clean:
+ -rm -rf fc2blog
+ -rm fc2blog_dist_*
+ -rm test_vm/fc2.zip
+
+.PHONY:
+test:
+ make build
+ cp fc2blog_dist_`git -C fc2blog rev-parse --short HEAD`.zip test_vm/fc2.zip
+ cd test_vm && make image-no-cache && make bash
diff --git a/dist_zip/README.md b/dist_zip/README.md
new file mode 100644
index 00000000..135eed14
--- /dev/null
+++ b/dist_zip/README.md
@@ -0,0 +1,42 @@
+# Create distribution zip
+
+Create a ZIP file for distribute.
+
+## IMPORTANT NOTICE
+
+The script will be make a zip that cloned from `https://github.com/uzulla/fc2blog` (not `fc2blog/blog`).
+
+This situation is temporary on the development. will be change to `fc2blog/blog`.
+
+## build zip
+
+```
+$ make build
+$ ls fc2blog_dist_*
+fc2blog_dist_*****.zip
+```
+
+`fc2blog_dist_*****.zip` is distributable zip. (***** is short commit id)
+
+that contain `app`, `public`, and `app/vendor/`(libraries that installed by the composer).
+
+## test on Ubuntu vm(docker)
+
+```
+$ make test
+{some logs output}
+If you want exit. please exit or ctrl-D
+==================================
+http://172.17.0.2/admin/common/install
+==================================
+{some logs output}
+root@2792c09097ef:/# exit
+```
+
+> All data is not permanent. All data will be lost when exited.
+
+## clean
+
+```
+$ make clean
+```
diff --git a/dist_zip/test_vm/001-blog.conf b/dist_zip/test_vm/001-blog.conf
new file mode 100644
index 00000000..85e2a679
--- /dev/null
+++ b/dist_zip/test_vm/001-blog.conf
@@ -0,0 +1,28 @@
+# for development purpose.
+
+ DocumentRoot /var/www/html
+ ErrorLog /dev/stdout
+ CustomLog /dev/stdout combined
+
+
+ Options FollowSymlinks Includes
+ AllowOverride All
+ Require all granted
+
+
+
+
+ DocumentRoot /var/www/html
+ ErrorLog /dev/stdout
+ CustomLog /dev/stdout combined
+
+ SSLEngine on
+ SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
+ SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
+
+
+ Options FollowSymlinks Includes
+ AllowOverride All
+ Require all granted
+
+
diff --git a/dist_zip/test_vm/Dockerfile b/dist_zip/test_vm/Dockerfile
new file mode 100644
index 00000000..799aba82
--- /dev/null
+++ b/dist_zip/test_vm/Dockerfile
@@ -0,0 +1,56 @@
+FROM ubuntu:focal
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN set -eux \
+ && apt-get update -y \
+ && apt-get upgrade -y \
+ && apt-get install -y software-properties-common iproute2 vim git wget unzip locales ssl-cert \
+ && sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen \
+ && locale-gen \
+ && rm -rf /tmp/*
+
+RUN add-apt-repository -y ppa:ondrej/php \
+ && add-apt-repository -y ppa:ondrej/apache2 \
+ && apt-get update \
+ && apt-get install -y apache2 mysql-server php8.0 libapache2-mod-php8.0 php8.0-intl php8.0-mbstring php8.0-gd php8.0-mysql
+
+ARG PUID=1000
+ARG PGID=1000
+
+RUN groupmod -o -g $PGID www-data && \
+ usermod -o -u $PUID -g www-data www-data && \
+ usermod --shell /bin/bash www-data
+
+COPY 001-blog.conf /etc/apache2/sites-available/
+
+RUN make-ssl-cert generate-default-snakeoil --force-overwrite \
+ && a2enmod rewrite \
+ && a2enmod ssl \
+ && a2ensite 001-blog \
+ && a2dissite 000-default.conf \
+ && a2dissite default-ssl.conf
+
+RUN mkdir /var/run/mysqld \
+ && chmod 777 /var/run/mysqld
+
+# XXX
+RUN sh -c "/usr/bin/mysqld_safe --user=mysql &" \
+ && sleep 3 \
+ && mysql_secure_installation -ppass -D \
+ && echo "CREATE DATABASE fc2" | mysql \
+ && echo "CREATE USER 'dbuser'@'127.0.0.1' IDENTIFIED BY 'd1B2p3a#s!s';" | mysql \
+ && echo "GRANT ALL ON fc2.* TO 'dbuser'@'127.0.0.1';" | mysql
+
+COPY fc2.zip /tmp
+RUN cd tmp \
+ && unzip fc2.zip \
+ && mv app /var/www/ \
+ && mv public/* /var/www/html/ \
+ && mv public/.htaccess /var/www/html/ \
+ && chown -R www-data:www-data /var/www/ \
+ && rm /var/www/html/index.html
+
+COPY config.php /var/www/app/
+
+COPY startup.sh /
diff --git a/dist_zip/test_vm/Makefile b/dist_zip/test_vm/Makefile
new file mode 100644
index 00000000..99164728
--- /dev/null
+++ b/dist_zip/test_vm/Makefile
@@ -0,0 +1,22 @@
+PHONY:
+image:
+ # alignment local UID/GID and docker UID/GID for Linux dev env.
+ $(eval UID := $(shell id -u))
+ $(eval GID := $(shell id -g))
+ docker build -t fc2_dist_test_vm --build-arg PUID=$(UID) --build-arg PGID=$(GID) .
+
+PHONY:
+image-no-cache:
+ # alignment local UID/GID and docker UID/GID for Linux dev env.
+ $(eval UID := $(shell id -u))
+ $(eval GID := $(shell id -g))
+ docker build -t fc2_dist_test_vm --no-cache --build-arg PUID=$(UID) --build-arg PGID=$(GID) .
+
+PHONY:
+run:
+ docker run --rm -it fc2_dist_test_vm sh -c "/startup.sh ; bash"
+
+PHONY:
+bash:
+ docker run --rm -it fc2_dist_test_vm bash
+
diff --git a/dist_zip/test_vm/config.php b/dist_zip/test_vm/config.php
new file mode 100644
index 00000000..387d44ab
--- /dev/null
+++ b/dist_zip/test_vm/config.php
@@ -0,0 +1,20 @@
+