English | 简体中文
Camlife is a website that showcases photography works for everyone who loves photography
- 🌓 Supports dark/light themes
- ✨ Minimalist and elegant UI design
- 📱 Responsive design for all devices
- 🖼️ Various beautiful image display layouts
- 🗺️ Cool interactive map browsing mode
- 🏷️ Organize and display photos using tags
- 🔗 Image sharing and open graph image generation
- 💼 Support image usage with copyright purchase
- 📊 Dashboard supports data statistics, album management, and others
- 🤖 Integrate AI generated image titles and descriptions
- 📷 Image EXIF automatic parsing
- 🗜️ High-efficiency image compression and generation of BlurHash data
- 📍 Get image location information based on latitude and longitude
- 📦 Support for batch automatic upload and parsing processing of images
- 📰 Generate RSS/JSON feeds
- 📸 Live Photo image format support
- 🚀 Supports CDN acceleration for faster photo delivery
- 🔐 Secure authentication with Better Auth
- 💾 Multi-Storage Support: Cloudflare R2、AWS S3 or Vercel Blob
- 🎁 Hide some Easter eggs and more features at any time
Welcome to add your website to the list #11
- ⚡ Framework - Next.js
- 🧩 Language - TypeScript
- 🌬️ Styling - Tailwind CSS
- 🎛️ UI Library - shadcn/ui
- 🐻 State Management - Zustand
- 🐘 Database - Postgres
- 🌧️ ORM - Drizzle
- 🔑 Auth - Better Auth
- 🗺️ Maps - mapbox
- 🌐 Multi-language - next-intl
- ✅ Schema Validations - Zod
- 🧪 Testing FrameWork - Vitest
- 🔗 API Layer - tRPC
- 🧹 Formatter and Linter - Biome
- 🪝 Git hooks - Lefthook
- 📊 Traffic Analysis - Umami & @vercel/analytics
|
Guoqi Sun |
Sun Xin |
-
Create a
.envfile in the root directory -
Docker Compose
docker-compose up -dWarning
Please ensure that all necessary environment variables are correctly configured before running the project.
# Database
DATABASE_URL="postgresql://postgres:password@host:port/camlife"
# Storage
STORAGE_PROVIDER="cloudflare-r2" # cloudflare-r2 | aws-s3 | vercel-blob
CLOUDFLARE_R2_ENDPOINT="https://fcb75ae*******2a3f5ce73fb.r2.cloudflarestorage.com"
CLOUDFLARE_R2_BUCKET="files"
CLOUDFLARE_R2_REGION="auto"
CLOUDFLARE_R2_ACCESS_KEY_ID="eac63617**********41cd00889"
CLOUDFLARE_R2_SECRET_ACCESS_KEY="29d01ddcb25d*****************b6d561ab18d175a94f"
CLOUDFLARE_R2_PREFIX="camlife"
CLOUDFLARE_R2_PUBLIC_URL="https://pub-ba****************j.r2.dev"
AWS_S3_BUCKET=
AWS_S3_REGION=
AWS_S3_ACCESS_KEY=
AWS_S3_SECRET_ACCESS_KEY=
# Mapbox
NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN="pk.eyJ18***********************************9.N3bTvCedxVfugnrCSRT2kw"
# Auth
# You can generate a random secret using `openssl rand -base64 32`
BETTER_AUTH_SECRET="I1IA7rUTafc+feqzSE61tjlPhtzTkewhJUnp6lL9nVI="
BETTER_AUTH_URL="http://localhost:3000"
# Umami
NEXT_PUBLIC_UMAMI_ANALYTICS_ID="****-1d30-4876-8de6-****"
NEXT_PUBLIC_UMAMI_ANALYTICS_JS="https://umami.guoqi.dev/script.js"Note
Variables marked with * are required only when STORAGE_PROVIDER is set to cloudflare-r2. For other storage providers (AWS S3, Vercel Blob), different environment variables will be required.
Cloudflare R2
- Setup bucket
- Create R2 bucket with default settings
- Setup CORS under bucket settings:
[{ "AllowedHeaders": ["*"], "AllowedMethods": [ "GET", "PUT" ], "AllowedOrigins": [ "http://localhost:3000", "https://{VERCEL_PROJECT_NAME}*.vercel.app", "{PRODUCTION_DOMAIN}" ] }]- Enable public hosting by doing one of the following:
- Select "Connect Custom Domain" and choose a Cloudflare domain
- OR
- Select "Allow Access" from R2.dev subdomain
- Store public configuration:
CLOUDFLARE_R2_BUCKET: bucket nameCLOUDFLARE_R2_ENDPOINT: bucket endpointCLOUDFLARE_R2_PUBLIC_URL: either "your-custom-domain.com" or "pub-jf90908...s0d9f8s0s9df.r2.dev"
- Setup private credentials
- Create API token by selecting "Manage R2 API Tokens," and clicking "Create API Token"
- Select "Object Read & Write," choose "Apply to specific buckets only," and select the bucket created in Step 1
- Store credentials:
CLOUDFLARE_R2_ACCESS_KEYCLOUDFLARE_R2_SECRET_ACCESS_KEY
AWS S3
- Setup bucket
- Create S3 bucket with "ACLs enabled," and "Block all public access" turned off
- Setup CORS under bucket permissions:
[{ "AllowedHeaders": ["*"], "AllowedMethods": [ "GET", "PUT" ], "AllowedOrigins": [ "http://localhost:*", "https://{VERCEL_PROJECT_NAME}*.vercel.app", "{PRODUCTION_DOMAIN}" ], "ExposeHeaders": [] }] - Store public configuration
AWS_S3_BUCKET: bucket nameAWS_S3_REGION: bucket region, e.g., "us-east-1"
- Setup private credentials
- Create IAM policy using JSON editor:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:PutObjectACL", "s3:GetObject", "s3:ListBucket", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::{BUCKET_NAME}", "arn:aws:s3:::{BUCKET_NAME}/*" ] } ] } - Create IAM user by choosing "Attach policies directly," and selecting the policy created above. Create "Access key" under "Security credentials," choose "Application running outside AWS," and store credentials :
AWS_S3_ACCESS_KEYAWS_S3_SECRET_ACCESS_KEY
- Create IAM policy using JSON editor:
Vercel Blob
Todo| Variable | Description | Default | Required |
|---|---|---|---|
DATABASE_URL |
PostgreSQL database connection URL | None | Yes |
STORAGE_PROVIDER |
Storage provider (cloudflare-r2, aws-s3, vercel-blob) | cloudflare-r2 | Yes |
CLOUDFLARE_R2_ENDPOINT |
Cloudflare R2 endpoint URL | None | Yes* |
CLOUDFLARE_R2_BUCKET |
Cloudflare R2 bucket name | None | Yes* |
CLOUDFLARE_R2_REGION |
Cloudflare R2 region | auto | No |
CLOUDFLARE_R2_ACCESS_KEY_ID |
Cloudflare R2 access key ID | None | Yes* |
CLOUDFLARE_R2_SECRET_ACCESS_KEY |
Cloudflare R2 secret access key | None | Yes* |
CLOUDFLARE_R2_PREFIX |
Cloudflare R2 object key prefix | camlife | No |
CLOUDFLARE_R2_PUBLIC_URL |
Cloudflare R2 public URL for accessing files | None | Yes* |
AWS_S3_BUCKET |
AWS S3 bucket name | None | Yes* |
AWS_S3_REGION |
AWS S3 region | auto | No |
AWS_S3_ACCESS_KEY |
AWS S3 access key | None | Yes* |
AWS_S3_SECRET_ACCESS_KEY |
AWS S3 secret access key | None | Yes* |
NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN |
Mapbox map service access token | None | Yes |
BETTER_AUTH_SECRET |
Better Auth secret key (generate with openssl rand -base64 32) |
None | Yes |
BETTER_AUTH_URL |
Application base URL | http://localhost:3000 |
Yes |
NEXT_PUBLIC_UMAMI_ANALYTICS_ID |
Umami Website ID | None | No |
NEXT_PUBLIC_UMAMI_ANALYTICS_JS |
Umami Custom Analysis JS URL | None | No |
- Clone the repository
git clone https://github.com/sun0225SUN/camlife.git
cd camlife-
Create a .env file in the root directory, and configure the environment variables as described in the 🚀 Getting Started section.
-
Install dependencies
bun install- Set up the database
bun db:migrate- Start the development server
bun run devOpen: http://localhost:3000 to see your application.
This project is licensed under the GNU General Public License v3.0.
Contributions are welcome! Feel free to open issues and pull requests.
If you find this project helpful, please give it a ⭐️ on GitHub!
|
|

