Overview
The “Pre-modern Japan-Asia Relations Digital Archive” was released on July 25, 2025.
https://asia-da.lit.kyushu-u.ac.jp/
The viewer is also available at:
https://github.com/localmedialabs/tei_comparative_viewer
In this article, I share my experience trying out this viewer.
As a result, I was able to self-host it as shown below:
https://tei-comparative-viewer.aws.ldas.jp/

It loads the following XML file of “Kaitoshokokki” (Record of Countries and Peoples in the Eastern Sea):
https://asia-da.lit.kyushu-u.ac.jp/viewer/300

Running Locally
Detailed instructions are provided at the following link, which I followed to get it running:
https://github.com/localmedialabs/tei_comparative_viewer/blob/main/docs/SETUP.md
Running on a Server
To run it on a server, I used Docker.
The forked repository is available at:
https://github.com/nakamura196/tei_comparative_viewer/tree/docker-traefik-setup
I prepared the following files:
FROM php:8.2-fpm
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
nodejs \
npm \
nginx \
supervisor
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install mbstring exif pcntl bcmath gd
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www
# Copy existing application directory contents
COPY . /var/www
# Install dependencies
RUN composer install --no-dev --optimize-autoloader
# Install and build frontend assets
RUN npm install && npm run build
# Remove default nginx site
RUN rm -f /etc/nginx/sites-enabled/default
# Copy nginx config
COPY docker/nginx/app.conf /etc/nginx/sites-available/app.conf
RUN ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
# Copy PHP-FPM config
COPY docker/php/www.conf /usr/local/etc/php-fpm.d/www.conf
# Copy supervisor config
COPY docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Create necessary directories and set permissions
RUN mkdir -p /var/log/supervisor \
&& chown -R www-data:www-data /var/www \
&& chmod -R 755 /var/www/storage \
&& chmod -R 755 /var/www/bootstrap/cache
# Generate key
RUN php artisan key:generate
# Optimize Laravel
RUN php artisan config:cache && \
php artisan route:cache && \
php artisan view:cache
# Expose port 80
EXPOSE 80
# Create PHP-FPM socket directory
RUN mkdir -p /var/run/php
# Start supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
services:
app:
build:
context: .
dockerfile: Dockerfile.prod.traefik
container_name: tei_viewer_app
restart: unless-stopped
env_file:
- .env.external
volumes:
- ./storage:/var/www/storage
- ./public/assets:/var/www/public/assets
networks:
- traefik-network
labels:
- "traefik.enable=true"
# HTTP router (redirects to HTTPS)
- "traefik.http.routers.app-insecure.rule=Host(`xxx.yyy.zzz`)"
- "traefik.http.routers.app-insecure.entrypoints=web"
- "traefik.http.routers.app-insecure.middlewares=https-redirect"
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
# HTTPS router
- "traefik.http.routers.app.rule=Host(`xxx.yyy.zzz`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=myresolver"
- "traefik.http.services.app.loadbalancer.server.port=80"
# Security headers
- "traefik.http.middlewares.app-headers.headers.frameDeny=true"
- "traefik.http.middlewares.app-headers.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.app-headers.headers.browserXssFilter=true"
- "traefik.http.middlewares.app-headers.headers.referrerPolicy=strict-origin-when-cross-origin"
- "traefik.http.middlewares.app-headers.headers.stsSeconds=31536000"
- "traefik.http.middlewares.app-headers.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.app-headers.headers.stsPreload=true"
# Apply middlewares
- "traefik.http.routers.app.middlewares=app-headers"
networks:
traefik-network:
external: true
# Application Environment
APP_ENV=production
APP_DEBUG=false
APP_KEY=
APP_URL=https://xxx.yyy.zzz
# Domain Configuration (used in docker-compose labels)
DOMAIN=xxx.yyy.zzz
# Database
DB_CONNECTION=sqlite
# Session and Cache
SESSION_DRIVER=file
CACHE_DRIVER=file
# Logging
LOG_CHANNEL=stack
# Mail (if needed)
MAIL_MAILER=smtp
# Other Laravel configurations as needed
#!/bin/bash
echo "=== TEI Comparative Viewer Setup with External Traefik ==="
# Create .env.external file if it doesn't exist
if [ ! -f .env.external ]; then
echo "Creating .env.external file..."
cp .env.external.example .env.external
# Generate application key
echo "Generating application key..."
docker run --rm \
-v $(pwd):/var/www \
-w /var/www \
php:8.2-cli \
php artisan key:generate --env=production --show | sed 's/base64://' > app_key.tmp
# Set the generated key in .env.external
APP_KEY=$(cat app_key.tmp)
sed -i.bak "s/APP_KEY=/APP_KEY=base64:$APP_KEY/" .env.external
rm app_key.tmp .env.external.bak
echo "Application key generated successfully!"
fi
# Configuration confirmation
echo ""
echo "⚠️ IMPORTANT: Please edit .env.external and configure the following:"
echo " 1. DOMAIN=your-domain.com (your actual domain)"
echo " 2. APP_URL=https://your-domain.com (with HTTPS)"
echo " 3. ASSET_URL=https://your-domain.com (for proper asset loading)"
echo ""
echo "Note: This setup assumes you have an external Traefik instance running"
echo "with the 'traefik-network' already created."
echo ""
read -p "Press Enter to continue with the current settings..."
# Load .env file
export $(cat .env.external | grep -v '^#' | xargs)
# Check if traefik-network exists
echo "Checking if traefik-network exists..."
if ! docker network ls | grep -q traefik-network; then
echo "❌ Error: traefik-network not found!"
echo "Please ensure your external Traefik is running with traefik-network created."
echo ""
echo "If you need to create the network manually:"
echo " docker network create traefik-network"
exit 1
fi
echo "✅ traefik-network found!"
# Create necessary directories
echo "Creating necessary directories..."
mkdir -p storage/app/public
mkdir -p storage/framework/{cache,sessions,views}
mkdir -p storage/logs
mkdir -p bootstrap/cache
# Copy .env file
echo "Copying environment file..."
cp .env.external .env
# Build Docker images (using Dockerfile without key generation)
echo "Building Docker images..."
if ! docker compose -f docker-compose-external.yml build; then
echo "❌ Docker build failed. Trying without cache..."
docker compose -f docker-compose-external.yml build --no-cache
fi
# Start containers
echo "Starting containers..."
docker compose -f docker-compose-external.yml up -d
# Wait for startup
echo "Waiting for services to be ready..."
sleep 15
# Generate application key if not set
echo "Checking and generating application key if needed..."
if docker compose -f docker-compose-external.yml exec app php artisan key:generate --show | grep -q "base64:"; then
echo "Generating new application key..."
docker compose -f docker-compose-external.yml exec app php artisan key:generate --force
fi
# Set permissions
echo "Setting permissions..."
docker compose -f docker-compose-external.yml exec app chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache || echo "Permission setting completed"
# Clear configuration cache
echo "Clearing configuration cache..."
docker compose -f docker-compose-external.yml exec app php artisan config:clear
docker compose -f docker-compose-external.yml exec app php artisan config:cache
docker compose -f docker-compose-external.yml exec app php artisan route:clear
# Check application status
echo "Checking application status..."
if docker compose -f docker-compose-external.yml ps | grep -q "Up"; then
echo "✅ Application container is running!"
else
echo "❌ Application container may have issues. Check logs:"
echo " docker compose -f docker-compose-external.yml logs app"
fi
echo ""
echo "✅ Setup complete!"
echo ""
echo "Application should be available at your configured domain (HTTPS)"
echo "(assuming your external Traefik is properly configured and SSL certificates are set up)"
echo ""
echo "To stop the application, run:"
echo " docker compose -f docker-compose-external.yml down"
echo ""
echo "To view logs, run:"
echo " docker compose -f docker-compose-external.yml logs -f app"
echo ""
echo "To check Traefik routing (if dashboard is accessible):"
echo " Check your Traefik dashboard for the new routes"
echo ""
echo "📝 Next steps:"
echo " 1. Edit .env.external with your actual domain settings"
echo " 2. Update docker-compose-external.yml Traefik labels with your domain"
echo " 3. Ensure DNS is properly configured for your domain"
Summary
There may be some inaccuracies, but I hope this serves as a useful reference.
I would like to thank the people involved for making the system and tools publicly available.