Getting Started
This documentation will guide you on how to quickly deploy and start using ChronoFrame.
🚧 Under Construction
Documentation is being written, some feature documentation is not yet complete.
Prerequisites
- Available Docker environment.
- An S3 protocol-compatible storage bucket (GitHub repository storage and local filesystem storage are still in development).
TIP
When using S3 storage, you need to obtain at least the following information from your service provider:
ACCESS_KEY_ID
,SECRET_ACCESS_KEY
,ENDPOINT
,BUCKET_NAME
,REGION
. When the bucket's external URL is different from theENDPOINT
, you also need to provide the external URLCDN_URL
. - Two Mapbox access tokens.
Why do I need two tokens?
- The first token is used for frontend map display, requires
styles:read
permission. It's recommended to restrict this token's URL to your ChronoFrame instance domain to prevent abuse. - The second token is used for backend reverse geocoding, this token cannot have URL restrictions. This token is optional.
- The first token is used for frontend map display, requires
- GitHub OAuth App
CLIENT_ID
andCLIENT_SECRET
(optional, for enabling GitHub login).TIP
When creating the OAuth app, the
Authorization callback URL
should be set tohttp(s)://<your-domain>/api/auth/github
.
Quick Deployment
Pre-built Images
We recommend using pre-built Docker images for deployment, hosted on GitHub Container Registry:
ghcr.io/hoshinosuzumi/chronoframe:latest
Docker Single Container Deployment
Quick Start
docker run -d \
--name chronoframe \
-p 3000:3000 \
-v $(pwd)/data:/app/data \
-e CFRAME_ADMIN_EMAIL="" \
-e CFRAME_ADMIN_NAME="" \
-e CFRAME_ADMIN_PASSWORD="" \
-e NUXT_PUBLIC_APP_TITLE="" \
-e NUXT_PUBLIC_APP_SLOGAN="" \
-e NUXT_PUBLIC_APP_AUTHOR="" \
-e NUXT_PUBLIC_APP_AVATAR_URL="" \
-e NUXT_PUBLIC_MAPBOX_ACCESS_TOKEN="" \
-e NUXT_STORAGE_PROVIDER="s3" \
-e NUXT_PROVIDER_S3_ENDPOINT="" \
-e NUXT_PROVIDER_S3_BUCKET="chronoframe" \
-e NUXT_PROVIDER_S3_REGION="auto" \
-e NUXT_PROVIDER_S3_ACCESS_KEY_ID="" \
-e NUXT_PROVIDER_S3_SECRET_ACCESS_KEY="" \
-e NUXT_PROVIDER_S3_PREFIX="photos/" \
-e NUXT_PROVIDER_S3_CDN_URL="" \
-e NUXT_OAUTH_GITHUB_CLIENT_ID="" \
-e NUXT_OAUTH_GITHUB_CLIENT_SECRET="" \
-e NUXT_SESSION_PASSWORD="" \
ghcr.io/hoshinosuzumi/chronoframe:latest
Docker Compose Deployment
Recommended for production environment deployment using Docker Compose for easier management and configuration.
1. Create .env
file
# Admin user email (required)
CFRAME_ADMIN_EMAIL=
# Admin username (default to Chronoframe, optional)
CFRAME_ADMIN_NAME=
# Admin user password (default to CF1234@!, optional)
CFRAME_ADMIN_PASSWORD=
# Application title and slogan
NUXT_PUBLIC_APP_TITLE=
NUXT_PUBLIC_APP_SLOGAN=
NUXT_PUBLIC_APP_AUTHOR=
NUXT_PUBLIC_APP_AVATAR_URL=
# Mapbox access token for map features, Mapbox GL JS (Client-side, public)
NUXT_PUBLIC_MAPBOX_ACCESS_TOKEN=
# Mapbox secret access token for server-side, Mapbox Search API (Reverse Geocoding)
NUXT_MAPBOX_ACCESS_TOKEN=
# Storage provider (s3/github/local)
NUXT_STORAGE_PROVIDER=s3
# S3 storage service configuration
NUXT_PROVIDER_S3_ENDPOINT=
NUXT_PROVIDER_S3_BUCKET=chronoframe
NUXT_PROVIDER_S3_REGION=auto
NUXT_PROVIDER_S3_ACCESS_KEY_ID=
NUXT_PROVIDER_S3_SECRET_ACCESS_KEY=
NUXT_PROVIDER_S3_PREFIX=photos/
NUXT_PROVIDER_S3_CDN_URL=
# Session password (32-character random string, required)
NUXT_SESSION_PASSWORD=
# GitHub OAuth
NUXT_OAUTH_GITHUB_CLIENT_ID=
NUXT_OAUTH_GITHUB_CLIENT_SECRET=
2. Create docker-compose.yml
file
services:
chronoframe:
image: ghcr.io/hoshinosuzumi/chronoframe:latest
container_name: chronoframe
restart: unless-stopped
ports:
- '3000:3000'
volumes:
- ./data:/app/data
env_file:
- .env
3. Start ChronoFrame Service
# Start service
docker compose up -d
# View logs
docker compose logs -f chronoframe
# Stop service
docker compose down
# Update to latest version
docker compose pull
docker compose up -d
Reverse Proxy
When deploying in production environment, you usually need a reverse proxy server (like Nginx or Caddy) to handle HTTPS and domain resolution. Here are some example configurations.
Nginx
server {
listen 80;
server_name your-domain.com;
# HTTPS redirect
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL certificate configuration
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# SSL security configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Upload size limit
client_max_body_size 100M;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# WebSocket support
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static resource caching
location ~* \.(jpg|jpeg|png|gif|webp|svg|css|js|ico|woff|woff2|ttf|eot)$ {
proxy_pass http://localhost:3000;
expires 1y;
add_header Cache-Control "public, immutable";
proxy_set_header Host $host;
}
}
Traefik
If you use Traefik as reverse proxy, you can add labels in docker-compose.yml
:
services:
chronoframe:
image: ghcr.io/hoshinosuzumi/chronoframe:latest
container_name: chronoframe
restart: unless-stopped
volumes:
- ./data:/app/data
env_file:
- .env
labels:
- "traefik.enable=true"
- "traefik.http.routers.chronoframe.rule=Host(`your-domain.com`)"
- "traefik.http.routers.chronoframe.entrypoints=websecure"
- "traefik.http.routers.chronoframe.tls.certresolver=letsencrypt"
- "traefik.http.services.chronoframe.loadbalancer.server.port=3000"
networks:
- traefik
networks:
traefik:
external: true
Common Issues
How to generate random NUXT_SESSION_PASSWORD
?
# Linux / macOS
openssl rand -base64 32
# Windows (pwsh)
[Convert]::ToBase64String((1..32|%{[byte](Get-Random -Max 256)}))
After successful backend authentication login, redirect to homepage and still in unauthenticated state?
First, please make sure you're not accessing directly through IP address and port number. For security reasons, please access through the configured domain name.
If for some reason you insist on accessing through IP port, please add to configuration:
NUXT_ALLOW_INSECURE_COOKIE=true