Galleria is a modern, self-hosted photography portfolio platform
9.1K
A modern photography portfolio website built with React 19, TypeScript, Express 5, and SQLite. Features optimized image delivery, admin panel, analytics tracking, and responsive design.
š Live Demo: tedcharles.netā
Pre-built Docker images are available on Docker Hub: hub.docker.com/r/tedcharles/galleriaā
# Pull latest production image
docker pull tedcharles/galleria:latest
# Pull latest development image
docker pull tedcharles/galleria:dev
# Pull specific version
docker pull tedcharles/galleria:v1.2.0
Quick Start with Docker Hub image:
# Create data directory
mkdir -p ~/galleria-data
# Run with Docker
docker run -d \
--name galleria \
-p 3000:3000 \
-v ~/galleria-data:/data \
-e DATA_DIR=/data \
tedcharles/galleria:latest
Open http://YOUR-SERVER-IP:3000 and create a username and password. No email address, DNS setup, or second exposed port is required. Email is requested only when you choose Google sign-in. Local accounts can use MFA and passkeys; email password recovery requires an email-based account.
For Nginx Proxy Manager, create one proxy host pointing to your server's WebUI port, using HTTP upstream, and enable SSL. No custom API location is needed. For plain nginx:
server {
listen 443 ssl;
server_name photos.example.com;
# Configure your ssl_certificate and ssl_certificate_key here.
client_max_body_size 0;
location / {
proxy_pass http://YOUR-SERVER-IP:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
DOMAIN=https://photos.example.com is optional. Leaving it blank uses your browser's origin. If your public hostname changes after setup, set DOMAIN to update generated links and Google/passkey origins.
Upgrading existing Unraid/Docker installations: keep your current volumes, port mappings, and environment variables. /app/data remains the default for existing Unraid templates; installations using DATA_DIR=/data remain supported. Existing email/password accounts keep their logins and data. FRONTEND_DOMAIN, BACKEND_DOMAIN, API_URL, ALLOWED_ORIGINS, and saved split-domain API URLs remain supported. To intentionally switch an existing split-domain installation to one domain, remove BACKEND_DOMAIN/API_URL, set DOMAIN to the public URL, and point the reverse proxy to port 3000. Update your Google OAuth redirect URI if you use Google sign-in.
| Variable | Default / purpose |
|---|---|
DOMAIN | Optional public URL; blank for automatic same-origin access |
FRONTEND_DOMAIN | Legacy frontend URL override |
BACKEND_DOMAIN / API_URL | Legacy public API URL; explicit values preserve split-domain access |
BACKEND_INTERNAL_URL | Internal proxy target; defaults to http://127.0.0.1:3001 |
DATA_DIR | /app/data in Docker unless explicitly set, e.g. /data |
ALLOWED_ORIGINS | Optional additional allowed browser origins |
Available tags:
:latest - Latest production build:dev - Latest development build:vX.Y.Z - Specific version (e.g., :v1.2.3)Single container deployment with PM2 process management.
git clone https://github.com/theodorecharles/Galleria.git
cd Galleria
mkdir -p ~/galleria-data
docker-compose.yml:environment:
- DATA_DIR=/data
- DOMAIN= # Optional, e.g. https://photos.yourdomain.com
volumes:
- ~/galleria-data:/data
docker-compose up -d --build
git clone https://github.com/theodorecharles/Galleria.git
cd Galleria
npm install
cd backend && npm install
cd ../frontend && npm install
cd ..
npm run dev
http://localhost:3000 - the setup wizard will guide you through initial configuration.# Build both frontend and backend
npm run build
# Install PM2 globally
npm install -g pm2
# Start services
pm2 start ecosystem.config.cjs
pm2 save
pm2 startup
See Docker Deploymentā section above.
Via GitHub Actions:
Push to master (prod) or devel branch, and GitHub Actions automatically deploys.
Manual deployment:
git pull origin <branch>
./restart.sh
The restart.sh script handles:
Galleria supports hardware-accelerated video encoding for faster video processing using your GPU.
Prerequisites:
Enable in docker-compose.yml:
services:
app:
runtime: nvidia # Enable NVIDIA runtime
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
Hardware encoding automatically detects and uses available GPU encoders on your system. No special configuration needed - just ensure GPU drivers are installed.
Performance: Hardware encoding can be 5-10x faster than software encoding, especially for high-resolution videos.
Configuration is managed through environment variables or the admin panel - you don't need to edit config files directly.
Configure via environment variables in docker-compose.yml:
environment:
- DATA_DIR=/data
- DOMAIN= # Optional, e.g. https://photos.yourdomain.com
Copy the example environment file:
cp .env.example .env
Edit .env with your settings:
DOMAIN= # Optional public URL
DATA_DIR=./data
After initial setup, all configuration is managed through the Admin Panel at /admin ā Settings.
Google OAuth is completely optional. You can use password-based authentication without any OAuth setup.
To enable Google OAuth login:
https://photos.yourdomain.com/api/auth/google/callbackhttp://localhost:3000/api/auth/google/callbackhttps://api.yourdomain.com/api/auth/google/callback/adminView logs (PM2):
pm2 logs
View logs (Docker):
docker exec galleria pm2 logs
Restart services:
pm2 restart all
# or
docker-compose restart
Optimize images:
node scripts/optimize_all_images.js
galleria/
āāā backend/ # Express API
ā āāā src/
ā ā āāā server.ts # Main server
ā ā āāā routes/ # API endpoints
ā āāā package.json
āāā frontend/ # React app
ā āāā src/
ā āāā package.json
āāā data/ # Data directory (not in Git)
ā āāā config.json # Configuration (auto-generated, managed via admin panel)
ā āāā photos/ # Original photos
ā āāā optimized/ # Generated images
ā āāā gallery.db # SQLite database
āāā .env.example # Environment variables template (copy to .env)
āāā scripts/ # Utility scripts
āāā Dockerfile # Docker container
āāā docker-compose.yml # Docker Compose config
āāā package.json # Root dependencies
Galleria supports 37 languages with full UI and SEO localization:
The selected language applies to:
Built by Ted Charlesā with React, TypeScript, and Express
Content type
Image
Digest
sha256:e1862d4adā¦
Size
694.4 MB
Last updated
11 days ago
docker pull tedcharles/galleria