mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-03 20:12:58 +00:00
small fix, don't worry about it
This commit is contained in:
@@ -0,0 +1,546 @@
|
||||
# Appwrite Backend-as-a-Service Template
|
||||
|
||||
## Overview
|
||||
Appwrite is an open-source backend-as-a-service platform that abstracts and simplifies complex development tasks behind a simple REST API.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
appwrite:
|
||||
image: appwrite/appwrite:latest
|
||||
container_name: appwrite
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "444:444"
|
||||
environment:
|
||||
- _APP_ENV=production
|
||||
- _APP_OPENSSL_KEY_V1=your-openssl-key-here
|
||||
- _APP_DOMAIN=http://localhost
|
||||
- _APP_DOMAIN_TARGET=http://localhost
|
||||
- _APP_REDIS_HOST=redis
|
||||
- _APP_REDIS_PORT=6379
|
||||
- _APP_DB_HOST=mariadb
|
||||
- _APP_DB_PORT=3306
|
||||
- _APP_DB_USER=root
|
||||
- _APP_DB_PASSWORD=instance-password
|
||||
- _APP_DB_SCHEMA=appwrite
|
||||
- _APP_INFLUXDB_HOST=influxdb
|
||||
- _APP_INFLUXDB_PORT=8086
|
||||
- _APP_INFLUXDB_USERNAME=appwrite
|
||||
- _APP_INFLUXDB_PASSWORD=your-influx-password
|
||||
- _APP_INFLUXDB_DATABASE=appwrite
|
||||
- _APP_MESSAGING_HOST=messaging
|
||||
- _APP_MESSAGING_PORT=80
|
||||
- _APP_EXECUTOR_HOST=executor
|
||||
- _APP_EXECUTOR_PORT=80
|
||||
- _APP_MAILER_HOST=mailer
|
||||
- _APP_MAILER_PORT=80
|
||||
- _APP_MAILER_SECURE=false
|
||||
- _APP_MAILER_USERNAME=your-email@gmail.com
|
||||
- _APP_MAILER_PASSWORD=your-app-password
|
||||
- _APP_MAILER_FROM=your-email@gmail.com
|
||||
- _APP_FUNCTIONS_ENV=executor
|
||||
- _APP_FUNCTIONS_TIMEOUT=900
|
||||
- _APP_FUNCTIONS_ASYNC=true
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads
|
||||
- appwrite-cache:/storage/cache
|
||||
- appwrite-config:/storage/config
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
- influxdb
|
||||
- messaging
|
||||
- executor
|
||||
- mailer
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.6
|
||||
container_name: appwrite-mariadb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=instance-password
|
||||
- MYSQL_DATABASE=appwrite
|
||||
- MYSQL_USER=appwrite
|
||||
- MYSQL_PASSWORD=secretpassword
|
||||
volumes:
|
||||
- appwrite-db:/var/lib/mysql
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: appwrite-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- appwrite-redis:/data
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
influxdb:
|
||||
image: influxdb:1.8
|
||||
container_name: appwrite-influxdb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- INFLUXDB_DB=appwrite
|
||||
- INFLUXDB_ADMIN_USER=appwrite
|
||||
- INFLUXDB_ADMIN_PASSWORD=your-influx-password
|
||||
volumes:
|
||||
- appwrite-influxdb:/var/lib/influxdb
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
messaging:
|
||||
image: appwrite/messaging:latest
|
||||
container_name: appwrite-messaging
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- _APP_REDIS_HOST=redis
|
||||
- _APP_REDIS_PORT=6379
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
executor:
|
||||
image: appwrite/executor:latest
|
||||
container_name: appwrite-executor
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- _APP_ENV=production
|
||||
- _APP_REDIS_HOST=redis
|
||||
- _APP_REDIS_PORT=6379
|
||||
- _APP_DB_HOST=mariadb
|
||||
- _APP_DB_PORT=3306
|
||||
- _APP_DB_USER=root
|
||||
- _APP_DB_PASSWORD=instance-password
|
||||
- _APP_DB_SCHEMA=appwrite
|
||||
- _APP_FUNCTIONS_ENV=executor
|
||||
- _APP_FUNCTIONS_TIMEOUT=900
|
||||
- _APP_FUNCTIONS_ASYNC=true
|
||||
volumes:
|
||||
- appwrite-functions:/storage/functions
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
mailer:
|
||||
image: appwrite/mailer:latest
|
||||
container_name: appwrite-mailer
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- _APP_MAILER_HOST=mailer
|
||||
- _APP_MAILER_PORT=80
|
||||
- _APP_MAILER_SECURE=false
|
||||
- _APP_MAILER_USERNAME=your-email@gmail.com
|
||||
- _APP_MAILER_PASSWORD=your-app-password
|
||||
- _APP_MAILER_FROM=your-email@gmail.com
|
||||
networks:
|
||||
- appwrite-network
|
||||
|
||||
volumes:
|
||||
appwrite-uploads:
|
||||
appwrite-cache:
|
||||
appwrite-config:
|
||||
appwrite-db:
|
||||
appwrite-redis:
|
||||
appwrite-influxdb:
|
||||
appwrite-functions:
|
||||
|
||||
networks:
|
||||
appwrite-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `_APP_ENV`: Environment (production/development)
|
||||
- `_APP_OPENSSL_KEY_V1`: OpenSSL encryption key
|
||||
- `_APP_DOMAIN`: Your domain URL
|
||||
- `_APP_DB_*`: Database configuration
|
||||
- `_APP_REDIS_*`: Redis configuration
|
||||
- `_APP_INFLUXDB_*`: InfluxDB configuration
|
||||
- `_APP_MAILER_*`: Email configuration
|
||||
- `_APP_FUNCTIONS_*`: Cloud functions configuration
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate OpenSSL Key**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Generate Database Passwords**:
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Create admin account
|
||||
- Set up first project
|
||||
- Generate API keys
|
||||
|
||||
## API Usage
|
||||
|
||||
### Authentication
|
||||
```bash
|
||||
# Create account
|
||||
curl -X POST http://localhost/v1/account \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"user@example.com","password":"password","name":"John Doe"}'
|
||||
|
||||
# Login
|
||||
curl -X POST http://localhost/v1/account/sessions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"user@example.com","password":"password"}'
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
```bash
|
||||
# Create collection
|
||||
curl -X POST http://localhost/v1/database/collections \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"name":"posts","read":["any"],"write":["any"]}'
|
||||
|
||||
# Create document
|
||||
curl -X POST http://localhost/v1/database/collections/posts/documents \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"title":"Hello World","content":"This is my first post"}'
|
||||
|
||||
# List documents
|
||||
curl http://localhost/v1/database/collections/posts/documents \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY"
|
||||
```
|
||||
|
||||
### File Storage
|
||||
```bash
|
||||
# Upload file
|
||||
curl -X POST http://localhost/v1/storage/files \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-F "file=@/path/to/file.jpg"
|
||||
|
||||
# Get file
|
||||
curl http://localhost/v1/storage/files/FILE_ID/download \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID"
|
||||
```
|
||||
|
||||
### Cloud Functions
|
||||
```bash
|
||||
# Create function
|
||||
curl -X POST http://localhost/v1/functions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"name":"hello-world","runtime":"node-18.0","execute":["any"],"events":[]}'
|
||||
|
||||
# Upload function code
|
||||
curl -X POST http://localhost/v1/functions/FUNCTION_ID/code \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"code":"export default function(req, res) { res.json({message: \"Hello World\"}); }"}'
|
||||
|
||||
# Execute function
|
||||
curl -X POST http://localhost/v1/functions/FUNCTION_ID/executions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
## Client SDKs
|
||||
|
||||
### JavaScript/TypeScript
|
||||
```javascript
|
||||
import { Client, Account, Databases } from 'appwrite'
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('http://localhost/v1')
|
||||
.setProject('YOUR_PROJECT_ID')
|
||||
|
||||
const account = new Account(client)
|
||||
const databases = new Databases(client)
|
||||
|
||||
// Authentication
|
||||
await account.createEmailSession('user@example.com', 'password')
|
||||
|
||||
// Database operations
|
||||
const response = await databases.createDocument(
|
||||
'YOUR_DATABASE_ID',
|
||||
'YOUR_COLLECTION_ID',
|
||||
ID.unique(),
|
||||
{ title: 'Hello World', content: 'This is my first post' }
|
||||
)
|
||||
```
|
||||
|
||||
### Python
|
||||
```python
|
||||
from appwrite.client import Client
|
||||
from appwrite.services.account import Account
|
||||
from appwrite.services.databases import Databases
|
||||
|
||||
client = Client()
|
||||
client.set_endpoint('http://localhost/v1')
|
||||
client.set_project('YOUR_PROJECT_ID')
|
||||
|
||||
account = Account(client)
|
||||
databases = Databases(client)
|
||||
|
||||
# Authentication
|
||||
account.create_email_session('user@example.com', 'password')
|
||||
|
||||
# Database operations
|
||||
databases.create_document(
|
||||
'YOUR_DATABASE_ID',
|
||||
'YOUR_COLLECTION_ID',
|
||||
ID.unique(),
|
||||
{ 'title': 'Hello World', 'content': 'This is my first post' }
|
||||
)
|
||||
```
|
||||
|
||||
### PHP
|
||||
```php
|
||||
use Appwrite\Client;
|
||||
use Appwrite\Services\Account;
|
||||
use Appwrite\Services\Databases;
|
||||
|
||||
$client = new Client();
|
||||
$client->setEndpoint('http://localhost/v1')
|
||||
->setProject('YOUR_PROJECT_ID');
|
||||
|
||||
$account = new Account($client);
|
||||
$databases = new Databases($client);
|
||||
|
||||
// Authentication
|
||||
$account->createEmailSession('user@example.com', 'password');
|
||||
|
||||
// Database operations
|
||||
$databases->createDocument(
|
||||
'YOUR_DATABASE_ID',
|
||||
'YOUR_COLLECTION_ID',
|
||||
ID::unique(),
|
||||
['title' => 'Hello World', 'content' => 'This is my first post']
|
||||
);
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.appwrite.rule=Host(`api.yourdomain.com`)"
|
||||
- "traefik.http.routers.appwrite.tls=true"
|
||||
- "traefik.http.routers.appwrite.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.appwrite.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Appwrite data
|
||||
docker run --rm -v appwrite-uploads:/storage/uploads -v $(pwd):/backup alpine tar czf /backup/appwrite-uploads.tar.gz -C /storage/uploads .
|
||||
docker run --rm -v appwrite-cache:/storage/cache -v $(pwd):/backup alpine tar czf /backup/appwrite-cache.tar.gz -C /storage/cache .
|
||||
docker run --rm -v appwrite-config:/storage/config -v $(pwd):/backup alpine tar czf /backup/appwrite-config.tar.gz -C /storage/config .
|
||||
|
||||
# Backup database
|
||||
docker exec appwrite-mariadb mysqldump -u root -pinstance-password appwrite > appwrite-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i appwrite-mariadb mysql -u root -pinstance-password appwrite < appwrite-db-backup.sql
|
||||
|
||||
# Restore Appwrite data
|
||||
docker run --rm -v appwrite-uploads:/storage/uploads -v $(pwd):/backup alpine tar xzf /backup/appwrite-uploads.tar.gz -C /storage/uploads
|
||||
docker run --rm -v appwrite-cache:/storage/cache -v $(pwd):/backup alpine tar xzf /backup/appwrite-cache.tar.gz -C /storage/cache
|
||||
docker run --rm -v appwrite-config:/storage/config -v $(pwd):/backup alpine tar xzf /backup/appwrite-config.tar.gz -C /storage/config
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart appwrite
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- _APP_REDIS_HOST=redis
|
||||
- _APP_REDIS_PORT=6379
|
||||
- _APP_CACHE_ENABLED=true
|
||||
- _APP_CACHE_QUOTA=100
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default passwords
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check Appwrite health
|
||||
curl http://localhost/health
|
||||
|
||||
# Check service status
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f appwrite
|
||||
|
||||
# Check specific service logs
|
||||
docker-compose logs -f mariadb
|
||||
docker-compose logs -f redis
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Database connection**: Check MariaDB configuration
|
||||
- **Redis connection**: Verify Redis settings
|
||||
- **Function execution**: Check executor logs
|
||||
- **Email issues**: Verify SMTP configuration
|
||||
- **File uploads**: Check storage permissions
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Update images
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec appwrite-mariadb mysql -u root -pinstance-password -e "DELETE FROM appwrite.cache WHERE expires < UNIX_TIMESTAMP();"
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Real-time Subscriptions
|
||||
```javascript
|
||||
// Subscribe to document changes
|
||||
client.subscribe('documents', response => {
|
||||
console.log('Document changed:', response.payload)
|
||||
})
|
||||
```
|
||||
|
||||
### Webhooks
|
||||
```bash
|
||||
# Create webhook
|
||||
curl -X POST http://localhost/v1/webhooks \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"name":"My Webhook","events":["database.documents.create"],"url":"https://your-domain.com/webhook"}'
|
||||
```
|
||||
|
||||
### Scheduled Tasks
|
||||
```bash
|
||||
# Create scheduled task
|
||||
curl -X POST http://localhost/v1/functions/FUNCTION_ID/schedules \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Appwrite-Project: YOUR_PROJECT_ID" \
|
||||
-H "X-Appwrite-Key: YOUR_API_KEY" \
|
||||
-d '{"schedule":"0 9 * * 1","timezone":"America/New_York"}'
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Mobile App Backend
|
||||
- User authentication
|
||||
- Data storage
|
||||
- File uploads
|
||||
- Push notifications
|
||||
- Real-time sync
|
||||
|
||||
### Web Application
|
||||
- User management
|
||||
- Database operations
|
||||
- File storage
|
||||
- Cloud functions
|
||||
- API integration
|
||||
|
||||
### IoT Platform
|
||||
- Device management
|
||||
- Data collection
|
||||
- Real-time monitoring
|
||||
- Alert systems
|
||||
- Analytics
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### React App
|
||||
```javascript
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Client, Account } from 'appwrite'
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('http://localhost/v1')
|
||||
.setProject('YOUR_PROJECT_ID')
|
||||
|
||||
const account = new Account(client)
|
||||
|
||||
function App() {
|
||||
const [user, setUser] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
account.get().then(setUser).catch(console.error)
|
||||
}, [])
|
||||
|
||||
return <div>{user ? `Hello ${user.name}` : 'Loading...'}</div>
|
||||
}
|
||||
```
|
||||
|
||||
### Node.js Backend
|
||||
```javascript
|
||||
const { Client, Account } = require('appwrite')
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('http://localhost/v1')
|
||||
.setProject('YOUR_PROJECT_ID')
|
||||
|
||||
const account = new Account(client)
|
||||
|
||||
// Server-side authentication
|
||||
async function authenticateUser(email, password) {
|
||||
try {
|
||||
const session = await account.createEmailSession(email, password)
|
||||
return session
|
||||
} catch (error) {
|
||||
throw new Error('Authentication failed')
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,526 @@
|
||||
# Cloudreve File Manager Template
|
||||
|
||||
## Overview
|
||||
Cloudreve is a cloud storage system with support for multiple storage backends, including local, remote, and cloud storage providers.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
cloudreve:
|
||||
image: cloudreve/cloudreve:latest
|
||||
container_name: cloudreve
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5212:5212"
|
||||
- "6888:6888"
|
||||
- "6888:6888/udp"
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- CR_CONF_Database_Type=postgres
|
||||
- CR_CONF_Database_Host=cloudreve-db
|
||||
- CR_CONF_Database_Port=5432
|
||||
- CR_CONF_Database_User=cloudreve
|
||||
- CR_CONF_Database_Password=cloudreve
|
||||
- CR_CONF_Database_Name=cloudreve
|
||||
- CR_CONF_Redis_Server=cloudreve-redis
|
||||
- CR_CONF_Redis_Port=6379
|
||||
- CR_CONF_Site_URL=https://cloudreve.yourdomain.com
|
||||
- CR_CONF_OverwriteMode=overwrite
|
||||
volumes:
|
||||
- cloudreve-data:/cloudreve
|
||||
- cloudreve-uploads:/uploads
|
||||
- /path/to/local-storage:/storage
|
||||
depends_on:
|
||||
- cloudreve-db
|
||||
- cloudreve-redis
|
||||
networks:
|
||||
- cloudreve-network
|
||||
|
||||
cloudreve-db:
|
||||
image: postgres:17-alpine
|
||||
container_name: cloudreve-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=cloudreve
|
||||
- POSTGRES_USER=cloudreve
|
||||
- POSTGRES_PASSWORD=cloudreve
|
||||
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||
volumes:
|
||||
- cloudreve-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- cloudreve-network
|
||||
|
||||
cloudreve-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: cloudreve-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- cloudreve-redis:/data
|
||||
networks:
|
||||
- cloudreve-network
|
||||
|
||||
volumes:
|
||||
cloudreve-data:
|
||||
cloudreve-uploads:
|
||||
cloudreve-db:
|
||||
cloudreve-redis:
|
||||
|
||||
networks:
|
||||
cloudreve-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `CR_CONF_Database_*`: Database configuration
|
||||
- `CR_CONF_Redis_*`: Redis configuration
|
||||
- `CR_CONF_Site_URL`: Your site URL
|
||||
- `CR_CONF_OverwriteMode`: Configuration overwrite mode
|
||||
- `TZ`: Timezone
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secure Password**:
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p cloudreve-uploads local-storage
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:5212
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Register first account (becomes admin)
|
||||
- Configure storage backends
|
||||
- Set up user accounts
|
||||
|
||||
## Storage Backends
|
||||
|
||||
### Local Storage
|
||||
```yaml
|
||||
# In Cloudreve admin interface
|
||||
Storage Type: Local
|
||||
Path: /storage
|
||||
```
|
||||
|
||||
### S3 Compatible Storage
|
||||
```yaml
|
||||
# Configure in admin interface
|
||||
Storage Type: S3 Compatible
|
||||
Endpoint: https://s3.yourdomain.com
|
||||
Access Key: your-access-key
|
||||
Secret Key: your-secret-key
|
||||
Bucket: cloudreve
|
||||
Region: us-east-1
|
||||
```
|
||||
|
||||
### OneDrive
|
||||
```yaml
|
||||
# Configure in admin interface
|
||||
Storage Type: OneDrive
|
||||
Client ID: your-client-id
|
||||
Client Secret: your-client-secret
|
||||
Redirect URI: https://cloudreve.yourdomain.com/callback
|
||||
```
|
||||
|
||||
### Google Drive
|
||||
```yaml
|
||||
# Configure in admin interface
|
||||
Storage Type: Google Drive
|
||||
Client ID: your-client-id
|
||||
Client Secret: your-client-secret
|
||||
Redirect URI: https://cloudreve.yourdomain.com/callback
|
||||
```
|
||||
|
||||
### FTP/SFTP
|
||||
```yaml
|
||||
# Configure in admin interface
|
||||
Storage Type: FTP/SFTP
|
||||
Host: ftp.yourdomain.com
|
||||
Port: 21
|
||||
Username: your-username
|
||||
Password: your-password
|
||||
Path: /remote/path
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Cloudreve Configuration
|
||||
```yaml
|
||||
# cloudreve.yml
|
||||
app:
|
||||
name: Cloudreve
|
||||
version: 3.8.1
|
||||
debug: false
|
||||
|
||||
database:
|
||||
type: postgres
|
||||
host: cloudreve-db
|
||||
port: 5432
|
||||
name: cloudreve
|
||||
user: cloudreve
|
||||
password: cloudreve
|
||||
|
||||
redis:
|
||||
host: cloudreve-redis
|
||||
port: 6379
|
||||
password: ""
|
||||
|
||||
site:
|
||||
url: https://cloudreve.yourdomain.com
|
||||
title: Cloudreve
|
||||
theme: default
|
||||
|
||||
security:
|
||||
secret_key: your-secret-key
|
||||
jwt_secret: your-jwt-secret
|
||||
|
||||
storage:
|
||||
default: local
|
||||
policies:
|
||||
- name: local
|
||||
type: local
|
||||
path: /storage
|
||||
max_size: 10737418240
|
||||
- name: s3
|
||||
type: s3
|
||||
endpoint: https://s3.yourdomain.com
|
||||
access_key: your-access-key
|
||||
secret_key: your-secret-key
|
||||
bucket: cloudreve
|
||||
region: us-east-1
|
||||
max_size: 10737418240
|
||||
|
||||
user:
|
||||
default_quota: 10737418240
|
||||
default_group: user
|
||||
registration_enabled: false
|
||||
email_verification: false
|
||||
|
||||
upload:
|
||||
chunk_size: 10485760
|
||||
concurrent_uploads: 3
|
||||
temp_dir: /tmp
|
||||
|
||||
preview:
|
||||
enabled: true
|
||||
max_size: 10485760
|
||||
formats:
|
||||
- image
|
||||
- video
|
||||
- audio
|
||||
- document
|
||||
```
|
||||
|
||||
## User Management
|
||||
|
||||
### Create User
|
||||
```bash
|
||||
# Create user via admin interface
|
||||
# Or via API
|
||||
curl -X POST "http://localhost:5212/api/v3/admin/users" \
|
||||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"user@example.com","password":"password","nickname":"John Doe","group":"user"}'
|
||||
```
|
||||
|
||||
### User Groups
|
||||
```bash
|
||||
# Create user group
|
||||
curl -X POST "http://localhost:5212/api/v3/admin/groups" \
|
||||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"poweruser","quota":536870912000,"policies":["local","s3"]}'
|
||||
```
|
||||
|
||||
## File Operations
|
||||
|
||||
### Upload Files
|
||||
```bash
|
||||
# Upload via API
|
||||
curl -X POST "http://localhost:5212/api/v3/file/upload" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-F "file=@/path/to/file.txt" \
|
||||
-F "path=/uploads"
|
||||
```
|
||||
|
||||
### Download Files
|
||||
```bash
|
||||
# Download via API
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
"http://localhost:5212/api/v3/file/download/FILE_ID"
|
||||
```
|
||||
|
||||
### Share Files
|
||||
```bash
|
||||
# Create share link
|
||||
curl -X POST "http://localhost:5212/api/v3/share" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"file_id": "FILE_ID","password":"","expire":3600}'
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.cloudreve.rule=Host(`cloudreve.yourdomain.com`)"
|
||||
- "traefik.http.routers.cloudreve.tls=true"
|
||||
- "traefik.http.routers.cloudreve.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.cloudreve.loadbalancer.server.port=5212"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Cloudreve data
|
||||
docker run --rm -v cloudreve-data:/cloudreve -v $(pwd):/backup alpine tar czf /backup/cloudreve-data-backup.tar.gz -C /cloudreve .
|
||||
|
||||
# Backup uploads
|
||||
docker run --rm -v cloudreve-uploads:/uploads -v $(pwd):/backup alpine tar czf /backup/cloudreve-uploads-backup.tar.gz -C /uploads .
|
||||
|
||||
# Backup database
|
||||
docker exec cloudreve-db pg_dump -U cloudreve cloudreve > cloudreve-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i cloudreve-db psql -U cloudreve cloudreve < cloudreve-db-backup.sql
|
||||
|
||||
# Restore Cloudreve data
|
||||
docker run --rm -v cloudreve-data:/cloudreve -v $(pwd):/backup alpine tar xzf /backup/cloudreve-data-backup.tar.gz -C /cloudreve
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart cloudreve
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- CLOUDREVE_UPLOAD_CHUNK_SIZE=10485760
|
||||
- CLOUDREVE_UPLOAD_CONCURRENT=3
|
||||
- CLOUDREVE_PREVIEW_MAX_SIZE=10485760
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default admin password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## API Usage
|
||||
|
||||
### Authentication
|
||||
```bash
|
||||
# Login
|
||||
curl -X POST "http://localhost:5212/api/v3/user/session" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"your-password"}'
|
||||
```
|
||||
|
||||
### File Operations
|
||||
```bash
|
||||
# List files
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
"http://localhost:5212/api/v3/directory/PATH"
|
||||
|
||||
# Create directory
|
||||
curl -X POST "http://localhost:5212/api/v3/directory" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"path":"/new-folder"}'
|
||||
|
||||
# Delete file
|
||||
curl -X DELETE "http://localhost:5212/api/v3/file/FILE_ID" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
## Client Integration
|
||||
|
||||
### WebDAV
|
||||
```bash
|
||||
# Mount via WebDAV
|
||||
davfs2 https://cloudreve.yourdomain.com/dav/ /mnt/cloudreve
|
||||
```
|
||||
|
||||
### rclone
|
||||
```bash
|
||||
# Configure rclone
|
||||
rclone config create cloudreve webdav
|
||||
rclone config set cloudreve url https://cloudreve.yourdomain.com/dav/
|
||||
rclone config set cloudreve vendor other
|
||||
rclone config set cloudreve user your-username
|
||||
rclone config set cloudreve pass your-password
|
||||
|
||||
# Sync files
|
||||
rclone sync /local/path cloudreve:/remote/path
|
||||
```
|
||||
|
||||
### Cyberduck
|
||||
- Connection type: WebDAV
|
||||
- Server: https://cloudreve.yourdomain.com/dav/
|
||||
- Username: your-username
|
||||
- Password: your-password
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check if Cloudreve is running
|
||||
curl http://localhost:5212/api/v3/site/ping
|
||||
|
||||
# Get system info
|
||||
curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||||
"http://localhost:5212/api/v3/admin/summary"
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f cloudreve
|
||||
|
||||
# Check specific logs
|
||||
docker exec cloudreve tail -f /cloudreve/logs/cloudreve.log
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Database connection**: Check PostgreSQL configuration
|
||||
- **Storage issues**: Verify storage backend configuration
|
||||
- **Upload problems**: Check permissions and disk space
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **Authentication errors**: Verify user credentials
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart service
|
||||
docker-compose restart cloudreve
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old files
|
||||
docker exec cloudreve find /cloudreve/uploads -name "*.tmp" -mtime +7 -delete
|
||||
|
||||
# Optimize database
|
||||
docker exec cloudreve-db psql -U cloudreve -c "VACUUM ANALYZE;"
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom Themes
|
||||
```yaml
|
||||
# In admin interface
|
||||
Theme: Custom
|
||||
CSS: |
|
||||
.custom-theme {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
```
|
||||
|
||||
### File Preview
|
||||
```yaml
|
||||
# Enable preview for different file types
|
||||
preview:
|
||||
enabled: true
|
||||
max_size: 10485760
|
||||
formats:
|
||||
- image: jpg,jpeg,png,gif,bmp,webp
|
||||
- video: mp4,avi,mkv,mov,wmv
|
||||
- audio: mp3,wav,flac,aac
|
||||
- document: pdf,doc,docx,xls,xlsx,ppt,pptx
|
||||
```
|
||||
|
||||
### Webhook Integration
|
||||
```yaml
|
||||
# Configure webhooks for file events
|
||||
webhooks:
|
||||
- name: file_upload
|
||||
url: https://yourdomain.com/webhook
|
||||
events: ["file.upload", "file.delete"]
|
||||
secret: your-webhook-secret
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Nextcloud Migration
|
||||
```bash
|
||||
# Export from Nextcloud
|
||||
# Import to Cloudreve using same directory structure
|
||||
```
|
||||
|
||||
### Home Assistant Integration
|
||||
```yaml
|
||||
# In Home Assistant configuration.yaml
|
||||
sensor:
|
||||
- platform: rest
|
||||
resource: http://cloudreve.yourdomain.com/api/v3/admin/summary
|
||||
headers:
|
||||
Authorization: Bearer YOUR_TOKEN
|
||||
value_template: "{{ value_json.storage_used }}"
|
||||
```
|
||||
|
||||
### Discord Bot Integration
|
||||
```python
|
||||
# Python Discord bot for file sharing
|
||||
import requests
|
||||
|
||||
class CloudreveBot:
|
||||
def __init__(self, api_url, token):
|
||||
self.api_url = api_url
|
||||
self.token = token
|
||||
self.headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
def upload_file(self, file_path):
|
||||
with open(file_path, 'rb') as f:
|
||||
files = {'file': f}
|
||||
response = requests.post(
|
||||
f"{self.api_url}/api/v3/file/upload",
|
||||
headers=self.headers,
|
||||
files=files
|
||||
)
|
||||
return response.json()
|
||||
|
||||
def create_share(self, file_id):
|
||||
data = {"file_id": file_id, "expire": 3600}
|
||||
response = requests.post(
|
||||
f"{self.api_url}/api/v3/share",
|
||||
headers=self.headers,
|
||||
json=data
|
||||
)
|
||||
return response.json()
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
1. **Regular backups**: Backup data and database regularly
|
||||
2. **Monitor storage**: Keep an eye on disk usage
|
||||
3. **Use HTTPS**: Always use HTTPS in production
|
||||
4. **Secure passwords**: Use strong passwords for admin accounts
|
||||
5. **Update regularly**: Keep Cloudreve updated
|
||||
6. **Monitor logs**: Keep an eye on error logs
|
||||
7. **Test backups**: Regularly test backup restoration
|
||||
8. **Configure quotas**: Set appropriate user quotas
|
||||
9. **Use multiple backends**: Distribute storage across multiple providers
|
||||
10. **Monitor performance**: Keep an eye on resource usage
|
||||
@@ -0,0 +1,465 @@
|
||||
# Gitea Git Hosting Template
|
||||
|
||||
## Overview
|
||||
Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket, and GitLab.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=gitea
|
||||
- GITEA__server__DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__ROOT_URL=https://git.yourdomain.com/
|
||||
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__SSH_PORT=2222
|
||||
- GITEA__server__SSH_LISTEN_PORT=22
|
||||
- GITEA__webhook__ALLOWED_HOST_LIST=git.yourdomain.com
|
||||
- GITEA__service__DISABLE_REGISTRATION=true
|
||||
- GITEA__service__REQUIRE_SIGNIN_VIEW=true
|
||||
- GITEA__mailer__ENABLED=true
|
||||
- GITEA__mailer__FROM=git@yourdomain.com
|
||||
- GITEA__mailer__MAILER_TYPE=smtp
|
||||
- GITEA__mailer__HOST=smtp.gmail.com:587
|
||||
- GITEA__mailer__USER=your-email@gmail.com
|
||||
- GITEA__mailer__PASSWD=your-app-password
|
||||
- GITEA__security__INSTALL_LOCK=true
|
||||
- GITEA__security__SECRET_KEY=your-secret-key
|
||||
ports:
|
||||
- "2222:22"
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- gitea-data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
depends_on:
|
||||
- gitea-db
|
||||
networks:
|
||||
- gitea-network
|
||||
|
||||
gitea-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: gitea-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=gitea
|
||||
- POSTGRES_USER=gitea
|
||||
- POSTGRES_PASSWORD=gitea
|
||||
volumes:
|
||||
- gitea-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- gitea-network
|
||||
|
||||
volumes:
|
||||
gitea-data:
|
||||
gitea-db:
|
||||
|
||||
networks:
|
||||
gitea-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `USER_UID`/`USER_GID`: User ID for file permissions
|
||||
- `GITEA__database__*`: Database configuration
|
||||
- `GITEA__server__*`: Server settings
|
||||
- `GITEA__service__*`: Service configuration
|
||||
- `GITEA__mailer__*`: Email configuration
|
||||
- `GITEA__security__*`: Security settings
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secret Key**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p gitea-data
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:3000
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Create admin account
|
||||
- Configure repository settings
|
||||
- Set up SSH keys
|
||||
|
||||
## Configuration
|
||||
|
||||
### App.ini Configuration
|
||||
```ini
|
||||
# /data/gitea/conf/app.ini
|
||||
[database]
|
||||
DB_TYPE = postgres
|
||||
HOST = gitea-db:5432
|
||||
NAME = gitea
|
||||
USER = gitea
|
||||
PASSWD = gitea
|
||||
|
||||
[server]
|
||||
DOMAIN = git.yourdomain.com
|
||||
ROOT_URL = https://git.yourdomain.com/
|
||||
SSH_DOMAIN = git.yourdomain.com
|
||||
SSH_PORT = 2222
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = your-lfs-jwt-secret
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = true
|
||||
ENABLE_NOTIFY_MAIL = true
|
||||
|
||||
[mailer]
|
||||
ENABLED = true
|
||||
FROM = git@yourdomain.com
|
||||
MAILER_TYPE = smtp
|
||||
HOST = smtp.gmail.com:587
|
||||
USER = your-email@gmail.com
|
||||
PASSWD = your-app-password
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = your-secret-key
|
||||
```
|
||||
|
||||
### SSH Configuration
|
||||
```bash
|
||||
# Add SSH key to Gitea
|
||||
ssh-keygen -t ed25519 -C "your-email@example.com"
|
||||
|
||||
# Add public key to Gitea web interface
|
||||
# Test SSH connection
|
||||
ssh -T git@git.yourdomain.com -p 2222
|
||||
```
|
||||
|
||||
## Repository Management
|
||||
|
||||
### Create Repository
|
||||
```bash
|
||||
# Create new repository via API
|
||||
curl -X POST http://localhost:3000/api/v1/user/repos \
|
||||
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"my-repo","description":"My first repository","private":false}'
|
||||
```
|
||||
|
||||
### Clone Repository
|
||||
```bash
|
||||
# HTTPS clone
|
||||
git clone https://git.yourdomain.com/username/my-repo.git
|
||||
|
||||
# SSH clone
|
||||
git clone ssh://git@git.yourdomain.com:2222/username/my-repo.git
|
||||
```
|
||||
|
||||
### Push to Repository
|
||||
```bash
|
||||
cd my-repo
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git remote add origin https://git.yourdomain.com/username/my-repo.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
## User Management
|
||||
|
||||
### Create User
|
||||
```bash
|
||||
# Create user via API
|
||||
curl -X POST http://localhost:3000/api/v1/admin/users \
|
||||
-H "Authorization: token YOUR_ADMIN_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"newuser","email":"user@example.com","password":"password","must_change_password":false}'
|
||||
```
|
||||
|
||||
### Organizations
|
||||
```bash
|
||||
# Create organization
|
||||
curl -X POST http://localhost:3000/api/v1/orgs \
|
||||
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"myorg","description":"My organization"}'
|
||||
```
|
||||
|
||||
## Actions (CI/CD)
|
||||
|
||||
### Enable Actions
|
||||
```yaml
|
||||
# In app.ini
|
||||
[actions]
|
||||
ENABLED = true
|
||||
|
||||
# Create .gitea/workflows/build.yml
|
||||
name: Build and Test
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
- name: Build
|
||||
run: npm run build
|
||||
```
|
||||
|
||||
### Package Registry
|
||||
```bash
|
||||
# Publish npm package
|
||||
npm publish --registry https://git.yourdomain.com/api/packages/npm
|
||||
|
||||
# Publish Docker image
|
||||
docker push git.yourdomain.com/username/my-image:latest
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.gitea.rule=Host(`git.yourdomain.com`)"
|
||||
- "traefik.http.routers.gitea.tls=true"
|
||||
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Gitea data
|
||||
docker run --rm -v gitea-data:/data -v $(pwd):/backup alpine tar czf /backup/gitea-backup.tar.gz -C /data .
|
||||
|
||||
# Backup PostgreSQL database
|
||||
docker exec gitea-db pg_dump -U gitea gitea > gitea-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i gitea-db psql -U gitea gitea < gitea-db-backup.sql
|
||||
|
||||
# Restore Gitea data
|
||||
docker run --rm -v gitea-data:/data -v $(pwd):/backup alpine tar xzf /backup/gitea-backup.tar.gz -C /data
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart gitea
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- GITEA__cache__ENABLED=true
|
||||
- GITEA__cache__ADAPTER=redis
|
||||
- GITEA__cache__HOST=redis://redis:6379/0
|
||||
- GITEA__queue__TYPE=redis
|
||||
- GITEA__queue__CONN_STR=redis://redis:6379/1
|
||||
|
||||
# Add Redis service
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: gitea-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- gitea-redis:/data
|
||||
networks:
|
||||
- gitea-network
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### SSH Keys
|
||||
```bash
|
||||
# Generate SSH key pair
|
||||
ssh-keygen -t ed25519 -C "gitea@yourdomain.com"
|
||||
|
||||
# Add to Gitea admin settings
|
||||
# Configure in app.ini
|
||||
[ssh]
|
||||
MINIMUM_KEY_SIZE = 2048
|
||||
AUTHORIZED_KEYS_ALLOW = true
|
||||
```
|
||||
|
||||
### Access Control
|
||||
```yaml
|
||||
environment:
|
||||
- GITEA__service__DISABLE_REGISTRATION=true
|
||||
- GITEA__service__REQUIRE_SIGNIN_VIEW=true
|
||||
- GITEA__security__LOGIN_REMEMBER_DAYS=30
|
||||
- GITEA__security__COOKIE_USERNAME=git
|
||||
- GITEA__security__COOKIE_REMEMBER_NAME=gitea_incredible
|
||||
```
|
||||
|
||||
### Two-Factor Authentication
|
||||
```yaml
|
||||
environment:
|
||||
- GITEA__security__TWO_FACTOR_ENABLED=true
|
||||
- GITEA__security__TWO_FACTOR_REQUIRE_SIGN_IN=true
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check Gitea health
|
||||
curl http://localhost:3000/api/v1/version
|
||||
|
||||
# Check database connection
|
||||
docker exec gitea-db pg_isready -U gitea
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f gitea
|
||||
|
||||
# Check specific logs
|
||||
docker exec gitea tail -f /data/gitea/log/gitea.log
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **SSH connection issues**: Check SSH key configuration
|
||||
- **Database connection**: Verify PostgreSQL settings
|
||||
- **Performance problems**: Monitor resource usage
|
||||
- **Email issues**: Check SMTP configuration
|
||||
- **Repository access**: Verify permissions
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Update images
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec gitea gitea admin cleanup
|
||||
|
||||
# Check repository integrity
|
||||
docker exec gitea gitea admin repo check
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### LFS (Large File Storage)
|
||||
```yaml
|
||||
environment:
|
||||
- GITEA__server__LFS_START_SERVER=true
|
||||
- GITEA__server__LFS_JWT_SECRET=your-lfs-jwt-secret
|
||||
|
||||
# Install LFS client
|
||||
git lfs install
|
||||
|
||||
# Track large files
|
||||
git lfs track "*.zip"
|
||||
git add .gitattributes
|
||||
git commit -m "Add LFS tracking"
|
||||
```
|
||||
|
||||
### Mirror Repositories
|
||||
```bash
|
||||
# Create mirror
|
||||
curl -X POST http://localhost:3000/api/v1/repos/migrate \
|
||||
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"clone_addr":"https://github.com/user/repo.git","repo_name":"my-mirror","mirror":true}'
|
||||
```
|
||||
|
||||
### Webhooks
|
||||
```bash
|
||||
# Create webhook
|
||||
curl -X POST http://localhost:3000/api/v1/repos/username/repo/hooks \
|
||||
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"gitea","config":{"content_type":"json","url":"https://your-domain.com/webhook","events":["push"]}}'
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### GitHub Migration
|
||||
```bash
|
||||
# Migrate from GitHub
|
||||
curl -X POST http://localhost:3000/api/v1/repos/migrate \
|
||||
-H "Authorization: token YOUR_ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"clone_addr":"https://github.com/user/repo.git","repo_name":"repo","service_type":"github","auth_token":"GITHUB_TOKEN"}'
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
```yaml
|
||||
# GitHub Actions compatible workflows
|
||||
name: CI/CD Pipeline
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
```
|
||||
|
||||
### Package Registry
|
||||
```bash
|
||||
# Setup npm registry
|
||||
npm config set registry https://git.yourdomain.com/api/packages/npm
|
||||
|
||||
# Login to registry
|
||||
npm login --registry https://git.yourdomain.com/api/packages/npm
|
||||
|
||||
# Publish package
|
||||
npm publish
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Custom Themes
|
||||
```yaml
|
||||
# In app.ini
|
||||
[ui]
|
||||
DEFAULT_THEME = gitea-auto
|
||||
THEMES = gitea,gitea-auto,gitea-dark
|
||||
|
||||
# Custom CSS
|
||||
[ui.meta]
|
||||
AUTHOR = Your Name
|
||||
DESCRIPTION = Your Git Service
|
||||
KEYWORDS = git,forge,development
|
||||
```
|
||||
|
||||
### Custom Pages
|
||||
```yaml
|
||||
# Custom home page
|
||||
[ui]
|
||||
CUSTOM_EMOJIS = :gitea:,:git:
|
||||
SHOW_MILESTONES_DASHBOARD_PAGE = true
|
||||
SHOW_ISSUES_SUMMARY_PAGE = true
|
||||
```
|
||||
@@ -0,0 +1,574 @@
|
||||
# Glance Dashboard Template
|
||||
|
||||
## Overview
|
||||
Glance is a self-hosted dashboard that puts all your feeds in one place. It's designed to be simple, fast, and easy to use.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
glance:
|
||||
image: glanceapp/glance:latest
|
||||
container_name: glance
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
volumes:
|
||||
- ./glance.yml:/app/glance.yml:ro
|
||||
- ./glance-data:/app/data
|
||||
networks:
|
||||
- glance-network
|
||||
|
||||
volumes:
|
||||
glance-data:
|
||||
|
||||
networks:
|
||||
glance-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Configuration File (glance.yml)
|
||||
```yaml
|
||||
server:
|
||||
port: 8080
|
||||
host: 0.0.0.0
|
||||
|
||||
pages:
|
||||
- name: Home
|
||||
columns: 3
|
||||
widgets:
|
||||
- type: calendar
|
||||
week-start: monday
|
||||
time-format: 12h
|
||||
show-week-numbers: true
|
||||
show-weekdays: true
|
||||
locale: en-US
|
||||
|
||||
- type: bookmarks
|
||||
bookmarks:
|
||||
- title: GitHub
|
||||
url: https://github.com
|
||||
icon: https://github.com/favicon.ico
|
||||
- title: Reddit
|
||||
url: https://reddit.com
|
||||
icon: https://reddit.com/favicon.ico
|
||||
- title: YouTube
|
||||
url: https://youtube.com
|
||||
icon: https://youtube.com/favicon.ico
|
||||
|
||||
- type: weather
|
||||
location: New York, NY
|
||||
units: imperial
|
||||
forecast-days: 5
|
||||
show-hourly: true
|
||||
api-key: your-openweather-api-key
|
||||
|
||||
- type: rss
|
||||
feeds:
|
||||
- title: Tech News
|
||||
url: https://techcrunch.com/feed/
|
||||
limit: 5
|
||||
- title: Hacker News
|
||||
url: https://hnrss.org/frontpage
|
||||
limit: 5
|
||||
refresh-interval: 15m
|
||||
|
||||
- type: search
|
||||
engines:
|
||||
- name: Google
|
||||
url: https://www.google.com/search?q=
|
||||
- name: DuckDuckGo
|
||||
url: https://duckduckgo.com/?q=
|
||||
- name: Wikipedia
|
||||
url: https://en.wikipedia.org/wiki/
|
||||
|
||||
- type: clock
|
||||
format: 12h
|
||||
show-date: true
|
||||
show-seconds: false
|
||||
timezone: America/New_York
|
||||
|
||||
- type: system
|
||||
show-cpu: true
|
||||
show-memory: true
|
||||
show-disk: true
|
||||
show-network: true
|
||||
refresh-interval: 5s
|
||||
|
||||
- type: docker
|
||||
containers:
|
||||
- name: pihole
|
||||
icon: pi-hole
|
||||
- name: nextcloud
|
||||
icon: nextcloud
|
||||
- name: jellyfin
|
||||
icon: jellyfin
|
||||
show-status: true
|
||||
show-stats: true
|
||||
|
||||
- type: iframe
|
||||
title: Grafana Dashboard
|
||||
url: http://grafana.yourdomain.com/d/overview
|
||||
height: 400
|
||||
|
||||
- type: html
|
||||
title: Custom HTML
|
||||
content: |
|
||||
<h3>Welcome to Glance!</h3>
|
||||
<p>This is your personal dashboard.</p>
|
||||
<button onclick="alert('Hello!')">Click me</button>
|
||||
height: 200
|
||||
|
||||
- name: Work
|
||||
columns: 2
|
||||
widgets:
|
||||
- type: calendar
|
||||
week-start: monday
|
||||
time-format: 24h
|
||||
locale: en-US
|
||||
|
||||
- type: bookmarks
|
||||
bookmarks:
|
||||
- title: Company Portal
|
||||
url: https://portal.company.com
|
||||
icon: https://portal.company.com/favicon.ico
|
||||
- title: Email
|
||||
url: https://mail.company.com
|
||||
icon: https://mail.company.com/favicon.ico
|
||||
- title: Jira
|
||||
url: https://jira.company.com
|
||||
icon: https://jira.company.com/favicon.ico
|
||||
|
||||
- type: rss
|
||||
feeds:
|
||||
- title: Company News
|
||||
url: https://company.com/news/feed
|
||||
limit: 3
|
||||
- title: Industry News
|
||||
url: https://industry.com/feed
|
||||
limit: 3
|
||||
|
||||
- type: clock
|
||||
format: 24h
|
||||
show-date: true
|
||||
timezone: America/New_York
|
||||
|
||||
- name: Media
|
||||
columns: 2
|
||||
widgets:
|
||||
- type: bookmarks
|
||||
bookmarks:
|
||||
- title: Jellyfin
|
||||
url: http://jellyfin.yourdomain.com
|
||||
icon: http://jellyfin.yourdomain.com/favicon.ico
|
||||
- title: Plex
|
||||
url: http://plex.yourdomain.com
|
||||
icon: http://plex.yourdomain.com/favicon.ico
|
||||
- title: Spotify
|
||||
url: https://open.spotify.com
|
||||
icon: https://open.spotify.com/favicon.ico
|
||||
|
||||
- type: weather
|
||||
location: Los Angeles, CA
|
||||
units: imperial
|
||||
forecast-days: 3
|
||||
api-key: your-openweather-api-key
|
||||
|
||||
- type: rss
|
||||
feeds:
|
||||
- title: Movie News
|
||||
url: https://movieweb.com/feed
|
||||
limit: 5
|
||||
- title: Music News
|
||||
url: https://pitchfork.com/feed
|
||||
limit: 5
|
||||
```
|
||||
|
||||
## Widget Types
|
||||
|
||||
### Calendar Widget
|
||||
```yaml
|
||||
- type: calendar
|
||||
week-start: monday # monday/sunday
|
||||
time-format: 12h # 12h/24h
|
||||
show-week-numbers: true # true/false
|
||||
show-weekdays: true # true/false
|
||||
locale: en-US # Locale code
|
||||
timezone: America/New_York # Timezone
|
||||
```
|
||||
|
||||
### Bookmarks Widget
|
||||
```yaml
|
||||
- type: bookmarks
|
||||
bookmarks:
|
||||
- title: Site Name
|
||||
url: https://example.com
|
||||
icon: https://example.com/favicon.ico
|
||||
description: Optional description
|
||||
category: Optional category
|
||||
```
|
||||
|
||||
### Weather Widget
|
||||
```yaml
|
||||
- type: weather
|
||||
location: "New York, NY" # City, State or City, Country
|
||||
units: imperial # imperial/metric
|
||||
forecast-days: 5 # Number of days (1-7)
|
||||
show-hourly: true # Show hourly forecast
|
||||
api-key: your-openweather-api-key
|
||||
```
|
||||
|
||||
### RSS Widget
|
||||
```yaml
|
||||
- type: rss
|
||||
feeds:
|
||||
- title: Feed Name
|
||||
url: https://example.com/feed.xml
|
||||
limit: 5 # Number of items
|
||||
refresh-interval: 15m # Refresh interval
|
||||
show-description: true # Show item descriptions
|
||||
show-thumbnail: true # Show thumbnails
|
||||
```
|
||||
|
||||
### Search Widget
|
||||
```yaml
|
||||
- type: search
|
||||
engines:
|
||||
- name: Google
|
||||
url: https://www.google.com/search?q=
|
||||
icon: https://google.com/favicon.ico
|
||||
- name: DuckDuckGo
|
||||
url: https://duckduckgo.com/?q=
|
||||
icon: https://duckduckgo.com/favicon.ico
|
||||
- name: Wikipedia
|
||||
url: https://en.wikipedia.org/wiki/
|
||||
icon: https://wikipedia.org/favicon.ico
|
||||
```
|
||||
|
||||
### Clock Widget
|
||||
```yaml
|
||||
- type: clock
|
||||
format: 12h # 12h/24h
|
||||
show-date: true # true/false
|
||||
show-seconds: false # true/false
|
||||
timezone: America/New_York # Timezone
|
||||
```
|
||||
|
||||
### System Widget
|
||||
```yaml
|
||||
- type: system
|
||||
show-cpu: true # Show CPU usage
|
||||
show-memory: true # Show memory usage
|
||||
show-disk: true # Show disk usage
|
||||
show-network: true # Show network usage
|
||||
refresh-interval: 5s # Refresh interval
|
||||
```
|
||||
|
||||
### Docker Widget
|
||||
```yaml
|
||||
- type: docker
|
||||
containers:
|
||||
- name: container-name
|
||||
icon: icon-name
|
||||
status-url: http://container:port/status
|
||||
show-status: true # Show container status
|
||||
show-stats: true # Show container stats
|
||||
```
|
||||
|
||||
### Iframe Widget
|
||||
```yaml
|
||||
- type: iframe
|
||||
title: Widget Title
|
||||
url: https://example.com
|
||||
height: 400 # Height in pixels
|
||||
width: 100% # Width in percentage
|
||||
border: none # Border style
|
||||
```
|
||||
|
||||
### HTML Widget
|
||||
```yaml
|
||||
- type: html
|
||||
title: Widget Title
|
||||
content: |
|
||||
<h3>Custom HTML Content</h3>
|
||||
<p>This can include any HTML content.</p>
|
||||
<script>
|
||||
// JavaScript code here
|
||||
console.log('Hello from Glance!');
|
||||
</script>
|
||||
height: 200 # Height in pixels
|
||||
```
|
||||
|
||||
## Setup Guide
|
||||
1. **Create Configuration**:
|
||||
```bash
|
||||
# Create glance.yml
|
||||
touch glance.yml
|
||||
# Copy the example configuration above
|
||||
```
|
||||
|
||||
2. **Get Weather API Key**:
|
||||
```bash
|
||||
# Get API key from https://openweathermap.org/api
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:8080
|
||||
|
||||
5. **Customize**: Edit glance.yml to your preferences
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.glance.rule=Host(`glance.yourdomain.com`)"
|
||||
- "traefik.http.routers.glance.tls=true"
|
||||
- "traefik.http.routers.glance.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.glance.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup configuration
|
||||
cp glance.yml glance.yml.backup
|
||||
|
||||
# Backup data
|
||||
docker run --rm -v glance-data:/app/data -v $(pwd):/backup alpine tar czf /backup/glance-data-backup.tar.gz -C /app/data .
|
||||
|
||||
# Restore data
|
||||
docker run --rm -v glance-data:/app/data -v $(pwd):/backup alpine tar xzf /backup/glance-data-backup.tar.gz -C /app/data
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart glance
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 128M
|
||||
cpus: '0.2'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Customization
|
||||
|
||||
### Custom CSS
|
||||
```yaml
|
||||
# Add custom CSS to your HTML widget
|
||||
- type: html
|
||||
content: |
|
||||
<style>
|
||||
.custom-widget {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
<div class="custom-widget">
|
||||
<h3>Custom Styled Widget</h3>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Custom JavaScript
|
||||
```yaml
|
||||
- type: html
|
||||
content: |
|
||||
<script>
|
||||
// Auto-refresh widget
|
||||
setInterval(() => {
|
||||
fetch('https://api.example.com/data')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('data').textContent = data.value;
|
||||
});
|
||||
}, 5000);
|
||||
</script>
|
||||
<div id="data">Loading...</div>
|
||||
```
|
||||
|
||||
## Advanced Examples
|
||||
|
||||
### Stock Ticker Widget
|
||||
```yaml
|
||||
- type: html
|
||||
title: Stock Prices
|
||||
content: |
|
||||
<div id="stocks">
|
||||
<div>AAPL: <span id="aapl">Loading...</span></div>
|
||||
<div>GOOGL: <span id="googl">Loading...</span></div>
|
||||
<div>MSFT: <span id="msft">Loading...</span></div>
|
||||
</div>
|
||||
<script>
|
||||
// Fetch stock prices (you'd need a real API)
|
||||
const stocks = ['AAPL', 'GOOGL', 'MSFT'];
|
||||
stocks.forEach(stock => {
|
||||
fetch(`https://api.example.com/stocks/${stock}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById(stock.toLowerCase()).textContent = data.price;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
height: 150
|
||||
```
|
||||
|
||||
### Server Status Widget
|
||||
```yaml
|
||||
- type: html
|
||||
title: Server Status
|
||||
content: |
|
||||
<div id="server-status">
|
||||
<div>Web Server: <span id="web-status">Checking...</span></div>
|
||||
<div>Database: <span id="db-status">Checking...</span></div>
|
||||
<div>API: <span id="api-status">Checking...</span></div>
|
||||
</div>
|
||||
<script>
|
||||
const services = [
|
||||
{ name: 'web', url: 'https://example.com' },
|
||||
{ name: 'db', url: 'http://localhost:5432' },
|
||||
{ name: 'api', url: 'https://api.example.com' }
|
||||
];
|
||||
|
||||
services.forEach(service => {
|
||||
fetch(service.url)
|
||||
.then(response => {
|
||||
const status = response.ok ? '✅ Online' : '❌ Offline';
|
||||
document.getElementById(`${service.name}-status`).textContent = status;
|
||||
})
|
||||
.catch(() => {
|
||||
document.getElementById(`${service.name}-status`).textContent = '❌ Offline';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
height: 150
|
||||
```
|
||||
|
||||
### Calendar Integration
|
||||
```yaml
|
||||
- type: html
|
||||
title: Google Calendar
|
||||
content: |
|
||||
<iframe src="https://calendar.google.com/calendar/embed?src=your-email@gmail.com"
|
||||
style="border: 0" width="100%" height="300" frameborder="0" scrolling="no">
|
||||
</iframe>
|
||||
height: 300
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Configuration errors**: Check YAML syntax
|
||||
- **Widget not loading**: Verify widget configuration
|
||||
- **Performance issues**: Reduce refresh intervals
|
||||
- **API errors**: Check API keys and URLs
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart service
|
||||
docker-compose restart
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Check logs
|
||||
docker-compose logs -f glance
|
||||
|
||||
# Validate configuration
|
||||
docker exec glance glance --validate-config
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
1. **Keep it simple**: Don't overload your dashboard
|
||||
2. **Use appropriate refresh intervals**: Don't refresh too frequently
|
||||
3. **Monitor performance**: Keep an eye on resource usage
|
||||
4. **Secure your dashboard**: Use authentication in production
|
||||
5. **Backup regularly**: Save your configuration
|
||||
6. **Test widgets**: Ensure all widgets work properly
|
||||
7. **Use HTTPS**: Always use HTTPS in production
|
||||
8. **Organize pages**: Group related widgets on separate pages
|
||||
|
||||
## Mobile Support
|
||||
- Glance is mobile-responsive
|
||||
- Use touch-friendly widgets
|
||||
- Consider mobile data usage
|
||||
- Test on different screen sizes
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Home Assistant Integration
|
||||
```yaml
|
||||
- type: html
|
||||
title: Home Assistant
|
||||
content: |
|
||||
<iframe src="http://homeassistant.local:8123/lovelace-dashboard"
|
||||
style="border: 0" width="100%" height="400" frameborder="0">
|
||||
</iframe>
|
||||
height: 400
|
||||
```
|
||||
|
||||
### Grafana Integration
|
||||
```yaml
|
||||
- type: html
|
||||
title: System Metrics
|
||||
content: |
|
||||
<iframe src="http://grafana.local:3000/d-solo/system-overview"
|
||||
style="border: 0" width="100%" height="300" frameborder="0">
|
||||
</iframe>
|
||||
height: 300
|
||||
```
|
||||
|
||||
### Custom API Integration
|
||||
```yaml
|
||||
- type: html
|
||||
title: API Status
|
||||
content: |
|
||||
<div id="api-status">
|
||||
<div>API Response Time: <span id="response-time">Checking...</span></div>
|
||||
<div>Last Updated: <span id="last-updated">-</span></div>
|
||||
</div>
|
||||
<script>
|
||||
const checkAPI = () => {
|
||||
const start = Date.now();
|
||||
fetch('https://api.example.com/health')
|
||||
.then(response => {
|
||||
const responseTime = Date.now() - start;
|
||||
document.getElementById('response-time').textContent = `${responseTime}ms`;
|
||||
document.getElementById('last-updated').textContent = new Date().toLocaleTimeString();
|
||||
})
|
||||
.catch(() => {
|
||||
document.getElementById('response-time').textContent = 'Error';
|
||||
});
|
||||
};
|
||||
|
||||
checkAPI();
|
||||
setInterval(checkAPI, 30000); // Check every 30 seconds
|
||||
</script>
|
||||
height: 100
|
||||
```
|
||||
@@ -0,0 +1,416 @@
|
||||
# Grafana Monitoring Template
|
||||
|
||||
## Overview
|
||||
Grafana is an open source observability platform for visualizing metrics, logs, and traces.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=your-secure-password
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource,grafana-worldmap-panel
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
- ./provisioning:/etc/grafana/provisioning
|
||||
networks:
|
||||
- grafana-network
|
||||
depends_on:
|
||||
- prometheus
|
||||
- loki
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9090:9090"
|
||||
environment:
|
||||
- PROMETHEUS_RETENTION_TIME=30d
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
- '--web.enable-lifecycle'
|
||||
networks:
|
||||
- grafana-network
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
container_name: loki
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3100:3100"
|
||||
volumes:
|
||||
- ./loki.yml:/etc/loki/local-config.yaml
|
||||
- loki-data:/loki
|
||||
command: -config.file=/etc/loki/local-config.yaml
|
||||
networks:
|
||||
- grafana-network
|
||||
|
||||
promtail:
|
||||
image: grafana/promtail:latest
|
||||
container_name: promtail
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./promtail.yml:/etc/promtail/config.yml
|
||||
- /var/log:/var/log:ro
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
command: -config.file=/etc/promtail/config.yml
|
||||
networks:
|
||||
- grafana-network
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:latest
|
||||
container_name: node-exporter
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "9100:9100"
|
||||
volumes:
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /:/rootfs:ro
|
||||
command:
|
||||
- '--path.procfs=/host/proc'
|
||||
- '--path.rootfs=/rootfs'
|
||||
- '--path.sysfs=/host/sys'
|
||||
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
|
||||
networks:
|
||||
- grafana-network
|
||||
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
container_name: cadvisor
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:rw
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker/:/var/lib/docker:ro
|
||||
privileged: true
|
||||
devices:
|
||||
- /dev/kmsg
|
||||
networks:
|
||||
- grafana-network
|
||||
|
||||
volumes:
|
||||
grafana-data:
|
||||
prometheus-data:
|
||||
loki-data:
|
||||
|
||||
networks:
|
||||
grafana-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Prometheus Configuration (`prometheus.yml`)
|
||||
```yaml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
rule_files:
|
||||
- "rules/*.yml"
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
- job_name: 'node-exporter'
|
||||
static_configs:
|
||||
- targets: ['node-exporter:9100']
|
||||
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
|
||||
- job_name: 'grafana'
|
||||
static_configs:
|
||||
- targets: ['grafana:3000']
|
||||
|
||||
- job_name: 'docker'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
```
|
||||
|
||||
### Loki Configuration (`loki.yml`)
|
||||
```yaml
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
|
||||
ingester:
|
||||
lifecycler:
|
||||
address: 127.0.0.1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
replication_factor: 1
|
||||
final_sleep: 0s
|
||||
heartbeat_period: 15s
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-10-24
|
||||
store: boltdb-shipper
|
||||
object_store: filesystem
|
||||
schema: v11
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
storage_config:
|
||||
boltdb_shipper:
|
||||
active_index_directory: /loki/boltdb-shipper-active
|
||||
cache_location: /loki/boltdb-shipper-cache
|
||||
shared_store: filesystem
|
||||
filesystem:
|
||||
directory: /loki/chunks
|
||||
|
||||
limits_config:
|
||||
enforce_metric_name: false
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
chunk_store_config:
|
||||
max_look_back_period: 0s
|
||||
|
||||
table_manager:
|
||||
retention_deletes_enabled: false
|
||||
retention_period: 0s
|
||||
```
|
||||
|
||||
### Promtail Configuration (`promtail.yml`)
|
||||
```yaml
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://loki:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
- job_name: containers
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: containerlogs
|
||||
__path__: /var/lib/docker/containers/*/*log
|
||||
|
||||
pipeline_stages:
|
||||
- json:
|
||||
expressions:
|
||||
output: log
|
||||
stream: stream
|
||||
attrs:
|
||||
- json:
|
||||
expressions:
|
||||
tag:
|
||||
source: attrs
|
||||
- regex:
|
||||
expression: (?P<container_name>(?:[^|]*))\|
|
||||
source: tag
|
||||
- timestamp:
|
||||
format: RFC3339Nano
|
||||
source: time
|
||||
- labels:
|
||||
stream:
|
||||
container_name:
|
||||
- output:
|
||||
source: output
|
||||
|
||||
- job_name: system
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: varlogs
|
||||
__path__: /var/log/*log
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `GF_SECURITY_ADMIN_USER`: Grafana admin username
|
||||
- `GF_SECURITY_ADMIN_PASSWORD`: Grafana admin password
|
||||
- `GF_USERS_ALLOW_SIGN_UP`: Disable public sign-up
|
||||
- `GF_INSTALL_PLUGINS`: Pre-install plugins
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secure Password**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p provisioning/{datasources,dashboards}
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:3000
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Login with admin credentials
|
||||
- Add data sources
|
||||
- Import dashboards
|
||||
|
||||
## Data Sources
|
||||
|
||||
### Prometheus Data Source
|
||||
```yaml
|
||||
# provisioning/datasources/prometheus.yml
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://prometheus:9090
|
||||
isDefault: true
|
||||
```
|
||||
|
||||
### Loki Data Source
|
||||
```yaml
|
||||
# provisioning/datasources/loki.yml
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
url: http://loki:3100
|
||||
```
|
||||
|
||||
## Dashboards
|
||||
|
||||
### System Dashboard
|
||||
- CPU usage
|
||||
- Memory usage
|
||||
- Disk usage
|
||||
- Network traffic
|
||||
- Container metrics
|
||||
|
||||
### Docker Dashboard
|
||||
- Container stats
|
||||
- Image sizes
|
||||
- Network usage
|
||||
- Volume usage
|
||||
|
||||
### Application Dashboard
|
||||
- Custom metrics
|
||||
- Error rates
|
||||
- Response times
|
||||
- Request counts
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.grafana.rule=Host(`grafana.yourdomain.com`)"
|
||||
- "traefik.http.routers.grafana.tls=true"
|
||||
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Grafana data
|
||||
docker run --rm -v grafana-data:/data -v $(pwd):/backup alpine tar czf /backup/grafana-backup.tar.gz -C /data .
|
||||
|
||||
# Backup Prometheus data
|
||||
docker run --rm -v prometheus-data:/prometheus -v $(pwd):/backup alpine tar czf /backup/prometheus-backup.tar.gz -C /prometheus .
|
||||
|
||||
# Restore Grafana data
|
||||
docker run --rm -v grafana-data:/data -v $(pwd):/backup alpine tar xzf /backup/grafana-backup.tar.gz -C /data
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# Grafana performance
|
||||
environment:
|
||||
- GF_LOG_LEVEL=error
|
||||
- GF_METRICS_ENABLED=false
|
||||
|
||||
# Prometheus performance
|
||||
environment:
|
||||
- PROMETHEUS_STORAGE_TSDB_WAL_COMPRESSION=true
|
||||
- PROMETHEUS_WEB_MAX_CONCURRENCY=20
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default admin password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Monitoring Targets
|
||||
```yaml
|
||||
# Add to prometheus.yml for additional services
|
||||
- job_name: 'nginx'
|
||||
static_configs:
|
||||
- targets: ['nginx:9113']
|
||||
|
||||
- job_name: 'redis'
|
||||
static_configs:
|
||||
- targets: ['redis:9121']
|
||||
|
||||
- job_name: 'postgres'
|
||||
static_configs:
|
||||
- targets: ['postgres-exporter:9187']
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Data source issues**: Check network connectivity
|
||||
- **Dashboard problems**: Verify data source configuration
|
||||
- **Performance issues**: Check resource usage
|
||||
- **Storage problems**: Monitor disk space
|
||||
- **Authentication errors**: Verify credentials
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f grafana
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Update images
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec prometheus curl -X POST http://localhost:9090/api/v1/admin/tsdb/clean_tombstones
|
||||
```
|
||||
@@ -0,0 +1,247 @@
|
||||
# Home Assistant Template
|
||||
|
||||
## Overview
|
||||
Home Assistant is an open source home automation that puts local control and privacy first.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
homeassistant:
|
||||
image: ghcr.io/home-assistant/home-assistant:stable
|
||||
container_name: homeassistant
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "8123:8123"
|
||||
privileged: true
|
||||
network_mode: host
|
||||
depends_on:
|
||||
- mqtt
|
||||
- postgres
|
||||
networks:
|
||||
- homeassistant-network
|
||||
|
||||
mqtt:
|
||||
image: eclipse-mosquitto:2.0
|
||||
container_name: homeassistant-mqtt
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./mqtt/config:/mosquitto/config
|
||||
- ./mqtt/data:/mosquitto/data
|
||||
- ./mqtt/log:/mosquitto/log
|
||||
ports:
|
||||
- "1883:1883"
|
||||
- "9001:9001"
|
||||
networks:
|
||||
- homeassistant-network
|
||||
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: homeassistant-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=homeassistant
|
||||
- POSTGRES_USER=homeassistant
|
||||
- POSTGRES_PASSWORD=homeassistant
|
||||
volumes:
|
||||
- homeassistant-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- homeassistant-network
|
||||
|
||||
zigbee2mqtt:
|
||||
image: koenkk/zigbee2mqtt:latest
|
||||
container_name: zigbee2mqtt
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
volumes:
|
||||
- ./zigbee2mqtt/data:/app/data
|
||||
- /run/udev:/run/udev:ro
|
||||
ports:
|
||||
- "8080:8080"
|
||||
devices:
|
||||
- /dev/ttyUSB0:/dev/ttyUSB0
|
||||
networks:
|
||||
- homeassistant-network
|
||||
|
||||
volumes:
|
||||
homeassistant-db:
|
||||
|
||||
networks:
|
||||
homeassistant-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `TZ`: Timezone (find yours: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
|
||||
|
||||
## Setup Guide
|
||||
1. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p config mqtt/{config,data,log} zigbee2mqtt/data
|
||||
```
|
||||
|
||||
2. **Configure MQTT** (`mqtt/config/mosquitto.conf`):
|
||||
```conf
|
||||
listener 1883
|
||||
allow_anonymous false
|
||||
password_file /mosquitto/config/passwd
|
||||
|
||||
listener 9001
|
||||
protocol websockets
|
||||
```
|
||||
|
||||
3. **Create MQTT Password**:
|
||||
```bash
|
||||
docker exec homeassistant-mqtt mosquitto_passwd -c /mosquitto/config/passwd homeassistant
|
||||
```
|
||||
|
||||
4. **Configure Zigbee2MQTT** (`zigbee2mqtt/data/configuration.yaml`):
|
||||
```yaml
|
||||
homeassistant: true
|
||||
permit_join: false
|
||||
mqtt:
|
||||
base_topic: zigbee2mqtt
|
||||
server: mqtt://homeassistant-mqtt:1883
|
||||
user: homeassistant
|
||||
password: your-mqtt-password
|
||||
serial:
|
||||
port: /dev/ttyUSB0
|
||||
```
|
||||
|
||||
5. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
6. **Access**: Open http://localhost:8123
|
||||
|
||||
7. **Initial Setup**:
|
||||
- Create Home Assistant user account
|
||||
- Detect devices and integrations
|
||||
- Configure automations
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Home Assistant (`config/configuration.yaml`)
|
||||
```yaml
|
||||
homeassistant:
|
||||
name: Home
|
||||
latitude: 40.7128
|
||||
longitude: -74.0060
|
||||
elevation: 10
|
||||
unit_system: metric
|
||||
time_zone: America/New_York
|
||||
country: US
|
||||
|
||||
default_config:
|
||||
|
||||
http:
|
||||
server_port: 8123
|
||||
|
||||
mqtt:
|
||||
broker: homeassistant-mqtt
|
||||
port: 1883
|
||||
username: homeassistant
|
||||
password: your-mqtt-password
|
||||
|
||||
recorder:
|
||||
db_url: postgresql://homeassistant:homeassistant@homeassistant-postgres/homeassistant
|
||||
|
||||
logger:
|
||||
default: info
|
||||
```
|
||||
|
||||
## Device Integration
|
||||
- **Zigbee Devices**: Via Zigbee2MQTT
|
||||
- **WiFi Devices**: Direct integration
|
||||
- **Z-Wave**: Add Z-Wave integration
|
||||
- **Cameras**: RTSP/ONVIF support
|
||||
- **Sensors**: MQTT/HTTP/USB sensors
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
# Note: Home Assistant works best with host networking
|
||||
# If using bridge mode, add these labels:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.homeassistant.rule=Host(`home.yourdomain.com`)"
|
||||
- "traefik.http.routers.homeassistant.tls=true"
|
||||
- "traefik.http.routers.homeassistant.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.homeassistant.loadbalancer.server.port=8123"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Home Assistant config
|
||||
tar czf homeassistant-backup.tar.gz config/
|
||||
|
||||
# Backup database
|
||||
docker exec homeassistant-postgres pg_dump -U homeassistant homeassistant > ha-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i homeassistant-postgres psql -U homeassistant homeassistant < ha-db-backup.sql
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For systems with limited resources
|
||||
environment:
|
||||
- WEBSERVER_THREAD_POOL_SIZE=5
|
||||
- WEBSERVER_WORKER_TIMEOUT=30
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default MQTT password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular updates
|
||||
- Monitor access logs
|
||||
|
||||
## Monitoring
|
||||
- **Logs**: `docker-compose logs -f homeassistant`
|
||||
- **Performance**: System monitor integration
|
||||
- **Devices**: Device status dashboard
|
||||
- **Automations**: Automation execution history
|
||||
|
||||
## Troubleshooting
|
||||
- **Device discovery**: Check network connectivity
|
||||
- **MQTT issues**: Verify broker configuration
|
||||
- **Zigbee problems**: Check USB device permissions
|
||||
- **Performance**: Monitor CPU/memory usage
|
||||
- **Database errors**: Check PostgreSQL logs
|
||||
|
||||
## Hardware Requirements
|
||||
- **CPU**: 2 cores minimum, 4 recommended
|
||||
- **RAM**: 2GB minimum, 4GB recommended
|
||||
- **Storage**: 32GB minimum (SSD recommended)
|
||||
- **Network**: Gigabit recommended for multiple devices
|
||||
|
||||
## Add-ons
|
||||
- **HACS**: Home Assistant Community Store
|
||||
- **Configurator**: Browser-based configuration editor
|
||||
- **Terminal**: SSH terminal in HA
|
||||
- **Samba**: File sharing
|
||||
- **VS Code Server**: Code editor
|
||||
@@ -0,0 +1,230 @@
|
||||
# Immich Photo & Video Backup Template
|
||||
|
||||
## Overview
|
||||
Immich is a self-hosted photo and video backup solution directly from your mobile phone.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
name: immich
|
||||
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: ghcr.io/immich-app/immich-server:release
|
||||
volumes:
|
||||
- ./upload:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
REDIS_HOSTNAME: immich-redis
|
||||
DB_HOSTNAME: immich-postgres
|
||||
DB_USERNAME: immich
|
||||
DB_PASSWORD: immich
|
||||
DB_DATABASE_NAME: immich
|
||||
TYPESENSE_API_KEY: replace-with-typesense-api-key
|
||||
ports:
|
||||
- "2283:2283"
|
||||
depends_on:
|
||||
- immich-redis
|
||||
- immich-postgres
|
||||
- immich-typesense
|
||||
restart: always
|
||||
networks:
|
||||
- immich-network
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||
volumes:
|
||||
- model-cache:/cache
|
||||
environment:
|
||||
REDIS_HOSTNAME: immich-redis
|
||||
DB_HOSTNAME: immich-postgres
|
||||
DB_USERNAME: immich
|
||||
DB_PASSWORD: immich
|
||||
DB_DATABASE_NAME: immich
|
||||
TYPESENSE_API_KEY: replace-with-typesense-api-key
|
||||
restart: always
|
||||
networks:
|
||||
- immich-network
|
||||
|
||||
immich-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: immich-redis
|
||||
restart: always
|
||||
networks:
|
||||
- immich-network
|
||||
|
||||
immich-postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: immich-postgres
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: immich
|
||||
POSTGRES_USER: immich
|
||||
POSTGRES_PASSWORD: immich
|
||||
volumes:
|
||||
- immich-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- immich-network
|
||||
|
||||
immich-typesense:
|
||||
image: typesense/typesense:0.24.0
|
||||
container_name: immich-typesense
|
||||
restart: always
|
||||
environment:
|
||||
TYPESENSE_API_KEY: replace-with-typesense-api-key
|
||||
TYPESENSE_DATA_DIR: /data
|
||||
volumes:
|
||||
- immich-typesense-data:/data
|
||||
networks:
|
||||
- immich-network
|
||||
|
||||
volumes:
|
||||
immich-postgres-data:
|
||||
immich-typesense-data:
|
||||
model-cache:
|
||||
|
||||
networks:
|
||||
immich-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `REDIS_HOSTNAME`: Redis service name
|
||||
- `DB_HOSTNAME`: PostgreSQL service name
|
||||
- `DB_USERNAME`: Database username
|
||||
- `DB_PASSWORD`: Database password
|
||||
- `DB_DATABASE_NAME`: Database name
|
||||
- `TYPESENSE_API_KEY`: API key for search functionality
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Typesense API Key**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p upload
|
||||
mkdir -p immich-data
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:2283
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Create admin account
|
||||
- Set up library path
|
||||
- Configure mobile app
|
||||
|
||||
## Mobile App Setup
|
||||
1. **Download App**: Install Immich mobile app (iOS/Android)
|
||||
2. **Server URL**: `http://your-server-ip:2283`
|
||||
3. **Login**: Use admin credentials
|
||||
4. **Backup Settings**: Enable auto-backup for photos/videos
|
||||
|
||||
## Directory Structure
|
||||
```
|
||||
immich/
|
||||
├── upload/
|
||||
│ ├── library/
|
||||
│ │ ├── 2024/
|
||||
│ │ │ ├── 01-January/
|
||||
│ │ │ └── 02-February/
|
||||
│ │ └── 2023/
|
||||
│ ├── encoded-video/
|
||||
│ ├── thumbs/
|
||||
│ └── profile/
|
||||
├── immich-data/
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
## Storage Requirements
|
||||
- **Photos**: ~5MB per photo (varies by quality)
|
||||
- **Videos**: ~100MB per minute (1080p)
|
||||
- **Database**: ~100MB for 10k photos
|
||||
- **Cache**: ~10% of library size
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For large libraries (>100k photos)
|
||||
environment:
|
||||
- IMMICH_TELEMETRY_ON=false
|
||||
- LOG_LEVEL=verbose
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 2G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.immich.rule=Host(`photos.yourdomain.com`)"
|
||||
- "traefik.http.routers.immich.tls=true"
|
||||
- "traefik.http.routers.immich.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.immich.loadbalancer.server.port=3001"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup entire Immich data
|
||||
docker run --rm -v immich-postgres-data:/data -v $(pwd):/backup alpine tar czf /backup/immich-db.tar.gz -C /data .
|
||||
tar czf immich-upload.tar.gz upload/
|
||||
|
||||
# Restore database
|
||||
docker run --rm -v immich-postgres-data:/data -v $(pwd):/backup alpine tar xzf /backup/immich-db.tar.gz -C /data
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f immich-server
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Update images
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up unused images
|
||||
docker image prune -f
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
- **Health Check**: Auto-restart on failure
|
||||
- **Storage**: Monitor disk space usage
|
||||
- **Performance**: Check CPU/memory during uploads
|
||||
- **Backup**: Regular database and file backups
|
||||
|
||||
## Security
|
||||
- Change default passwords
|
||||
- Use HTTPS in production
|
||||
- Regular updates
|
||||
- Network access control
|
||||
- Backup encryption
|
||||
|
||||
## Troubleshooting
|
||||
- **Upload failures**: Check disk space and permissions
|
||||
- **Slow performance**: Verify system resources
|
||||
- **Mobile sync**: Check network connectivity
|
||||
- **Database issues**: Review PostgreSQL logs
|
||||
@@ -0,0 +1,472 @@
|
||||
# Jellyfin Media Server Template
|
||||
|
||||
## Overview
|
||||
Jellyfin is a free software media system that puts you in control of managing and streaming your media.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
container_name: jellyfin
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8096:8096"
|
||||
- "8920:8920" # HTTPS
|
||||
- "7359:7359/udp" # Auto discovery
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- JELLYFIN_PublishedServerUrl=https://jellyfin.yourdomain.com
|
||||
volumes:
|
||||
- jellyfin-config:/config
|
||||
- jellyfin-cache:/cache
|
||||
- /path/to/media:/media
|
||||
- /path/to/movies:/media/movies
|
||||
- /path/to/tvshows:/media/tvshows
|
||||
- /path/to/music:/media/music
|
||||
- /path/to/photos:/media/photos
|
||||
devices:
|
||||
- /dev/dri:/dev/dri # Hardware acceleration
|
||||
networks:
|
||||
- jellyfin-network
|
||||
|
||||
volumes:
|
||||
jellyfin-config:
|
||||
jellyfin-cache:
|
||||
|
||||
networks:
|
||||
jellyfin-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `PUID`: User ID for file permissions
|
||||
- `PGID`: Group ID for file permissions
|
||||
- `TZ`: Timezone (find yours: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
|
||||
- `JELLYFIN_PublishedServerUrl`: Your server URL for external access
|
||||
|
||||
## Setup Guide
|
||||
1. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p jellyfin/{config,cache}
|
||||
mkdir -p media/{movies,tvshows,music,photos}
|
||||
```
|
||||
|
||||
2. **Set Permissions**:
|
||||
```bash
|
||||
sudo chown -R 1000:1000 jellyfin media
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:8096
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Choose language
|
||||
- Set up media libraries
|
||||
- Configure metadata
|
||||
- Set up users
|
||||
|
||||
## Media Library Setup
|
||||
|
||||
### Movies Library
|
||||
```
|
||||
/path/to/movies/
|
||||
├── Movie Name (Year)/
|
||||
│ ├── Movie Name (Year).mp4
|
||||
│ ├── Movie Name (Year).nfo
|
||||
│ ├── poster.jpg
|
||||
│ ├── fanart.jpg
|
||||
│ └── subtitles/
|
||||
│ ├── en.srt
|
||||
│ └── es.srt
|
||||
```
|
||||
|
||||
### TV Shows Library
|
||||
```
|
||||
/path/to/tvshows/
|
||||
├── Show Name/
|
||||
│ ├── Season 01/
|
||||
│ │ ├── S01E01.mkv
|
||||
│ │ ├── S01E02.mkv
|
||||
│ │ └── S01E03.mkv
|
||||
│ ├── Season 02/
|
||||
│ │ ├── S02E01.mkv
|
||||
│ │ └── S02E02.mkv
|
||||
│ ├── poster.jpg
|
||||
│ ├── fanart.jpg
|
||||
│ └── tvshow.nfo
|
||||
```
|
||||
|
||||
### Music Library
|
||||
```
|
||||
/path/to/music/
|
||||
├── Artist Name/
|
||||
│ ├── Album Name/
|
||||
│ │ ├── 01 - Song Name.mp3
|
||||
│ │ ├── 02 - Another Song.mp3
|
||||
│ │ ├── cover.jpg
|
||||
│ │ └── album.nfo
|
||||
│ └── artist.nfo
|
||||
```
|
||||
|
||||
## Hardware Acceleration
|
||||
|
||||
### NVIDIA GPU
|
||||
```yaml
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
runtime: nvidia
|
||||
environment:
|
||||
- JELLYFIN_FFMPEG__hwaccel__nvdec=true
|
||||
- JELLYFIN_FFMPEG__hwaccel__vaapi=false
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
```
|
||||
|
||||
### Intel Quick Sync
|
||||
```yaml
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
environment:
|
||||
- JELLYFIN_FFMPEG__hwaccel__vaapi=true
|
||||
- JELLYFIN_FFMPEG__hwaccel__nvdec=false
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
volumes:
|
||||
- /dev/dri:/dev/dri
|
||||
```
|
||||
|
||||
### AMD VAAPI
|
||||
```yaml
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
environment:
|
||||
- JELLYFIN_FFMPEG__hwaccel__vaapi=true
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.jellyfin.rule=Host(`jellyfin.yourdomain.com`)"
|
||||
- "traefik.http.routers.jellyfin.tls=true"
|
||||
- "traefik.http.routers.jellyfin.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### System.xml (`jellyfin-config/system.xml`)
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<SystemConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<AlbumArtworkMaxWidth>400</AlbumArtworkMaxWidth>
|
||||
<AlbumArtworkMaxResolution>480</AlbumArtworkMaxResolution>
|
||||
<MaxAlbumArtworkDownloadThreads>4</MaxAlbumArtworkDownloadThreads>
|
||||
<ChapterImageResolution>600</ChapterImageResolution>
|
||||
<DownloadImagesInAdvance>false</DownloadImagesInAdvance>
|
||||
<EnableLocalIpAutoDiscovery>true</EnableLocalIpAutoDiscovery>
|
||||
<EnableExternalIpAutoDiscovery>false</EnableExternalIpAutoDiscovery>
|
||||
<EnableUPnP>true</EnableUPnP>
|
||||
<PublicPort>8096</PublicPort>
|
||||
<HttpServerPortNumber>8096</HttpServerPortNumber>
|
||||
<HttpsPortNumber>8920</HttpsPortNumber>
|
||||
<EnableHttps>false</EnableHttps>
|
||||
<RequireHttps>false</RequireHttps>
|
||||
<BaseUrl></BaseUrl>
|
||||
<UDPPortNumber>7359</UDPPortNumber>
|
||||
<EnableIP4>true</EnableIP4>
|
||||
<EnableIP6>false</EnableIP6>
|
||||
<EnableIPv6Firewall>false</EnableIPv6Firewall>
|
||||
<EnableSSDPTracing>true</EnableSSDPTracing>
|
||||
<SSDPTracingFilter></SSDPTracingFilter>
|
||||
<UPnPCreateHttpPortMapping>true</UPnPCreateHttpPortMapping>
|
||||
<UPnPCreateHttpsPortMapping>false</UPnPCreateHttpsPortMapping>
|
||||
<BaseHttpPort>8096</BaseHttpPort>
|
||||
<BaseHttpsPort>8920</BaseHttpsPort>
|
||||
<EnableAutomaticPortMapping>true</EnableAutomaticPortMapping>
|
||||
<AutoRunWebApp>false</AutoRunWebApp>
|
||||
<DisableAutoWebApp>false</DisableAutoWebApp>
|
||||
<LaunchWebBrowserOnStartup>false</LaunchWebBrowserOnStartup>
|
||||
<UICulture>en-US</UICulture>
|
||||
<SaveMetadataHidden>false</SaveMetadataHidden>
|
||||
<MetadataUpdateMode>FullRefresh</MetadataUpdateMode>
|
||||
<MetadataSavers>
|
||||
<NfoSaver>
|
||||
<Enabled>true</Enabled>
|
||||
<Path>/config/metadata/Nfo</Path>
|
||||
<UserDataPath>/config/metadata/Nfo</UserDataPath>
|
||||
</NfoSaver>
|
||||
</MetadataSavers>
|
||||
<MetadataNetworkPath></MetadataNetworkPath>
|
||||
<MetadataPath></MetadataPath>
|
||||
<PreferredMetadataLanguage>en</PreferredMetadataLanguage>
|
||||
<PreferredMetadataLanguageCode>en</PreferredMetadataLanguageCode>
|
||||
<SeasonZeroDisplayName>Specials</SeasonZeroDisplayName>
|
||||
<LibraryMonitorDelay>60</LibraryMonitorDelay>
|
||||
<ImageSavingConvention>Compatible</ImageSavingConvention>
|
||||
</SystemConfiguration>
|
||||
```
|
||||
|
||||
### Encoding.xml (`jellyfin-config/encoding.xml`)
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<EncodingConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<EncodingThreadCount>0</EncodingThreadCount>
|
||||
<MaxMuxingQueueSize>4096</MaxMuxingQueueSize>
|
||||
<ThrottleDelaySeconds>0</ThrottleDelaySeconds>
|
||||
<EnableHardwareEncoding>true</EnableHardwareEncoding>
|
||||
<EnableHardwareDecoding>true</EnableHardwareDecoding>
|
||||
<EnableSubtitleExtraction>true</EnableSubtitleExtraction>
|
||||
<EnableThrottling>false</EnableThrottling>
|
||||
<EnableAudioVbr>true</EnableAudioVbr>
|
||||
<DownMixAudioBoost>2</DownMixAudioBoost>
|
||||
<MaxAudioChannels>6</MaxAudioChannels>
|
||||
<MaxAudioBitrate>128000</MaxAudioBitrate>
|
||||
<MaxAudioTranscodingBitrate>384000</MaxAudioTranscodingBitrate>
|
||||
<H264Preset>fast</H264Preset>
|
||||
<H264Crf>23</H264Crf>
|
||||
<H265Preset>fast</H265Preset>
|
||||
<H265Crf>23</H265Crf>
|
||||
<TonemapPreset>bt2390</TonemapPreset>
|
||||
<TonemapRange>auto</TonemapRange>
|
||||
<TonemapDesaturation>0</TonemapDesaturation>
|
||||
<TonemapPeak>100</TonemapPeak>
|
||||
<TonemapGamma>2.2</TonemapGamma>
|
||||
<VideoBitrate>4000000</VideoBitrate>
|
||||
</EncodingConfiguration>
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Jellyfin configuration
|
||||
docker run --rm -v jellyfin-config:/config -v $(pwd):/backup alpine tar czf /backup/jellyfin-config-backup.tar.gz -C /config .
|
||||
|
||||
# Backup cache (optional)
|
||||
docker run --rm -v jellyfin-cache:/cache -v $(pwd):/backup alpine tar czf /backup/jellyfin-cache-backup.tar.gz -C /cache .
|
||||
|
||||
# Restore configuration
|
||||
docker run --rm -v jellyfin-config:/config -v $(pwd):/backup alpine tar xzf /backup/jellyfin-config-backup.tar.gz -C /config
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart jellyfin
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- JELLYFIN_CACHE_PATH=/cache
|
||||
- JELLYFIN_WEB_PORT=8096
|
||||
- JELLYFIN_HTTP_PORT=8096
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default admin password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Client Apps
|
||||
|
||||
### Official Apps
|
||||
- **Web**: Built-in web interface
|
||||
- **Desktop**: Windows, macOS, Linux
|
||||
- **Mobile**: iOS, Android
|
||||
- **TV**: Android TV, Fire TV, Roku
|
||||
|
||||
### Third-party Apps
|
||||
- **iOS**: Infuse, nPlayer
|
||||
- **Android**: VLC, MX Player
|
||||
- **Desktop**: VLC, MPC-HC
|
||||
|
||||
## API Usage
|
||||
|
||||
### Get Server Info
|
||||
```bash
|
||||
curl -X GET "http://localhost:8096/System/Public" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
### Get Users
|
||||
```bash
|
||||
curl -X GET "http://localhost:8096/Users" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
### Get Libraries
|
||||
```bash
|
||||
curl -X GET "http://localhost:8096/Users/USER_ID/Items" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
### Popular Plugins
|
||||
- **Subtitle Downloader**: Automatic subtitle downloads
|
||||
- **Ombi**: Request system for media
|
||||
- **TMDb Box Sets**: Automatic box set creation
|
||||
- **Trakt**: Trakt.tv integration
|
||||
- **AudioBookshelf**: Audiobook support
|
||||
|
||||
### Plugin Installation
|
||||
```bash
|
||||
# Download plugin
|
||||
curl -L "https://github.com/jellyfin/jellyfin-plugin-repo/releases/download/v10/manifest.json" \
|
||||
-o /tmp/manifest.json
|
||||
|
||||
# Install via web interface or copy to plugins directory
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check if Jellyfin is running
|
||||
curl http://localhost:8096/health
|
||||
|
||||
# Get system info
|
||||
curl http://localhost:8096/System/Info/Public
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f jellyfin
|
||||
|
||||
# Check specific logs
|
||||
docker exec jellyfin cat /config/log/jellyfin.log
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Playback issues**: Check codec support and hardware acceleration
|
||||
- **Metadata problems**: Verify file naming and permissions
|
||||
- **Network access**: Check firewall and port configuration
|
||||
- **Performance issues**: Monitor CPU/memory usage
|
||||
- **Transcoding failures**: Check ffmpeg configuration
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart service
|
||||
docker-compose restart jellyfin
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old logs
|
||||
docker exec jellyfin find /config/log -name "*.log.*" -mtime +30 -delete
|
||||
|
||||
# Rebuild library
|
||||
curl -X POST "http://localhost:8096/Library/Refresh" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Live TV
|
||||
```yaml
|
||||
# Add TV tuner support
|
||||
devices:
|
||||
- /dev/dvb:/dev/dvb
|
||||
- /dev/bus/usb:/dev/bus/usb
|
||||
```
|
||||
|
||||
### Bookmarks
|
||||
```bash
|
||||
# Sync bookmarks between devices
|
||||
curl -X POST "http://localhost:8096/Sync/Users/USER_ID/Data" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
### Parental Controls
|
||||
```bash
|
||||
# Set parental controls via web interface
|
||||
# Or via API
|
||||
curl -X POST "http://localhost:8090/Users/USER_ID/Policy" \
|
||||
-H "Authorization: MediaBrowser Token=YOUR_API_KEY" \
|
||||
-d '{"MaxParentalRating": 18}'
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Home Assistant
|
||||
```yaml
|
||||
# In Home Assistant configuration.yaml
|
||||
media_player:
|
||||
- platform: jellyfin
|
||||
host: http://192.168.1.10:8096
|
||||
api_key: YOUR_API_KEY
|
||||
username: your-username
|
||||
password: your-password
|
||||
```
|
||||
|
||||
### Kodi
|
||||
```bash
|
||||
# Install Jellyfin Kodi addon
|
||||
# Configure server URL and credentials
|
||||
```
|
||||
|
||||
### Plex Migration
|
||||
```bash
|
||||
# Export Plex library
|
||||
# Import to Jellyfin using compatible metadata
|
||||
```
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
### Minimum Requirements
|
||||
- **CPU**: 2 cores (4 recommended for transcoding)
|
||||
- **RAM**: 2GB (4GB recommended)
|
||||
- **Storage**: SSD for system, HDD for media
|
||||
- **Network**: Gigabit recommended for 4K streaming
|
||||
|
||||
### Recommended Requirements
|
||||
- **CPU**: Intel i5/i7 or AMD Ryzen 5/7
|
||||
- **RAM**: 8GB+
|
||||
- **GPU**: NVIDIA/Intel for hardware acceleration
|
||||
- **Storage**: NVMe SSD for cache, large HDD for media
|
||||
- **Network**: 10GbE for multiple 4K streams
|
||||
|
||||
## Best Practices
|
||||
1. **Organize media**: Use proper folder structure
|
||||
2. **Hardware acceleration**: Enable for better performance
|
||||
3. **Regular backups**: Backup configuration and metadata
|
||||
4. **Network optimization**: Use wired connections
|
||||
5. **Monitor resources**: Keep an eye on CPU/memory usage
|
||||
@@ -0,0 +1,468 @@
|
||||
# Mastodon Social Network Template
|
||||
|
||||
## Overview
|
||||
Mastodon is a free, open-source social network server based on ActivityPub where users can follow friends and discover new ones.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
db:
|
||||
restart: always
|
||||
image: postgres:15-alpine
|
||||
shm_size: 256mb
|
||||
networks:
|
||||
- internal_network
|
||||
healthcheck:
|
||||
test: ['CMD', 'pg_isready', '-U', 'postgres']
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_DB=mastodon
|
||||
- POSTGRES_USER=mastodon
|
||||
- POSTGRES_PASSWORD=mastodon
|
||||
container_name: mastodon-db
|
||||
|
||||
redis:
|
||||
restart: always
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
- internal_network
|
||||
healthcheck:
|
||||
test: ['CMD', 'redis-cli', 'ping']
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
container_name: mastodon-redis
|
||||
|
||||
web:
|
||||
image: ghcr.io/mastodon/mastodon:v4.5.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec puma -C config/puma.rb
|
||||
networks:
|
||||
- external_network
|
||||
- internal_network
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', "curl -s --noproxy localhost localhost:3000/health | grep -q 'OK' || exit 1"]
|
||||
ports:
|
||||
- '3000:3000'
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
volumes:
|
||||
- mastodon-data:/mastodon/public/system
|
||||
container_name: mastodon-web
|
||||
|
||||
streaming:
|
||||
image: ghcr.io/mastodon/mastodon-streaming:v4.5.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: node ./streaming/index.js
|
||||
networks:
|
||||
- external_network
|
||||
- internal_network
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', "curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q 'OK' || exit 1"]
|
||||
ports:
|
||||
- '4000:4000'
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
container_name: mastodon-streaming
|
||||
|
||||
sidekiq:
|
||||
image: ghcr.io/mastodon/mastodon:v4.5.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
networks:
|
||||
- external_network
|
||||
- internal_network
|
||||
volumes:
|
||||
- mastodon-data:/mastodon/public/system
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq' || false"]
|
||||
container_name: mastodon-sidekiq
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
redis-data:
|
||||
mastodon-data:
|
||||
|
||||
networks:
|
||||
external_network:
|
||||
internal_network:
|
||||
internal: true
|
||||
```
|
||||
|
||||
## Environment Variables (.env.production)
|
||||
```bash
|
||||
# Federation
|
||||
LOCAL_DOMAIN=mastodon.yourdomain.com
|
||||
WEB_DOMAIN=mastodon.yourdomain.com
|
||||
|
||||
# Redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# Database
|
||||
DB_HOST=db
|
||||
DB_USER=mastodon
|
||||
DB_NAME=mastodon
|
||||
DB_PASS=mastodon
|
||||
DB_PORT=5432
|
||||
|
||||
# Secrets
|
||||
SECRET_KEY_BASE=your-secret-key-base
|
||||
OTP_SECRET=your-otp-secret
|
||||
|
||||
# Web Push
|
||||
VAPID_PRIVATE_KEY=your-vapid-private-key
|
||||
VAPID_PUBLIC_KEY=your-vapid-public-key
|
||||
VAPID_SUBJECT=mailto:your-email@yourdomain.com
|
||||
|
||||
# Email
|
||||
SMTP_SERVER=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_LOGIN=your-email@gmail.com
|
||||
SMTP_PASSWORD=your-app-password
|
||||
SMTP_FROM_ADDRESS=Mastodon <notifications@mastodon.yourdomain.com>
|
||||
|
||||
# File storage
|
||||
S3_ENABLED=true
|
||||
S3_BUCKET=mastodon
|
||||
AWS_ACCESS_KEY_ID=your-access-key
|
||||
AWS_SECRET_ACCESS_KEY=your-secret-key
|
||||
S3_ENDPOINT=https://s3.yourdomain.com
|
||||
S3_PROTOCOL=https
|
||||
S3_HOSTNAME=s3.yourdomain.com
|
||||
S3_ALIAS_HOST=files.mastodon.yourdomain.com
|
||||
|
||||
# Locale
|
||||
DEFAULT_LOCALE=en
|
||||
|
||||
# Other
|
||||
SINGLE_USER_MODE=false
|
||||
RAILS_ENV=production
|
||||
RAILS_SERVE_STATIC_FILES=true
|
||||
```
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secrets**:
|
||||
```bash
|
||||
# Generate secret keys
|
||||
SECRET_KEY_BASE=$(openssl rand -hex 64)
|
||||
OTP_SECRET=$(openssl rand -hex 64)
|
||||
|
||||
# Generate VAPID keys
|
||||
VAPID_PRIVATE_KEY=$(openssl ecparam -name prime256v1 -genkey -noout | openssl ec -outform DER | tail -c +8 | head -c 32 | base64)
|
||||
VAPID_PUBLIC_KEY=$(openssl ec -in <(openssl ecparam -name prime256v1 -genkey -noout) -pubout -outform DER | tail -c +8 | head -c 32 | base64)
|
||||
```
|
||||
|
||||
2. **Create .env.production**:
|
||||
```bash
|
||||
cp .env.production.example .env.production
|
||||
# Edit with your values
|
||||
```
|
||||
|
||||
3. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p public/system
|
||||
```
|
||||
|
||||
4. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
5. **Run Setup Commands**:
|
||||
```bash
|
||||
# Create database
|
||||
docker-compose exec web bundle exec rails db:migrate
|
||||
docker-compose exec web bundle exec rails assets:precompile
|
||||
|
||||
# Create admin user
|
||||
docker-compose exec web bundle exec rails mastodon:admin:create USERNAME=admin EMAIL=admin@yourdomain.com
|
||||
```
|
||||
|
||||
6. **Access**: Open https://mastodon.yourdomain.com
|
||||
|
||||
## Configuration
|
||||
|
||||
### Single User Mode
|
||||
```bash
|
||||
# In .env.production
|
||||
SINGLE_USER_MODE=true
|
||||
LOCAL_DOMAIN=yourdomain.com
|
||||
```
|
||||
|
||||
### Object Storage (S3)
|
||||
```bash
|
||||
# MinIO setup for local S3
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
command: server /data --console-address ":9001"
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
environment:
|
||||
- MINIO_ROOT_USER=minioadmin
|
||||
- MINIO_ROOT_PASSWORD=minioadmin
|
||||
networks:
|
||||
- mastodon-network
|
||||
```
|
||||
|
||||
### Elasticsearch (Optional)
|
||||
```yaml
|
||||
elasticsearch:
|
||||
image: elasticsearch:8.11.1
|
||||
restart: always
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- xpack.security.enabled=false
|
||||
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||||
volumes:
|
||||
- elasticsearch-data:/usr/share/elasticsearch/data
|
||||
networks:
|
||||
- mastodon-network
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mastodon.rule=Host(`mastodon.yourdomain.com`)"
|
||||
- "traefik.http.routers.mastodon.tls=true"
|
||||
- "traefik.http.routers.mastodon.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.mastodon.loadbalancer.server.port=3000"
|
||||
|
||||
- "traefik.http.routers.mastodon-streaming.rule=Host(`mastodon.yourdomain.com`) && PathPrefix(`/api/v1/streaming`)"
|
||||
- "traefik.http.routers.mastodon-streaming.tls=true"
|
||||
- "traefik.http.routers.mastodon-streaming.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.mastodon-streaming.loadbalancer.server.port=4000"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup database
|
||||
docker exec mastodon-db pg_dump -U mastodon mastodon > mastodon-db-backup.sql
|
||||
|
||||
# Backup Redis
|
||||
docker exec mastodon-redis redis-cli BGSAVE
|
||||
docker cp mastodon-redis:/data/dump.rdb ./redis-backup.rdb
|
||||
|
||||
# Backup files
|
||||
docker run --rm -v ./public/system:/data -v $(pwd):/backup alpine tar czf /backup/mastodon-files.tar.gz -C /data .
|
||||
|
||||
# Restore database
|
||||
docker exec -i mastodon-db psql -U mastodon mastodon < mastodon-db-backup.sql
|
||||
|
||||
# Restore Redis
|
||||
docker cp ./redis-backup.rdb mastodon-redis:/data/dump.rdb
|
||||
docker-compose restart redis
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- RAILS_MAX_THREADS=5
|
||||
- RAILS_MIN_THREADS=5
|
||||
- WEB_CONCURRENCY=2
|
||||
- MAX_THREADS=25
|
||||
- PREPARED_STATEMENTS=true
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default passwords
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Administration
|
||||
|
||||
### Admin Commands
|
||||
```bash
|
||||
# Create admin user
|
||||
docker-compose exec web bundle exec rails mastodon:admin:create USERNAME=admin EMAIL=admin@yourdomain.com
|
||||
|
||||
# Remove user
|
||||
docker-compose exec web bundle exec rails mastodon:accounts:remove USERNAME=username
|
||||
|
||||
# Clear media cache
|
||||
docker-compose exec web bundle exec rails mastodon:media:remove
|
||||
|
||||
# Clear cache
|
||||
docker-compose exec web bundle exec rails cache:clear
|
||||
```
|
||||
|
||||
### Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f web
|
||||
docker-compose logs -f sidekiq
|
||||
docker-compose logs -f streaming
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
|
||||
# Update Mastodon
|
||||
docker-compose pull && docker-compose up -d
|
||||
docker-compose exec web bundle exec rails db:migrate
|
||||
docker-compose exec web bundle exec rails assets:precompile
|
||||
```
|
||||
|
||||
## Federation
|
||||
|
||||
### Add to Federation List
|
||||
```bash
|
||||
# Add your instance to joinmastodon.org
|
||||
curl -X POST https://instances.social/api/submit \
|
||||
-d "name=mastodon.yourdomain.com" \
|
||||
-d "url=https://mastodon.yourdomain.com" \
|
||||
-d "email=admin@yourdomain.com"
|
||||
```
|
||||
|
||||
### Block Other Instances
|
||||
```bash
|
||||
# Block instance via admin interface
|
||||
# Or via command line
|
||||
docker-compose exec web bundle exec rails mastodon:domains:block DOMAIN=bad-instance.social
|
||||
```
|
||||
|
||||
## API Usage
|
||||
|
||||
### REST API
|
||||
```bash
|
||||
# Get instance info
|
||||
curl https://mastodon.yourdomain.com/api/v1/instance
|
||||
|
||||
# Get timeline
|
||||
curl -H "Authorization: Bearer ACCESS_TOKEN" \
|
||||
https://mastodon.yourdomain.com/api/v1/timelines/home
|
||||
|
||||
# Post status
|
||||
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"status":"Hello from Mastodon!"}' \
|
||||
https://mastodon.yourdomain.com/api/v1/statuses
|
||||
```
|
||||
|
||||
### WebSocket API
|
||||
```javascript
|
||||
// Connect to streaming API
|
||||
const ws = new WebSocket('wss://mastodon.yourdomain.com/api/v1/streaming?access_token=TOKEN&stream=user');
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('New event:', data);
|
||||
};
|
||||
```
|
||||
|
||||
## Mobile Apps
|
||||
|
||||
### Official Apps
|
||||
- **iOS**: Mastodon for iOS
|
||||
- **Android**: Mastodon for Android
|
||||
|
||||
### Third-party Apps
|
||||
- **iOS**: Ivory, Ice Cubes
|
||||
- **Android**: Tusky, Megalodon
|
||||
- **Web**: Elk, Pinafore
|
||||
|
||||
## Troubleshooting
|
||||
- **Database connection**: Check PostgreSQL configuration
|
||||
- **Redis connection**: Verify Redis settings
|
||||
- **Federation issues**: Check DNS and SSL certificates
|
||||
- **Media uploads**: Verify S3 configuration
|
||||
- **Performance problems**: Monitor resource usage
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Web service health
|
||||
curl https://mastodon.yourdomain.com/health
|
||||
|
||||
# Streaming health
|
||||
curl https://mastodon.yourdomain.com/api/v1/streaming/health
|
||||
|
||||
# Database health
|
||||
docker exec mastodon-db pg_isready -U mastodon
|
||||
```
|
||||
|
||||
### Metrics
|
||||
```bash
|
||||
# Sidekiq stats
|
||||
docker-compose exec web bundle exec rails mastodon:sidekiq:stats
|
||||
|
||||
# Instance stats
|
||||
docker-compose exec web bundle exec rails mastodon:instance:stats
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom CSS
|
||||
```bash
|
||||
# Add custom CSS to public/custom.css
|
||||
# Enable in admin interface
|
||||
```
|
||||
|
||||
### Custom Emojis
|
||||
```bash
|
||||
# Upload custom emojis via admin interface
|
||||
# Or import from file
|
||||
docker-compose exec web bundle exec rails mastodon:emoji:import PATH=/path/to/emojis
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
```bash
|
||||
# Configure rate limits in admin interface
|
||||
# Or via environment variables
|
||||
RATE_LIMITS_USERS=300
|
||||
RATE_LIMITS_SESSIONS=300
|
||||
```
|
||||
|
||||
## Migration from Other Platforms
|
||||
|
||||
### From Twitter
|
||||
```bash
|
||||
# Import Twitter archive
|
||||
docker-compose exec web bundle exec rails mastodon:import:twitter PATH=/path/to/twitter.zip
|
||||
```
|
||||
|
||||
### From Other Mastodon Instance
|
||||
```bash
|
||||
# Export account data from old instance
|
||||
# Import via admin interface
|
||||
```
|
||||
|
||||
## Compliance
|
||||
- **GDPR**: Data export and deletion tools
|
||||
- **Accessibility**: WCAG 2.1 compliance
|
||||
- **Privacy**: Granular privacy controls
|
||||
- **Content moderation**: Advanced moderation tools
|
||||
- **Federation**: ActivityPub protocol compliance
|
||||
@@ -0,0 +1,367 @@
|
||||
# MeiliSearch Search Engine Template
|
||||
|
||||
## Overview
|
||||
MeiliSearch is a fast, typo-tolerant search engine for your applications and websites.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.8
|
||||
container_name: meilisearch
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "7700:7700"
|
||||
environment:
|
||||
- MEILI_MASTER_KEY=your-master-key-here
|
||||
- MEILI_ENV=production
|
||||
- MEILI_DB_ENGINE=rocksdb
|
||||
- MEILI_DB_PATH=/meili_data
|
||||
- MEILI_HTTP_ADDR=0.0.0.0:7700
|
||||
- MEILI_SCHEDULE_SNAPSHOTS_ENABLED=true
|
||||
- MEILI_SCHEDULE_SNAPSHOTS_INTERVAL=3600
|
||||
- MEILI_SNAPSHOT_DIR=/meili_data/snapshots
|
||||
volumes:
|
||||
- meilisearch-data:/meili_data
|
||||
networks:
|
||||
- meilisearch-network
|
||||
|
||||
volumes:
|
||||
meilisearch-data:
|
||||
|
||||
networks:
|
||||
meilisearch-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `MEILI_MASTER_KEY`: Master key for API authentication
|
||||
- `MEILI_ENV`: Environment (development/production)
|
||||
- `MEILI_DB_ENGINE`: Database engine (rocksdb)
|
||||
- `MEILI_DB_PATH`: Database storage path
|
||||
- `MEILI_HTTP_ADDR`: HTTP bind address
|
||||
- `MEILI_SCHEDULE_SNAPSHOTS_ENABLED`: Enable automatic snapshots
|
||||
- `MEILI_SCHEDULE_SNAPSHOTS_INTERVAL`: Snapshot interval in seconds
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Master Key**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Verify Installation**:
|
||||
```bash
|
||||
curl http://localhost:7700/health
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:7700 for basic info
|
||||
|
||||
## API Usage
|
||||
|
||||
### Index Creation
|
||||
```bash
|
||||
# Create an index
|
||||
curl -X POST 'http://localhost:7700/indexes' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '{
|
||||
"uid": "movies",
|
||||
"primaryKey": "id"
|
||||
}'
|
||||
```
|
||||
|
||||
### Document Addition
|
||||
```bash
|
||||
# Add documents
|
||||
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Carol",
|
||||
"poster": "https://image.tmdb.org/t/p/w1280/5KCVsktQcYFzvrxpJ9KsImA3QoI.jpg",
|
||||
"overview": "An aspiring photographer develops an intimate relationship with an older woman.",
|
||||
"release_date": "2015-11-20"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Mad Max: Fury Road",
|
||||
"poster": "https://image.tmdb.org/t/p/w1280/kqjL17yufvn9OVLyXYpvtyrFfak.jpg",
|
||||
"overview": "In a post-apocalyptic wasteland, a woman rebels against a tyrannical ruler.",
|
||||
"release_date": "2015-05-15"
|
||||
}
|
||||
]'
|
||||
```
|
||||
|
||||
### Search
|
||||
```bash
|
||||
# Basic search
|
||||
curl 'http://localhost:7700/indexes/movies/search?q=mad'
|
||||
|
||||
# Search with filters
|
||||
curl 'http://localhost:7700/indexes/movies/search?q=carol&filter=release_date > 2015-01-01'
|
||||
|
||||
# Search with ranking
|
||||
curl 'http://localhost:7700/indexes/movies/search?q=fury&rankingRules=typo,words,proximity,attribute,sort,exactness'
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Index Settings
|
||||
```bash
|
||||
# Configure search settings
|
||||
curl -X PATCH 'http://localhost:7700/indexes/movies/settings' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '{
|
||||
"searchableAttributes": ["title", "overview"],
|
||||
"filterableAttributes": ["release_date"],
|
||||
"sortableAttributes": ["title", "release_date"],
|
||||
"rankingRules": [
|
||||
"typo",
|
||||
"words",
|
||||
"proximity",
|
||||
"attribute",
|
||||
"sort",
|
||||
"exactness"
|
||||
],
|
||||
"stopWords": ["the", "a", "an"],
|
||||
"synonyms": {
|
||||
"wolverine": ["xmen", "logan"],
|
||||
"logan": ["wolverine", "xmen"]
|
||||
},
|
||||
"typoTolerance": {
|
||||
"enabled": true,
|
||||
"minWordSizeForTypos": 5,
|
||||
"disableOnWords": [],
|
||||
"disableOnAttributes": []
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Searchable Attributes
|
||||
```bash
|
||||
# Set searchable attributes
|
||||
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/searchable-attributes' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '["title", "overview", "genre"]'
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.meilisearch.rule=Host(`search.yourdomain.com`)"
|
||||
- "traefik.http.routers.meilisearch.tls=true"
|
||||
- "traefik.http.routers.meilisearch.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.meilisearch.loadbalancer.server.port=7700"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Create snapshot
|
||||
curl -X POST 'http://localhost:7700/snapshots' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
|
||||
# List snapshots
|
||||
curl 'http://localhost:7700/snapshots' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
|
||||
# Restore from snapshot
|
||||
curl -X POST 'http://localhost:7700/snapshots/restore' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '{ "snapshotPath": "/meili_data/snapshots/snapshot-20231201-123456.ms" }'
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- MEILI_MAX_INDEXING_MEMORY=2G
|
||||
- MEILI_MAX_INDEXING_THREADS=4
|
||||
- MEILI_HTTP_PAYLOAD_SIZE_LIMIT=100MB
|
||||
- MEILI_DUMP_BATCH_SIZE=1000
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Client Libraries
|
||||
|
||||
### JavaScript
|
||||
```javascript
|
||||
import { MeiliSearch } from 'meilisearch'
|
||||
|
||||
const client = new MeiliSearch({
|
||||
host: 'http://localhost:7700',
|
||||
apiKey: 'YOUR_MASTER_KEY'
|
||||
})
|
||||
|
||||
// Search
|
||||
const results = await client.index('movies').search('mad max')
|
||||
|
||||
// Add documents
|
||||
await client.index('movies').addDocuments([
|
||||
{ id: 1, title: 'Carol', overview: '...' }
|
||||
])
|
||||
```
|
||||
|
||||
### Python
|
||||
```python
|
||||
import meilisearch
|
||||
|
||||
client = meilisearch.Client("http://localhost:7700", "YOUR_MASTER_KEY")
|
||||
|
||||
# Search
|
||||
results = client.index("movies").search("mad max")
|
||||
|
||||
# Add documents
|
||||
client.index("movies").add_documents([
|
||||
{"id": 1, "title": "Carol", "overview": "..."}
|
||||
])
|
||||
```
|
||||
|
||||
### PHP
|
||||
```php
|
||||
use MeiliSearch\Client;
|
||||
|
||||
$client = new Client('http://localhost:7700', 'YOUR_MASTER_KEY');
|
||||
|
||||
// Search
|
||||
$results = $client->index('movies')->search('mad max');
|
||||
|
||||
// Add documents
|
||||
$client->index('movies')->addDocuments([
|
||||
['id' => 1, 'title' => 'Carol', 'overview' => '...']
|
||||
]);
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### E-commerce Search
|
||||
```bash
|
||||
# Product search with filters
|
||||
curl 'http://localhost:7700/indexes/products/search?q=laptop&filter=price < 1000 AND category = "electronics"'
|
||||
```
|
||||
|
||||
### Document Search
|
||||
```bash
|
||||
# Full-text document search
|
||||
curl 'http://localhost:7700/indexes/documents/search?q=machine learning&limit=20'
|
||||
```
|
||||
|
||||
### User Search
|
||||
```bash
|
||||
# User directory search
|
||||
curl 'http://localhost:7700/indexes/users/search?q=john&filter=department = "engineering"'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default master key
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## Monitoring
|
||||
```bash
|
||||
# Get stats
|
||||
curl 'http://localhost:7700/stats' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
|
||||
# Get index info
|
||||
curl 'http://localhost:7700/indexes/movies/stats' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
|
||||
# Get version
|
||||
curl 'http://localhost:7700/version'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Search not working**: Check index configuration
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **Authentication errors**: Verify master key
|
||||
- **Data loss**: Restore from snapshot
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f meilisearch
|
||||
|
||||
# Restart service
|
||||
docker-compose restart meilisearch
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old snapshots
|
||||
find ./meilisearch-data/snapshots -name "*.ms" -mtime +7 -delete
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Faceted Search
|
||||
```bash
|
||||
# Configure facets
|
||||
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/faceting' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '{
|
||||
"maxValuesPerFacet": 10,
|
||||
"facets": ["genre", "release_date"]
|
||||
}'
|
||||
|
||||
# Search with facets
|
||||
curl 'http://localhost:7700/indexes/movies/search?q=action&facets=genre,release_date'
|
||||
```
|
||||
|
||||
### Geosearch
|
||||
```bash
|
||||
# Add geo coordinates
|
||||
curl -X POST 'http://localhost:7700/indexes/restaurants/documents' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY' \
|
||||
--data-binary '[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Nandos",
|
||||
"_geo": { "lat": 51.5064, "lng": -0.0741 }
|
||||
}
|
||||
]'
|
||||
|
||||
# Geo search
|
||||
curl 'http://localhost:7700/indexes/restaurants/search?q=nandos&filter=_geoRadius(51.5064, -0.0741, 2000)'
|
||||
```
|
||||
|
||||
### Search Analytics
|
||||
```bash
|
||||
# Get search analytics
|
||||
curl 'http://localhost:7700/indexes/movies/search?q=test&analytics=true' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
|
||||
# Get popular searches
|
||||
curl 'http://localhost:7700/indexes/movies/searches/popular' \
|
||||
-H 'Authorization: Bearer YOUR_MASTER_KEY'
|
||||
```
|
||||
@@ -0,0 +1,352 @@
|
||||
# Memos Open Source Notion Alternative Template
|
||||
|
||||
## Overview
|
||||
Memos is a lightweight, self-hosted memo hub for your personal notes and thoughts.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
memos:
|
||||
image: usememos/memos:latest
|
||||
container_name: memos
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5230:5230"
|
||||
environment:
|
||||
- MEMOS_MODE=prod
|
||||
- MEMOS_DRIVER=postgres
|
||||
- MEMOS_POSTGRES_DSN=postgres://memos:memos@postgres:5432/memos
|
||||
- MEMOS_PORT=5230
|
||||
- MEMOS_ADDR=0.0.0.0
|
||||
volumes:
|
||||
- memos-data:/var/opt/memos
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- memos-network
|
||||
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: memos-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=memos
|
||||
- POSTGRES_USER=memos
|
||||
- POSTGRES_PASSWORD=memos
|
||||
volumes:
|
||||
- memos-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- memos-network
|
||||
|
||||
volumes:
|
||||
memos-data:
|
||||
memos-db:
|
||||
|
||||
networks:
|
||||
memos-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `MEMOS_MODE`: Running mode (prod/dev)
|
||||
- `MEMOS_DRIVER`: Database driver (postgres/sqlite)
|
||||
- `MEMOS_POSTGRES_DSN`: PostgreSQL connection string
|
||||
- `MEMOS_PORT`: Application port
|
||||
- `MEMOS_ADDR`: Bind address
|
||||
|
||||
## Setup Guide
|
||||
1. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
2. **Access**: Open http://localhost:5230
|
||||
|
||||
3. **Initial Setup**:
|
||||
- Create admin account
|
||||
- Set username and password
|
||||
- Configure workspace settings
|
||||
|
||||
4. **Create First Memo**:
|
||||
- Click "+" button
|
||||
- Write your first note
|
||||
- Add tags for organization
|
||||
|
||||
## SQLite Alternative
|
||||
```yaml
|
||||
# For smaller deployments, use SQLite instead of PostgreSQL
|
||||
services:
|
||||
memos:
|
||||
image: usememos/memos:latest
|
||||
container_name: memos
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5230:5230"
|
||||
environment:
|
||||
- MEMOS_MODE=prod
|
||||
- MEMOS_DRIVER=sqlite
|
||||
volumes:
|
||||
- memos-data:/var/opt/memos
|
||||
- ./memos.db:/var/opt/memos/memos.db
|
||||
networks:
|
||||
- memos-network
|
||||
|
||||
volumes:
|
||||
memos-data:
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Environment Variables
|
||||
```yaml
|
||||
environment:
|
||||
- MEMOS_MODE=prod
|
||||
- MEMOS_DRIVER=postgres
|
||||
- MEMOS_POSTGRES_DSN=postgres://user:pass@host:5432/db
|
||||
- MEMOS_PORT=5230
|
||||
- MEMOS_ADDR=0.0.0.0
|
||||
- MEMOS_SECRET_KEY=your-secret-key
|
||||
- MEMOS_DATA=/var/opt/memos
|
||||
- MEMOS_DSN=file:/var/opt/memos/memos.db
|
||||
```
|
||||
|
||||
### Advanced Configuration
|
||||
```yaml
|
||||
# Custom configuration file
|
||||
volumes:
|
||||
- ./config.yaml:/var/opt/memos/config.yaml
|
||||
|
||||
# Example config.yaml
|
||||
# server:
|
||||
# port: 5230
|
||||
# mode: prod
|
||||
# addr: 0.0.0.0
|
||||
# database:
|
||||
# driver: postgres
|
||||
# dsn: postgres://memos:memos@postgres:5432/memos
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### Note Organization
|
||||
- **Tags**: Categorize notes with hashtags
|
||||
- **Archives**: Archive old notes
|
||||
- **Favorites**: Mark important notes
|
||||
- **Search**: Full-text search across all notes
|
||||
|
||||
### Markdown Support
|
||||
```markdown
|
||||
# Headers
|
||||
## Subheaders
|
||||
|
||||
**Bold text**
|
||||
*Italic text*
|
||||
|
||||
- Lists
|
||||
- With items
|
||||
|
||||
`Code snippets`
|
||||
|
||||
[Links](https://example.com)
|
||||
|
||||
> Blockquotes
|
||||
```
|
||||
|
||||
### Daily Memo
|
||||
- **Daily notes**: Create daily journal entries
|
||||
- **Templates**: Use templates for consistent formatting
|
||||
- **Reminders**: Set reminders for important notes
|
||||
|
||||
### Sharing
|
||||
- **Public links**: Share individual notes
|
||||
- **RSS feeds**: Export notes as RSS
|
||||
- **Export**: Export notes as markdown files
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.memos.rule=Host(`memos.yourdomain.com`)"
|
||||
- "traefik.http.routers.memos.tls=true"
|
||||
- "traefik.http.routers.memos.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.memos.loadbalancer.server.port=5230"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Memos data
|
||||
docker run --rm -v memos-data:/var/opt/memos -v $(pwd):/backup alpine tar czf /backup/memos-backup.tar.gz -C /var/opt/memos .
|
||||
|
||||
# Backup PostgreSQL database
|
||||
docker exec memos-postgres pg_dump -U memos memos > memos-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i memos-postgres psql -U memos memos < memos-db-backup.sql
|
||||
|
||||
# Restore Memos data
|
||||
docker run --rm -v memos-data:/var/opt/memos -v $(pwd):/backup alpine tar xzf /backup/memos-backup.tar.gz -C /var/opt/memos
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- MEMOS_MODE=prod
|
||||
- MEMOS_WORKER=4
|
||||
- MEMOS_MAX_UPLOAD_SIZE=32MB
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.2'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default credentials
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## API Usage
|
||||
```bash
|
||||
# Get all memos
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:5230/api/v1/memos
|
||||
|
||||
# Create memo
|
||||
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"content":"Hello World"}' \
|
||||
http://localhost:5230/api/v1/memos
|
||||
|
||||
# Search memos
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
"http://localhost:5230/api/v1/memos?filter=tag:important"
|
||||
```
|
||||
|
||||
## Mobile Apps
|
||||
- **iOS**: Available on App Store
|
||||
- **Android**: Available on Google Play
|
||||
- **Web**: Progressive Web App (PWA)
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Daily Journal Template
|
||||
```markdown
|
||||
# Daily Journal - {{date}}
|
||||
|
||||
## Mood: 😊
|
||||
|
||||
## Today's Highlights
|
||||
-
|
||||
|
||||
## Gratitude
|
||||
-
|
||||
|
||||
## Tomorrow's Goals
|
||||
-
|
||||
|
||||
## Notes
|
||||
-
|
||||
```
|
||||
|
||||
### Meeting Notes Template
|
||||
```markdown
|
||||
# Meeting - {{title}}
|
||||
|
||||
**Date**: {{date}}
|
||||
**Attendees**:
|
||||
**Duration**:
|
||||
|
||||
## Agenda
|
||||
-
|
||||
|
||||
## Notes
|
||||
-
|
||||
|
||||
## Action Items
|
||||
- [ ]
|
||||
|
||||
## Follow-up
|
||||
-
|
||||
```
|
||||
|
||||
## Migration from Other Tools
|
||||
|
||||
### From Notion
|
||||
1. Export pages as markdown
|
||||
2. Import via API or manual copy
|
||||
3. Reorganize with tags
|
||||
|
||||
### From Obsidian
|
||||
1. Copy markdown files
|
||||
2. Maintain folder structure with tags
|
||||
3. Adjust image links
|
||||
|
||||
### From Google Keep
|
||||
1. Export notes (if available)
|
||||
2. Manual copy for most notes
|
||||
3. Use tags for organization
|
||||
|
||||
## Troubleshooting
|
||||
- **Database connection**: Check PostgreSQL configuration
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **Access problems**: Verify port and firewall settings
|
||||
- **Data loss**: Restore from backup
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f memos
|
||||
|
||||
# Restart service
|
||||
docker-compose restart memos
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec memos rm -rf /var/opt/memos/tmp/*
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### CSS Customization
|
||||
```css
|
||||
/* Add custom CSS in settings */
|
||||
.memo-content {
|
||||
font-family: 'Inter', sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Themes
|
||||
- **Dark mode**: Built-in dark theme
|
||||
- **Custom colors**: Configure in settings
|
||||
- **Font sizes**: Adjustable in settings
|
||||
|
||||
## Best Practices
|
||||
1. **Use tags consistently**: Create a tag system
|
||||
2. **Daily reviews**: Review and organize notes daily
|
||||
3. **Archive old notes**: Keep workspace clean
|
||||
4. **Use templates**: Standardize common note types
|
||||
5. **Regular backups**: Protect your data
|
||||
@@ -0,0 +1,262 @@
|
||||
# n8n Workflow Automation Template
|
||||
|
||||
## Overview
|
||||
n8n is a fair-code licensed tool that helps you automate tasks, workflows, and processes without the need for writing code.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
volumes:
|
||||
db_storage:
|
||||
n8n_storage:
|
||||
redis_storage:
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
container_name: n8n-postgres
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_DB=n8n
|
||||
- POSTGRES_USER=n8n
|
||||
- POSTGRES_PASSWORD=n8n
|
||||
- POSTGRES_NON_ROOT_USER=n8n
|
||||
- POSTGRES_NON_ROOT_PASSWORD=n8n
|
||||
volumes:
|
||||
- db_storage:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- n8n-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: n8n-redis
|
||||
restart: always
|
||||
volumes:
|
||||
- redis_storage:/data
|
||||
healthcheck:
|
||||
test: ['CMD', 'redis-cli', 'ping']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- n8n-network
|
||||
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
container_name: n8n
|
||||
restart: always
|
||||
ports:
|
||||
- "5678:5678"
|
||||
environment:
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_HOST=postgres
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_DATABASE=n8n
|
||||
- DB_POSTGRESDB_USER=n8n
|
||||
- DB_POSTGRESDB_PASSWORD=n8n
|
||||
- EXECUTIONS_MODE=queue
|
||||
- QUEUE_BULL_REDIS_HOST=redis
|
||||
- QUEUE_HEALTH_CHECK_ACTIVE=true
|
||||
- N8N_ENCRYPTION_KEY=your-encryption-key-here
|
||||
- N8N_BASIC_AUTH_ACTIVE=true
|
||||
- N8N_BASIC_AUTH_USER=admin
|
||||
- N8N_BASIC_AUTH_PASSWORD=your-secure-password
|
||||
- WEBHOOK_URL=http://your-domain.com:5678/
|
||||
volumes:
|
||||
- n8n_storage:/home/node/.n8n
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- n8n-network
|
||||
|
||||
n8n-worker:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
container_name: n8n-worker
|
||||
restart: always
|
||||
environment:
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_HOST=postgres
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_DATABASE=n8n
|
||||
- DB_POSTGRESDB_USER=n8n
|
||||
- DB_POSTGRESDB_PASSWORD=n8n
|
||||
- EXECUTIONS_MODE=queue
|
||||
- QUEUE_BULL_REDIS_HOST=redis
|
||||
- QUEUE_HEALTH_CHECK_ACTIVE=true
|
||||
- N8N_ENCRYPTION_KEY=your-encryption-key-here
|
||||
volumes:
|
||||
- n8n_storage:/home/node/.n8n
|
||||
command: worker
|
||||
depends_on:
|
||||
- n8n
|
||||
redis:
|
||||
condition: service_healthy
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- n8n-network
|
||||
|
||||
networks:
|
||||
n8n-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `DB_TYPE=postgresdb`: Use PostgreSQL database
|
||||
- `DB_POSTGRESDB_*`: PostgreSQL connection settings
|
||||
- `EXECUTIONS_MODE=queue`: Use queue mode for better performance
|
||||
- `QUEUE_BULL_REDIS_HOST=redis`: Redis host for queue
|
||||
- `N8N_ENCRYPTION_KEY`: Encryption key for sensitive data
|
||||
- `N8N_BASIC_AUTH_*`: Basic authentication settings
|
||||
- `WEBHOOK_URL`: URL for webhook workflows
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Encryption Key**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Generate Secure Password**:
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:5678
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Login with basic auth credentials
|
||||
- Create first workflow
|
||||
- Configure integrations
|
||||
|
||||
## Workflow Examples
|
||||
```yaml
|
||||
# Example: Email Notification Workflow
|
||||
# Trigger: Webhook
|
||||
# Action: Send Email
|
||||
# Schedule: Every hour
|
||||
|
||||
# Example: Data Sync
|
||||
# Trigger: Schedule (daily)
|
||||
# Action: Google Sheets → Database
|
||||
# Error Handling: Retry on failure
|
||||
|
||||
# Example: Social Media Post
|
||||
# Trigger: Manual
|
||||
# Action: Create content → Post to Twitter
|
||||
# Conditions: Business hours only
|
||||
```
|
||||
|
||||
## Popular Integrations
|
||||
- **Communication**: Slack, Discord, Telegram
|
||||
- **Storage**: Google Drive, Dropbox, OneDrive
|
||||
- **Databases**: PostgreSQL, MySQL, MongoDB
|
||||
- **CRM**: Salesforce, HubSpot
|
||||
- **Social**: Twitter, LinkedIn, Facebook
|
||||
- **Productivity**: Notion, Trello, Asana
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.n8n.rule=Host(`n8n.yourdomain.com`)"
|
||||
- "traefik.http.routers.n8n.tls=true"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
```
|
||||
|
||||
## Custom Nodes
|
||||
```yaml
|
||||
# Mount custom nodes directory
|
||||
volumes:
|
||||
- ./n8n-custom:/home/node/.n8n/custom
|
||||
|
||||
# Install custom nodes
|
||||
docker exec n8n npm install n8n-nodes-your-custom-node
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup n8n data
|
||||
docker run --rm -v n8n-data:/data -v $(pwd):/backup alpine tar czf /backup/n8n-data.tar.gz -C /data .
|
||||
|
||||
# Backup database
|
||||
docker exec n8n-postgres pg_dump -U n8n n8n > n8n-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i n8n-postgres psql -U n8n n8n < n8n-db-backup.sql
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For high-volume workflows
|
||||
environment:
|
||||
- N8N_EXECUTIONS_DATA_PRUNE=true
|
||||
- N8N_EXECUTIONS_DATA_MAX_AGE=168 # 7 days
|
||||
- N8N_QUEUE_BULL_REDIS_HOST=redis
|
||||
- N8N_QUEUE_BULL_REDIS_PORT=6379
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '1.5'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Use strong passwords
|
||||
- Enable HTTPS
|
||||
- Regular updates
|
||||
- Network access control
|
||||
- Audit workflow executions
|
||||
|
||||
## Monitoring
|
||||
```bash
|
||||
# Check execution logs
|
||||
docker-compose logs -f n8n
|
||||
|
||||
# Monitor Redis queue
|
||||
docker exec n8n-redis redis-cli info
|
||||
|
||||
# Database status
|
||||
docker exec n8n-postgres psql -U n8n -c "SELECT count(*) FROM workflow_entity;"
|
||||
```
|
||||
|
||||
## Scaling
|
||||
```yaml
|
||||
# Worker nodes for execution
|
||||
n8n-worker:
|
||||
image: docker.n8n.io/n8nio/n8n:latest
|
||||
environment:
|
||||
- N8N_QUEUE_BULL_REDIS_HOST=redis
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- n8n-network
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Workflow failures**: Check execution logs
|
||||
- **Memory issues**: Increase memory limits
|
||||
- **Database errors**: Verify PostgreSQL connection
|
||||
- **SMTP problems**: Test email configuration
|
||||
@@ -0,0 +1,505 @@
|
||||
# Nextcloud Cloud Storage Template
|
||||
|
||||
## Overview
|
||||
Nextcloud is a suite of client-server software for creating and using file hosting services.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
nextcloud-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: nextcloud-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=nextcloud
|
||||
- POSTGRES_USER=nextcloud
|
||||
- POSTGRES_PASSWORD=nextcloud
|
||||
volumes:
|
||||
- nextcloud-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- nextcloud-network
|
||||
|
||||
nextcloud-redis:
|
||||
image: redis:7-alpine
|
||||
container_name: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- nextcloud-redis:/data
|
||||
networks:
|
||||
- nextcloud-network
|
||||
|
||||
nextcloud-app:
|
||||
image: nextcloud:latest
|
||||
container_name: nextcloud
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:80"
|
||||
environment:
|
||||
- POSTGRES_HOST=nextcloud-db
|
||||
- POSTGRES_DB=nextcloud
|
||||
- POSTGRES_USER=nextcloud
|
||||
- POSTGRES_PASSWORD=nextcloud
|
||||
- REDIS_HOST=nextcloud-redis
|
||||
- NEXTCLOUD_ADMIN_USER=admin
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=your-secure-password
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=localhost
|
||||
- OVERWRITEPROTOCOL=http
|
||||
- OVERWRITEHOST=localhost:8080
|
||||
volumes:
|
||||
- nextcloud-data:/var/www/html
|
||||
- nextcloud-config:/var/www/html/config
|
||||
- nextcloud-apps:/var/www/html/apps
|
||||
- /path/to/nextcloud-data:/var/www/html/data
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
- nextcloud-redis
|
||||
networks:
|
||||
- nextcloud-network
|
||||
|
||||
nextcloud-cron:
|
||||
image: nextcloud:latest
|
||||
container_name: nextcloud-cron
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_HOST=nextcloud-db
|
||||
- POSTGRES_DB=nextcloud
|
||||
- POSTGRES_USER=nextcloud
|
||||
- POSTGRES_PASSWORD=nextcloud
|
||||
- REDIS_HOST=nextcloud-redis
|
||||
volumes:
|
||||
- nextcloud-data:/var/www/html
|
||||
- nextcloud-config:/var/www/html/config
|
||||
- nextcloud-apps:/var/www/html/apps
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
- nextcloud-redis
|
||||
entrypoint: /cron.sh
|
||||
networks:
|
||||
- nextcloud-network
|
||||
|
||||
volumes:
|
||||
nextcloud-data:
|
||||
nextcloud-config:
|
||||
nextcloud-apps:
|
||||
nextcloud-db:
|
||||
nextcloud-redis:
|
||||
|
||||
networks:
|
||||
nextcloud-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `POSTGRES_*`: Database configuration
|
||||
- `REDIS_HOST`: Redis server host
|
||||
- `NEXTCLOUD_ADMIN_*`: Admin user credentials
|
||||
- `NEXTCLOUD_TRUSTED_DOMAINS`: Trusted domains
|
||||
- `OVERWRITEPROTOCOL`: Protocol override
|
||||
- `OVERWRITEHOST`: Host override
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secure Password**:
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p nextcloud-data
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:8080
|
||||
|
||||
5. **Initial Setup**:
|
||||
- Admin account should be auto-created
|
||||
- Configure apps and settings
|
||||
- Set up user accounts
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### config.php (`nextcloud-config/config.php`)
|
||||
```php
|
||||
<?php
|
||||
$CONFIG = array (
|
||||
'instanceid' => 'your-instance-id',
|
||||
'passwordsalt' => 'your-password-salt',
|
||||
'secret' => 'your-secret',
|
||||
'trusted_domains' =>
|
||||
array (
|
||||
0 => 'localhost',
|
||||
1 => 'nextcloud.yourdomain.com',
|
||||
),
|
||||
'datadirectory' => '/var/www/html/data',
|
||||
'dbtype' => 'pgsql',
|
||||
'version' => '27.0.0',
|
||||
'dbname' => 'nextcloud',
|
||||
'dbhost' => 'nextcloud-db',
|
||||
'dbport' => '',
|
||||
'dbtableprefix' => 'oc_',
|
||||
'dbuser' => 'nextcloud',
|
||||
'dbpassword' => 'nextcloud',
|
||||
'installed' => true,
|
||||
'filelocking.enabled' => true,
|
||||
'memcache.locking' => '\\OC\\Memcache\\Redis',
|
||||
'memcache.local' => '\\OC\\Memcache\\Redis',
|
||||
'redis' =>
|
||||
array (
|
||||
'host' => 'nextcloud-redis',
|
||||
'port' => 6379,
|
||||
),
|
||||
'mail_smtpmode' => 'smtp',
|
||||
'mail_sendmailmode' => 'smtp',
|
||||
'mail_from_address' => 'nextcloud',
|
||||
'mail_domain' => 'yourdomain.com',
|
||||
'mail_smtpserver' => 'smtp.gmail.com',
|
||||
'mail_smtpport' => '587',
|
||||
'mail_smtpsecure' => 'tls',
|
||||
'mail_smtpauth' => 1,
|
||||
'mail_smtpauthtype' => 'LOGIN',
|
||||
'mail_smtpname' => 'your-email@gmail.com',
|
||||
'mail_smtppassword' => 'your-app-password',
|
||||
'overwrite.cli.url' => 'http://localhost:8080',
|
||||
'default_phone_region' => 'US',
|
||||
'enabledPreviewProviders' =>
|
||||
array (
|
||||
0 => 'OC\\Preview\\Image',
|
||||
1 => 'OC\\Preview\\Movie',
|
||||
2 => 'OC\\Preview\\TXT',
|
||||
3 => 'OC\\Preview\\MarkDown',
|
||||
4 => 'OC\\Preview\\PDF',
|
||||
5 => 'OC\\Preview\\Office',
|
||||
6 => 'OC\\Preview\\SVG',
|
||||
7 => 'OC\\Preview\\EPUB',
|
||||
8 => 'OC\\Preview\\Font',
|
||||
9 => 'OC\\Preview\\MP3',
|
||||
10 => 'OC\\Preview\\HEIC',
|
||||
),
|
||||
'enable_previews' => true,
|
||||
'preview_max_x' => 2048,
|
||||
'preview_max_y' => 2048,
|
||||
'preview_max_scale_factor' => 1,
|
||||
'enabledPreviewProviders' =>
|
||||
array (
|
||||
0 => 'OC\\Preview\\Image',
|
||||
1 => 'OC\\Preview\\Movie',
|
||||
2 => 'OC\\Preview\\TXT',
|
||||
3 => 'OC\\Preview\\MarkDown',
|
||||
4 => 'OC\\Preview\\PDF',
|
||||
5 => 'OC\\Preview\\Office',
|
||||
6 => 'OC\\Preview\\SVG',
|
||||
7 => 'OC\\Preview\\EPUB',
|
||||
8 => 'OC\\Preview\\Font',
|
||||
9 => 'OC\\Preview\\MP3',
|
||||
10 => 'OC\\Preview\\HEIC',
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
## Apps Installation
|
||||
|
||||
### Popular Apps
|
||||
```bash
|
||||
# Install apps via web interface or CLI
|
||||
docker exec nextcloud-app occ app:install files_external
|
||||
docker exec nextcloud-app occ app:install calendar
|
||||
docker exec nextcloud-app occ app:install contacts
|
||||
docker exec nextcloud-app occ app:install mail
|
||||
docker exec nextcloud-app occ app:install deck
|
||||
docker exec nextcloud-app occ app:install notes
|
||||
docker exec nextcloud-app occ app:install tasks
|
||||
docker exec nextcloud-app occ app:install talk
|
||||
```
|
||||
|
||||
### External Storage
|
||||
```bash
|
||||
# Add external storage
|
||||
docker exec nextcloud-app occ files_external:create admin local /path/to/external/storage
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.yourdomain.com`)"
|
||||
- "traefik.http.routers.nextcloud.tls=true"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Nextcloud data
|
||||
docker run --rm -v nextcloud-data:/var/www/html -v $(pwd):/backup alpine tar czf /backup/nextcloud-data-backup.tar.gz -C /var/www/html .
|
||||
|
||||
# Backup database
|
||||
docker exec nextcloud-db pg_dump -U nextcloud nextcloud > nextcloud-db-backup.sql
|
||||
|
||||
# Backup Redis
|
||||
docker exec nextcloud-redis redis-cli BGSAVE
|
||||
docker cp nextcloud-redis:/data/dump.rdb ./redis-backup.rdb
|
||||
|
||||
# Restore database
|
||||
docker exec -i nextcloud-db psql -U nextcloud nextcloud < nextcloud-db-backup.sql
|
||||
|
||||
# Restore Nextcloud data
|
||||
docker run --rm -v nextcloud-data:/var/www/html -v $(pwd):/backup alpine tar xzf /backup/nextcloud-data-backup.tar.gz -C /var/www/html
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart nextcloud-app
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- PHP_MEMORY_LIMIT=512M
|
||||
- PHP_UPLOAD_LIMIT=512M
|
||||
- PHP_MAX_EXECUTION_TIME=300
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default admin password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## User Management
|
||||
|
||||
### Create User
|
||||
```bash
|
||||
# Create user via CLI
|
||||
docker exec nextcloud-app occ user:add --display-name="John Doe" --group="users" john
|
||||
```
|
||||
|
||||
### Groups
|
||||
```bash
|
||||
# Create group
|
||||
docker exec nextcloud-app occ group:add team
|
||||
|
||||
# Add user to group
|
||||
docker exec nextcloud-app occ group:adduser john team
|
||||
```
|
||||
|
||||
### Quotas
|
||||
```bash
|
||||
# Set user quota
|
||||
docker exec nextcloud-app occ user:setting john quota 5GB
|
||||
```
|
||||
|
||||
## File Sharing
|
||||
|
||||
### Share Files
|
||||
```bash
|
||||
# Create share link
|
||||
docker exec nextcloud-app occ share:create /path/to/file --type=link --permissions=1
|
||||
```
|
||||
|
||||
### External Storage
|
||||
```bash
|
||||
# Add SMB share
|
||||
docker exec nextcloud-app occ files_external:create admin smb://server/share --mount=external
|
||||
```
|
||||
|
||||
## Calendar & Contacts
|
||||
|
||||
### Calendar Setup
|
||||
```bash
|
||||
# Install calendar app
|
||||
docker exec nextcloud-app occ app:install calendar
|
||||
|
||||
# Create calendar
|
||||
docker exec nextcloud-app occ calendar:create --name="Work" --color="#ff0000"
|
||||
```
|
||||
|
||||
### Contacts Setup
|
||||
```bash
|
||||
# Install contacts app
|
||||
docker exec nextcloud-app occ app:install contacts
|
||||
|
||||
# Import contacts
|
||||
docker exec nextcloud-app occ contacts:import /path/to/contacts.vcf
|
||||
```
|
||||
|
||||
## Talk (Chat & Video)
|
||||
|
||||
### Enable Talk
|
||||
```bash
|
||||
# Install talk app
|
||||
docker exec nextcloud-app occ app:install talk
|
||||
|
||||
# Enable signaling server
|
||||
docker exec nextcloud-app occ talk:signaling:install
|
||||
```
|
||||
|
||||
### Talk Configuration
|
||||
```php
|
||||
// In config.php
|
||||
'allow_local_remote_servers' => true,
|
||||
'signaling' => [
|
||||
'servers' => [
|
||||
[
|
||||
'server' => 'https://nextcloud.yourdomain.com',
|
||||
'verify' => true
|
||||
]
|
||||
]
|
||||
],
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check if Nextcloud is running
|
||||
curl http://localhost:8080/status.php
|
||||
|
||||
# Get system info
|
||||
docker exec nextcloud-app occ status
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f nextcloud-app
|
||||
|
||||
# Check Nextcloud logs
|
||||
docker exec nextcloud-app occ log:tail
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Database connection**: Check PostgreSQL configuration
|
||||
- **File permissions**: Verify volume permissions
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **App installation**: Check app compatibility
|
||||
- **Sharing problems**: Verify external storage configuration
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Update Nextcloud
|
||||
docker-compose pull && docker-compose up -d
|
||||
docker exec nextcloud-app occ upgrade
|
||||
|
||||
# Run maintenance tasks
|
||||
docker exec nextcloud-app occ maintenance:repair
|
||||
docker exec nextcloud-app occ files:scan --all
|
||||
|
||||
# Clean up old files
|
||||
docker exec nextcloud-app occ trashbin:cleanup
|
||||
docker exec nextcloud-app occ versions:cleanup
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Collabora Online
|
||||
```yaml
|
||||
collabora:
|
||||
image: collabora/code:latest
|
||||
container_name: collabora
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- aliasgroup1=https://nextcloud.yourdomain.com
|
||||
- dictionaries=en_US
|
||||
- extra_params=--o:ssl.enable=false --o:ssl.termination=true
|
||||
ports:
|
||||
- "9980:9980"
|
||||
networks:
|
||||
- nextcloud-network
|
||||
```
|
||||
|
||||
### OnlyOffice
|
||||
```yaml
|
||||
onlyoffice:
|
||||
image: onlyoffice/documentserver:latest
|
||||
container_name: onlyoffice
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- JWT_ENABLED=true
|
||||
- JWT_SECRET=your-jwt-secret
|
||||
ports:
|
||||
- "8081:80"
|
||||
networks:
|
||||
- nextcloud-network
|
||||
```
|
||||
|
||||
### Full Text Search
|
||||
```yaml
|
||||
elasticsearch:
|
||||
image: elasticsearch:8.11.1
|
||||
container_name: nextcloud-elasticsearch
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- xpack.security.enabled=false
|
||||
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||||
volumes:
|
||||
- elasticsearch-data:/usr/share/elasticsearch/data
|
||||
networks:
|
||||
- nextcloud-network
|
||||
```
|
||||
|
||||
## Client Apps
|
||||
|
||||
### Desktop Apps
|
||||
- **Windows**: Nextcloud Desktop Client
|
||||
- **macOS**: Nextcloud Desktop Client
|
||||
- **Linux**: Nextcloud Desktop Client
|
||||
|
||||
### Mobile Apps
|
||||
- **iOS**: Nextcloud iOS App
|
||||
- **Android**: Nextcloud Android App
|
||||
|
||||
### WebDAV
|
||||
```bash
|
||||
# Mount via WebDAV
|
||||
davfs2 https://nextcloud.yourdomain.com/remote.php/dav/files/username/ /mnt/nextcloud
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Home Assistant
|
||||
```yaml
|
||||
# In Home Assistant configuration.yaml
|
||||
nextcloud:
|
||||
url: https://nextcloud.yourdomain.com
|
||||
username: your-username
|
||||
password: your-password
|
||||
```
|
||||
|
||||
### LDAP Integration
|
||||
```php
|
||||
// In config.php
|
||||
'ldapProviderFactory' => 'OCA\\User_LDAP\\LDAPProviderFactory',
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
1. **Regular backups**: Backup data and database regularly
|
||||
2. **Monitor resources**: Keep an eye on disk space and memory
|
||||
3. **Update regularly**: Keep Nextcloud and apps updated
|
||||
4. **Use HTTPS**: Always use HTTPS in production
|
||||
5. **Configure quotas**: Set appropriate user quotas
|
||||
6. **Enable caching**: Use Redis for better performance
|
||||
7. **Monitor logs**: Keep an eye on error logs
|
||||
8. **Test backups**: Regularly test backup restoration
|
||||
@@ -0,0 +1,378 @@
|
||||
# Pi-hole DNS Ad Blocker Template
|
||||
|
||||
## Overview
|
||||
Pi-hole is a DNS sinkhole that protects your devices from unwanted content without installing any client-side software.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pihole:
|
||||
image: pihole/pihole:latest
|
||||
container_name: pihole
|
||||
restart: unless-stopped
|
||||
hostname: pihole
|
||||
ports:
|
||||
- "53:53/tcp"
|
||||
- "53:53/udp"
|
||||
- "80:80/tcp"
|
||||
- "443:443/tcp"
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- FTLCONF_webserver_api_password=your-secure-password
|
||||
- FTLCONF_dns_listeningMode=ALL
|
||||
volumes:
|
||||
- pihole-config:/etc/pihole
|
||||
- pihole-dnsmasq:/etc/dnsmasq.d
|
||||
- pihole-logs:/var/log
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_TIME
|
||||
- SYS_NICE
|
||||
networks:
|
||||
- pihole-network
|
||||
|
||||
volumes:
|
||||
pihole-config:
|
||||
pihole-dnsmasq:
|
||||
pihole-logs:
|
||||
|
||||
networks:
|
||||
pihole-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `TZ`: Timezone (find yours: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
|
||||
- `FTLCONF_webserver_api_password`: Admin password for web interface
|
||||
- `FTLCONF_dns_listeningMode`: DNS listening mode ('ALL' for bridge networks)
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secure Password**:
|
||||
```bash
|
||||
openssl rand -base64 16
|
||||
```
|
||||
|
||||
2. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Access**: Open http://localhost/admin
|
||||
|
||||
4. **Login**: Use your WEBPASSWORD
|
||||
|
||||
5. **Configure DNS Settings**:
|
||||
- Set upstream DNS servers
|
||||
- Configure local network settings
|
||||
- Enable/disable features
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### Custom DNS Records (`pihole-dnsmasq.d/02-custom.conf`)
|
||||
```conf
|
||||
# Custom DNS records
|
||||
address=/homeserver.lan/192.168.1.100
|
||||
address=/nas.lan/192.168.1.101
|
||||
address=/camera.lan/192.168.1.102
|
||||
|
||||
# Local domain resolution
|
||||
local=/lan/
|
||||
domain=lan
|
||||
expand-hosts
|
||||
```
|
||||
|
||||
### Custom Blocklists (`pihole-dnsmasq.d/03-blocklist.conf`)
|
||||
```conf
|
||||
# Additional blocklists
|
||||
conf-file=/etc/pihole/custom.list
|
||||
|
||||
# Block specific domains
|
||||
address=/ads.example.com/0.0.0.0
|
||||
address=/tracker.example.com/0.0.0.0
|
||||
```
|
||||
|
||||
### DHCP Configuration (`pihole-dnsmasq.d/04-dhcp.conf`)
|
||||
```conf
|
||||
# DHCP settings (optional)
|
||||
dhcp-range=192.168.1.50,192.168.1.150,12h
|
||||
dhcp-option=option:router,192.168.1.1
|
||||
dhcp-option=option:dns,192.168.1.10
|
||||
dhcp-option=option:ntp,192.168.1.1
|
||||
|
||||
# Static leases
|
||||
dhcp-host=aa:bb:cc:dd:ee:ff,192.168.1.100,server
|
||||
```
|
||||
|
||||
## Network Configuration
|
||||
|
||||
### Router Setup
|
||||
1. **Disable DHCP on router** (if using Pi-hole for DHCP)
|
||||
2. **Set DNS on router** to Pi-hole IP (192.168.1.10)
|
||||
3. **Configure devices** to use router DNS
|
||||
|
||||
### Device Configuration
|
||||
```bash
|
||||
# Linux
|
||||
echo "nameserver 192.168.1.10" | sudo tee /etc/resolv.conf
|
||||
|
||||
# Windows (PowerShell)
|
||||
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses "192.168.1.10"
|
||||
|
||||
# macOS
|
||||
sudo networksetup -setdnsservers Wi-Fi 192.168.1.10
|
||||
```
|
||||
|
||||
## Blocklist Management
|
||||
|
||||
### Default Blocklists
|
||||
- Steven Black's blocklists
|
||||
- Firebog blocklists
|
||||
- Malware domains
|
||||
- Ad-serving domains
|
||||
|
||||
### Custom Blocklists
|
||||
```bash
|
||||
# Add custom blocklist
|
||||
curl -s https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | sudo tee /etc/pihole/custom.list
|
||||
|
||||
# Add specific domains
|
||||
echo "ads.example.com" | sudo tee -a /etc/pihole/custom.list
|
||||
```
|
||||
|
||||
### Whitelisting
|
||||
```bash
|
||||
# Add domain to whitelist
|
||||
docker exec pihole pihole -w example.com
|
||||
|
||||
# Remove from whitelist
|
||||
docker exec pihole pihole -w -d example.com
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Conditional Forwarding
|
||||
```yaml
|
||||
environment:
|
||||
- CONDITIONAL_FORWARDING=true
|
||||
- CONDITIONAL_FORWARDING_IP=192.168.1.1
|
||||
- CONDITIONAL_FORWARDING_DOMAIN=lan
|
||||
- CONDITIONAL_FORWARDING_REVERSE=192.168.1.0/24
|
||||
```
|
||||
|
||||
### DNSSEC
|
||||
```yaml
|
||||
environment:
|
||||
- DNSSEC=true
|
||||
```
|
||||
|
||||
### DNS over TLS
|
||||
```yaml
|
||||
environment:
|
||||
- PIHOLE_DNS_=1.1.1.1@853#cloudflare-dns.com;1.0.0.1@853#cloudflare-dns.com
|
||||
- DNS_FQDN_REQUIRED=true
|
||||
- DNSSEC=true
|
||||
```
|
||||
|
||||
## Monitoring and Statistics
|
||||
|
||||
### Web Interface
|
||||
- **Dashboard**: Overview of DNS queries
|
||||
- **Queries**: Real-time query log
|
||||
- **Statistics**: Top domains, clients, and queries
|
||||
- **Blocklists**: Manage blocklists and whitelists
|
||||
|
||||
### CLI Commands
|
||||
```bash
|
||||
# Check status
|
||||
docker exec pihole pihole status
|
||||
|
||||
# View query log
|
||||
docker exec pihole pihole -t
|
||||
|
||||
# Show top clients
|
||||
docker exec pihole pihole -c
|
||||
|
||||
# Show top domains
|
||||
docker exec pihole pihole -t -l
|
||||
|
||||
# Flush logs
|
||||
docker exec pihole pihole -f
|
||||
```
|
||||
|
||||
## API Usage
|
||||
```bash
|
||||
# Get stats
|
||||
curl -s http://localhost/admin/api.php?summary
|
||||
|
||||
# Get top items
|
||||
curl -s http://localhost/admin/api.php?topItems
|
||||
|
||||
# Get recent queries
|
||||
curl -s http://localhost/admin/api.php?recentBlocked
|
||||
|
||||
# Add to whitelist
|
||||
curl -X POST -d "list=whitelist&add=example.com" \
|
||||
http://localhost/admin/api.php
|
||||
|
||||
# Add to blacklist
|
||||
curl -X POST -d "list=blacklist&add=ads.example.com" \
|
||||
http://localhost/admin/api.php
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Pi-hole configuration
|
||||
docker run --rm -v pihole-config:/etc/pihole -v $(pwd):/backup alpine tar czf /backup/pihole-config-backup.tar.gz -C /etc/pihole .
|
||||
|
||||
# Backup gravity database
|
||||
docker exec pihole cp /etc/pihole/gravity.db /tmp/gravity.db
|
||||
docker cp pihole:/tmp/gravity.db ./gravity.db.backup
|
||||
|
||||
# Restore configuration
|
||||
docker run --rm -v pihole-config:/etc/pihole -v $(pwd):/backup alpine tar xzf /backup/pihole-config-backup.tar.gz -C /etc/pihole
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart pihole
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- DNSMASQ_CACHE_SIZE=10000
|
||||
- DNSMASQ_NEG_CACHE_TTL=3600
|
||||
- DNSMASQ_LOG_QUERIES=false
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Firewall Configuration
|
||||
```bash
|
||||
# Allow DNS (port 53)
|
||||
sudo ufw allow 53/tcp
|
||||
sudo ufw allow 53/udp
|
||||
|
||||
# Allow HTTP (port 80)
|
||||
sudo ufw allow 80/tcp
|
||||
|
||||
# Allow from local network only
|
||||
sudo ufw allow from 192.168.1.0/24 to any port 53
|
||||
sudo ufw allow from 192.168.1.0/24 to any port 80
|
||||
```
|
||||
|
||||
### Access Control
|
||||
```yaml
|
||||
# Restrict web access
|
||||
environment:
|
||||
- WEBTHEME=default-darker
|
||||
- TEMPERATUREUNIT=c
|
||||
- WEBUIBOXEDLAYOUT=traditional
|
||||
|
||||
# Enable password protection
|
||||
environment:
|
||||
- WEBPASSWORD=your-secure-password
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **DNS not working**: Check upstream DNS configuration
|
||||
- **Web interface inaccessible**: Verify port and firewall settings
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **Blocklist not updating**: Check internet connectivity
|
||||
- **DHCP conflicts**: Disable router DHCP if using Pi-hole DHCP
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Update blocklists
|
||||
docker exec pihole pihole -g
|
||||
|
||||
# Restart DNS service
|
||||
docker exec pihole pihole restartdns
|
||||
|
||||
# Check logs
|
||||
docker-compose logs -f pihole
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old logs
|
||||
docker exec pihole find /var/log/pihole -name "*.log.*" -mtime +30 -delete
|
||||
```
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Home Assistant
|
||||
```yaml
|
||||
# In Home Assistant configuration.yaml
|
||||
sensor:
|
||||
- platform: rest
|
||||
resource: http://192.168.1.10/admin/api.php?summary
|
||||
name: Pi-hole Stats
|
||||
value_template: "{{ value_json.ads_blocked_today }}"
|
||||
```
|
||||
|
||||
### Grafana Dashboard
|
||||
```bash
|
||||
# Add to Prometheus scrape config
|
||||
- job_name: 'pihole'
|
||||
static_configs:
|
||||
- targets: ['pihole:80']
|
||||
metrics_path: /admin/api.php?summaryRaw
|
||||
```
|
||||
|
||||
### Unifi Network
|
||||
- Set Pi-hole as DNS server in Unifi Controller
|
||||
- Configure DNS for all networks
|
||||
- Monitor DNS queries through Unifi
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Regex Blocking
|
||||
```bash
|
||||
# Add regex blocklist
|
||||
docker exec pihole pihole -b -adlist.regex "ads.*\.example\.com"
|
||||
```
|
||||
|
||||
### Per-Client Blocking
|
||||
```bash
|
||||
# Create group for specific client
|
||||
docker exec pihole pihole -g add "family" "Family Group"
|
||||
|
||||
# Add client to group
|
||||
docker exec pihole pihole -c add "192.168.1.50" "family"
|
||||
|
||||
# Assign blocklist to group
|
||||
docker exec pihole pihole -g assign "family" "default"
|
||||
```
|
||||
|
||||
### Query Logging
|
||||
```yaml
|
||||
# Enable detailed logging
|
||||
environment:
|
||||
- DNSMASQ_LOG_QUERIES=true
|
||||
- DNSMASQ_LOG_CACHE=true
|
||||
```
|
||||
|
||||
## Privacy Considerations
|
||||
- **Local DNS**: All queries processed locally
|
||||
- **No tracking**: Pi-hole doesn't track users
|
||||
- **Configurable logging**: Control what gets logged
|
||||
- **Blocklist choice**: Choose your blocklists
|
||||
- **Data retention**: Configure log retention policies
|
||||
@@ -0,0 +1,159 @@
|
||||
# Plex Media Server Template
|
||||
|
||||
## Overview
|
||||
Plex is a media server software that lets you organize and stream your media library.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
plex:
|
||||
image: lscr.io/linuxserver/plex:latest
|
||||
container_name: plex
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- PLEX_CLAIM=your-claim-token
|
||||
- PLEX_ADVERTISE_IP=http://your-local-ip
|
||||
- ALLOWED_NETWORKS=192.168.1.0/24
|
||||
volumes:
|
||||
- ./config:/config
|
||||
- /path/to/movies:/data/movies
|
||||
- /path/to/tv:/data/tvshows
|
||||
- /path/to/music:/data/music
|
||||
- /path/to/photos:/data/photos
|
||||
- /path/to/transcode:/transcode
|
||||
|
||||
volumes:
|
||||
config:
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `PUID`: User ID for file permissions
|
||||
- `PGID`: Group ID for file permissions
|
||||
- `TZ`: Timezone (find yours: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
|
||||
- `PLEX_CLAIM`: Claim token from https://plex.tv/claim
|
||||
- `PLEX_ADVERTISE_IP`: Your server's local IP
|
||||
- `ALLOWED_NETWORKS`: Networks allowed to access Plex
|
||||
|
||||
## Setup Guide
|
||||
1. **Get Claim Token**:
|
||||
- Visit https://plex.tv/claim
|
||||
- Copy the token (valids for 4 minutes)
|
||||
|
||||
2. **Prepare Media Directories**:
|
||||
```bash
|
||||
mkdir -p /path/to/movies
|
||||
mkdir -p /path/to/tvshows
|
||||
mkdir -p /path/to/music
|
||||
mkdir -p /path/to/photos
|
||||
mkdir -p /path/to/transcode
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://your-local-ip:32400/web
|
||||
|
||||
5. **Complete Setup**:
|
||||
- Sign in/create Plex account
|
||||
- Add media libraries
|
||||
- Configure remote access
|
||||
|
||||
## Directory Structure
|
||||
```
|
||||
/path/to/media/
|
||||
├── movies/
|
||||
│ ├── Movie Name (Year)/
|
||||
│ │ ├── Movie Name (Year).mp4
|
||||
│ │ └── subtitles/
|
||||
├── tvshows/
|
||||
│ ├── Show Name/
|
||||
│ │ ├── Season 01/
|
||||
│ │ │ ├── S01E01.mkv
|
||||
│ │ │ └── S01E02.mkv
|
||||
│ │ └── Season 02/
|
||||
├── music/
|
||||
│ └── Artist Name/
|
||||
│ └── Album Name/
|
||||
│ ├── song1.mp3
|
||||
│ └── song2.mp3
|
||||
└── photos/
|
||||
└── 2024/
|
||||
├── vacation/
|
||||
└── family/
|
||||
```
|
||||
|
||||
## Hardware Requirements
|
||||
- **CPU**: Intel Core i3 or better (for transcoding)
|
||||
- **RAM**: 4GB minimum, 8GB recommended
|
||||
- **Storage**: SSD for OS/apps, HDD for media
|
||||
- **Network**: Gigabit recommended for 4K streaming
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For systems with limited resources
|
||||
environment:
|
||||
- PLEX_TRANSCODER_CACHE_SIZE=200000000
|
||||
- PLEX_RAMDISK_SIZE=300000000
|
||||
|
||||
# For NVIDIA GPU transcoding
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
# Note: Plex works best with host networking, but if using bridge mode:
|
||||
ports:
|
||||
- "32400:32400"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.plex.rule=Host(`plex.yourdomain.com`)"
|
||||
- "traefik.http.routers.plex.tls=true"
|
||||
- "traefik.http.routers.plex.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.plex.loadbalancer.server.port=32400"
|
||||
```
|
||||
|
||||
## Backup
|
||||
```bash
|
||||
# Backup Plex config
|
||||
docker run --rm -v plex_config:/data -v $(pwd):/backup alpine tar czf /backup/plex-config.tar.gz -C /data .
|
||||
|
||||
# Restore Plex config
|
||||
docker run --rm -v plex_config:/data -v $(pwd):/backup alpine tar xzf /backup/plex-config.tar.gz -C /data
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
- **Logs**: `docker-compose logs -f plex`
|
||||
- **Status**: Check web dashboard
|
||||
- **Performance**: Monitor CPU/RAM usage during transcoding
|
||||
|
||||
## Security
|
||||
- Use strong passwords
|
||||
- Enable secure connections
|
||||
- Regular updates
|
||||
- Network segmentation if possible
|
||||
|
||||
## Troubleshooting
|
||||
- **Port conflicts**: Use host networking or change ports
|
||||
- **Permission issues**: Check PUID/PGID match host user
|
||||
- **Transcoding**: Ensure sufficient CPU/RAM
|
||||
- **Remote access**: Configure router port forwarding
|
||||
@@ -0,0 +1,390 @@
|
||||
# Supabase Open Source Firebase Alternative Template
|
||||
|
||||
## Overview
|
||||
Supabase is an open source Firebase alternative that provides a complete backend-as-a-service platform.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: supabase/postgres:15.1.0.117
|
||||
container_name: supabase-db
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_PASSWORD: your-super-secret-and-long-postgres-password
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_INITDB_ARGS: --auth-host=scram
|
||||
volumes:
|
||||
- ./volumes/db:/var/lib/postgresql/data
|
||||
- ./volumes/db/init:/docker-entrypoint-initdb.d
|
||||
ports:
|
||||
- "54322:5432"
|
||||
command:
|
||||
- postgres
|
||||
- -c
|
||||
- config_file=/etc/postgresql/postgresql.conf
|
||||
- -c
|
||||
- log_min_messages=warning
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
auth:
|
||||
image: supabase/gotrue:v2.91.3
|
||||
container_name: supabase-auth
|
||||
restart: always
|
||||
environment:
|
||||
GOTRUE_API_HOST: 0.0.0.0
|
||||
GOTRUE_API_PORT: 9999
|
||||
GOTRUE_DB_DRIVER: postgres
|
||||
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:your-super-secret-and-long-postgres-password@db:5432/auth
|
||||
GOTRUE_JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
GOTRUE_JWT_EXP: 3600
|
||||
GOTRUE_JWT_AUD: authenticated
|
||||
GOTRUE_SITE_URL: http://localhost:3000
|
||||
GOTRUE_URI_ALLOW_LIST: "*"
|
||||
GOTRUE_DISABLE_SIGNUP: false
|
||||
GOTRUE_EXTERNAL_EMAIL_ENABLED: true
|
||||
GOTRUE_MAILER_AUTOCONFIRM: true
|
||||
GOTRUE_EXTERNAL_PHONE_ENABLED: true
|
||||
ports:
|
||||
- "9999:9999"
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
rest:
|
||||
image: postgrest/postgrest:v12.0.1
|
||||
container_name: supabase-rest
|
||||
restart: always
|
||||
environment:
|
||||
PGRST_DB_URI: postgres://authenticator:your-super-secret-and-long-postgres-password@db:5432/postgres
|
||||
PGRST_DB_SCHEMA: public,storage
|
||||
PGRST_DB_ANON_ROLE: anon
|
||||
PGRST_DB_SEARCH_PATH: public
|
||||
PGRST_SERVER_HOST: 0.0.0.0
|
||||
PGRST_SERVER_PORT: 3000
|
||||
PGRST_JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- db
|
||||
- auth
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
realtime:
|
||||
image: supabase/realtime:v2.25.73
|
||||
container_name: supabase-realtime
|
||||
restart: always
|
||||
environment:
|
||||
PORT: 4000
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DB_USER: supabase_realtime_admin
|
||||
DB_PASSWORD: your-super-secret-and-long-postgres-password
|
||||
DB_NAME: postgres
|
||||
DB_AFTER_CONNECT_QUERY: 'SET application_name = ''realtime'''
|
||||
DB_ENC_KEY: supabaserealtimeprotected-please-replace-this
|
||||
API_JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
SECURE_CHANNELS: true
|
||||
ports:
|
||||
- "4000:4000"
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
storage:
|
||||
image: supabase/storage:v0.48.0
|
||||
container_name: supabase-storage
|
||||
restart: always
|
||||
environment:
|
||||
ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOoJeerx0ntWqyT4DPCXUGSktY8R8Qw2HtWo
|
||||
SERVICE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8HdpbfsT3JApj1JNFo
|
||||
POSTGRES_PASSWORD: your-super-secret-and-long-postgres-password
|
||||
PGOPTIONS: "-c search_path=storage,public"
|
||||
FILE_SIZE_LIMIT: 52428800
|
||||
STORAGE_BACKEND: file
|
||||
STORAGE_FILE_PATH: /var/lib/storage
|
||||
TENANT_ID: stub
|
||||
REGION: stub
|
||||
GLOBAL_S3_BUCKET: stub
|
||||
volumes:
|
||||
- ./volumes/storage:/var/lib/storage
|
||||
ports:
|
||||
- "5000:5000"
|
||||
depends_on:
|
||||
- db
|
||||
- rest
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
meta:
|
||||
image: supabase/postgres-meta:v0.74.0
|
||||
container_name: supabase-meta
|
||||
restart: always
|
||||
environment:
|
||||
PG_META_PORT: 8080
|
||||
PG_META_DB_HOST: db
|
||||
PG_META_DB_PORT: 5432
|
||||
PG_META_DB_NAME: postgres
|
||||
PG_META_DB_USER: supabase_admin
|
||||
PG_META_DB_PASSWORD: your-super-secret-and-long-postgres-password
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
functions:
|
||||
image: supabase/edge-runtime:v1.47.4
|
||||
container_name: supabase-functions
|
||||
restart: always
|
||||
environment:
|
||||
JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
SUPABASE_URL: http://localhost:8000
|
||||
SUPABASE_ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOoJeerx0ntWqyT4DPCXUGSktY8R8Qw2HtWo
|
||||
SUPABASE_SERVICE_ROLE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8HdpbfsT3JApj1JNFo
|
||||
volumes:
|
||||
- ./volumes/functions:/home/deno/functions
|
||||
ports:
|
||||
- "9000:9000"
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
kong:
|
||||
image: kong:3.4
|
||||
container_name: supabase-kong
|
||||
restart: always
|
||||
environment:
|
||||
KONG_DATABASE: "off"
|
||||
KONG_DECLARATIVE_CONFIG: /var/lib/kong/kong.yml
|
||||
KONG_PROXY_ACCESS_LOG: /dev/stdout
|
||||
KONG_ADMIN_ACCESS_LOG: /dev/stdout
|
||||
KONG_PROXY_ERROR_LOG: /dev/stderr
|
||||
KONG_ADMIN_ERROR_LOG: /dev/stderr
|
||||
KONG_ADMIN_LISTEN: 0.0.0.0:8001
|
||||
KONG_ADMIN_GUI_URL: http://localhost:8002
|
||||
volumes:
|
||||
- ./volumes/kong:/var/lib/kong
|
||||
- ./kong.yml:/var/lib/kong/kong.yml
|
||||
ports:
|
||||
- "8000:8000"
|
||||
- "8001:8001"
|
||||
- "8002:8002"
|
||||
networks:
|
||||
- supabase-network
|
||||
|
||||
networks:
|
||||
supabase-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Kong Configuration (kong.yml)
|
||||
```yaml
|
||||
_format_version: "3.0"
|
||||
_transform: true
|
||||
|
||||
services:
|
||||
- name: auth
|
||||
url: http://auth:9999
|
||||
routes:
|
||||
- name: auth
|
||||
paths: ["/auth/v1/*"]
|
||||
strip_path: false
|
||||
|
||||
- name: rest
|
||||
url: http://rest:3000
|
||||
routes:
|
||||
- name: rest
|
||||
paths: ["/rest/v1/*"]
|
||||
strip_path: false
|
||||
|
||||
- name: realtime
|
||||
url: http://realtime:4000/socket.io/
|
||||
routes:
|
||||
- name: realtime
|
||||
paths: ["/realtime/v1/*"]
|
||||
strip_path: false
|
||||
|
||||
- name: storage
|
||||
url: http://storage:5000
|
||||
routes:
|
||||
- name: storage
|
||||
paths: ["/storage/v1/*"]
|
||||
strip_path: false
|
||||
|
||||
- name: functions
|
||||
url: http://functions:9000
|
||||
routes:
|
||||
- name: functions
|
||||
paths: ["/functions/v1/*"]
|
||||
strip_path: false
|
||||
|
||||
- name: meta
|
||||
url: http://meta:8080
|
||||
routes:
|
||||
- name: meta
|
||||
paths: ["/pg-meta/*"]
|
||||
strip_path: false
|
||||
|
||||
plugins:
|
||||
- name: cors
|
||||
service: auth
|
||||
config:
|
||||
origins: ["*"]
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||
headers: ["accept", "authorization", "content-type", "apikey", "x-client-info"]
|
||||
exposed_headers: ["content-length"]
|
||||
max_age: 3600
|
||||
credentials: true
|
||||
|
||||
- name: cors
|
||||
service: rest
|
||||
config:
|
||||
origins: ["*"]
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
|
||||
headers: ["accept", "authorization", "content-type", "apikey", "x-client-info"]
|
||||
exposed_headers: ["content-length"]
|
||||
max_age: 3600
|
||||
credentials: true
|
||||
|
||||
- name: cors
|
||||
service: storage
|
||||
config:
|
||||
origins: ["*"]
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
|
||||
headers: ["accept", "authorization", "content-type", "apikey", "x-client-info"]
|
||||
exposed_headers: ["content-length"]
|
||||
max_age: 3600
|
||||
credentials: true
|
||||
|
||||
- name: cors
|
||||
service: functions
|
||||
config:
|
||||
origins: ["*"]
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
|
||||
headers: ["accept", "authorization", "content-type", "apikey", "x-client-info"]
|
||||
exposed_headers: ["content-length"]
|
||||
max_age: 3600
|
||||
credentials: true
|
||||
```
|
||||
|
||||
## Environment Variables Setup
|
||||
```bash
|
||||
# Generate secure passwords and tokens
|
||||
POSTGRES_PASSWORD=$(openssl rand -base64 32)
|
||||
JWT_SECRET=$(openssl rand -base64 32)
|
||||
DB_ENC_KEY=$(openssl rand -base64 32)
|
||||
|
||||
# Replace in docker-compose.yml
|
||||
sed -i "s/your-super-secret-and-long-postgres-password/$POSTGRES_PASSWORD/g" docker-compose.yml
|
||||
sed -i "s/your-super-secret-jwt-token-with-at-least-32-characters-long/$JWT_SECRET/g" docker-compose.yml
|
||||
sed -i "s/supabaserealtimeprotected-please-replace-this/$DB_ENC_KEY/g" docker-compose.yml
|
||||
```
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Secrets**:
|
||||
```bash
|
||||
# Run the commands above to generate secure passwords
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p volumes/{db,storage,functions,kong}
|
||||
mkdir -p volumes/db/init
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access Points**:
|
||||
- **API Gateway**: http://localhost:8000
|
||||
- **Studio**: http://localhost:8000 (via Kong)
|
||||
- **Database**: localhost:54322
|
||||
- **Kong Admin**: http://localhost:8002
|
||||
|
||||
## API Endpoints
|
||||
- **Auth**: http://localhost:8000/auth/v1/
|
||||
- **REST**: http://localhost:8000/rest/v1/
|
||||
- **Realtime**: http://localhost:8000/realtime/v1/
|
||||
- **Storage**: http://localhost:8000/storage/v1/
|
||||
- **Functions**: http://localhost:8000/functions/v1/
|
||||
- **Meta**: http://localhost:8000/pg-meta/
|
||||
|
||||
## Database Setup
|
||||
```sql
|
||||
-- Create initial schema
|
||||
CREATE SCHEMA IF NOT EXISTS auth;
|
||||
CREATE SCHEMA IF NOT EXISTS storage;
|
||||
CREATE SCHEMA IF NOT EXISTS realtime;
|
||||
CREATE SCHEMA IF NOT EXISTS extensions;
|
||||
|
||||
-- Enable required extensions
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_graphql";
|
||||
```
|
||||
|
||||
## Client Libraries
|
||||
```javascript
|
||||
// JavaScript/TypeScript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'http://localhost:8000',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOoJeerx0ntWqyT4DPCXUGSktY8R8Qw2HtWo'
|
||||
)
|
||||
|
||||
// Example usage
|
||||
const { data, error } = await supabase
|
||||
.from('users')
|
||||
.select('*')
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup database
|
||||
docker exec supabase-db pg_dump -U postgres > supabase-backup.sql
|
||||
|
||||
# Backup storage
|
||||
tar czf storage-backup.tar.gz volumes/storage/
|
||||
|
||||
# Restore database
|
||||
docker exec -i supabase-db psql -U postgres < supabase-backup.sql
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# PostgreSQL tuning
|
||||
environment:
|
||||
POSTGRES_SHARED_PRELOAD_LIBRARIES: pg_stat_statements
|
||||
POSTGRES_MAX_CONNECTIONS: 200
|
||||
POSTGRES_SHARED_BUFFERS: 256MB
|
||||
POSTGRES_EFFECTIVE_CACHE_SIZE: 1GB
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change all default passwords
|
||||
- Use HTTPS in production
|
||||
- Enable RLS (Row Level Security)
|
||||
- Regular database backups
|
||||
- Monitor access logs
|
||||
|
||||
## Troubleshooting
|
||||
- **Connection issues**: Check network and ports
|
||||
- **Database errors**: Review PostgreSQL logs
|
||||
- **Auth problems**: Verify JWT configuration
|
||||
- **Storage failures**: Check disk permissions
|
||||
@@ -0,0 +1,381 @@
|
||||
# Traefik Reverse Proxy Template
|
||||
|
||||
## Overview
|
||||
Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.0
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- "--api=true"
|
||||
- "--api.insecure=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
- "--global.checknewversion=false"
|
||||
- "--global.sendanonymoususage=false"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
- ./traefik.yml:/traefik.yml:ro
|
||||
networks:
|
||||
- traefik-network
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
|
||||
|
||||
volumes:
|
||||
letsencrypt:
|
||||
|
||||
networks:
|
||||
traefik-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Configuration File (`traefik.yml`)
|
||||
```yaml
|
||||
api:
|
||||
dashboard: true
|
||||
insecure: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
scheme: https
|
||||
websecure:
|
||||
address: ":443"
|
||||
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: traefik-network
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: your-email@example.com
|
||||
storage: /letsencrypt/acme.json
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `TRAEFIK_API_DASHBOARD`: Enable dashboard (true/false)
|
||||
- `TRAEFIK_API_INSECURE`: Enable insecure dashboard (true/false)
|
||||
- `TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_EMAIL`: Let's Encrypt email
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Let's Encrypt Email**:
|
||||
```bash
|
||||
# Use your actual email for certificate notifications
|
||||
EMAIL="your-email@example.com"
|
||||
```
|
||||
|
||||
2. **Create Directories**:
|
||||
```bash
|
||||
mkdir -p letsencrypt
|
||||
```
|
||||
|
||||
3. **Configure DNS**:
|
||||
- Point `yourdomain.com` and `*.yourdomain.com` to your server IP
|
||||
- Ensure ports 80 and 443 are accessible
|
||||
|
||||
4. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
5. **Access**:
|
||||
- **Dashboard**: http://traefik.yourdomain.com:8080
|
||||
- **API**: http://traefik.yourdomain.com:8080/api/
|
||||
|
||||
## Service Integration Examples
|
||||
|
||||
### Basic Web Service
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
container_name: whoami
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=websecure"
|
||||
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.whoami.loadbalancer.server.port=80"
|
||||
networks:
|
||||
- traefik-network
|
||||
```
|
||||
|
||||
### WordPress with HTTPS
|
||||
```yaml
|
||||
services:
|
||||
wordpress:
|
||||
image: wordpress:latest
|
||||
container_name: wordpress
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db:3306
|
||||
WORDPRESS_DB_USER: wordpress
|
||||
WORDPRESS_DB_PASSWORD: wordpress
|
||||
WORDPRESS_DB_NAME: wordpress
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.wordpress.rule=Host(`blog.yourdomain.com`)"
|
||||
- "traefik.http.routers.wordpress.entrypoints=websecure"
|
||||
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
|
||||
networks:
|
||||
- traefik-network
|
||||
- default
|
||||
```
|
||||
|
||||
### Nextcloud with HTTPS
|
||||
```yaml
|
||||
services:
|
||||
nextcloud:
|
||||
image: nextcloud:latest
|
||||
container_name: nextcloud
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.nextcloud.rule=Host(`cloud.yourdomain.com`)"
|
||||
- "traefik.http.routers.nextcloud.entrypoints=websecure"
|
||||
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||
- "traefik.http.middlewares.nextcloud-headers.headers.customRequestHeaders.X-Forwarded-Proto=https"
|
||||
- "traefik.http.routers.nextcloud.middlewares=nextcloud-headers"
|
||||
networks:
|
||||
- traefik-network
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Middleware Examples
|
||||
```yaml
|
||||
# Rate limiting
|
||||
labels:
|
||||
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
|
||||
- "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
|
||||
- "traefik.http.routers.api.middlewares=ratelimit"
|
||||
|
||||
# Basic auth
|
||||
labels:
|
||||
- "traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$hash"
|
||||
|
||||
# Compression
|
||||
labels:
|
||||
- "traefik.http.middlewares.compress.compress=true"
|
||||
- "traefik.http.routers.api.middlewares=compress"
|
||||
|
||||
# Security headers
|
||||
labels:
|
||||
- "traefik.http.middlewares.secure.headers.stsSeconds=31536000"
|
||||
- "traefik.http.middlewares.secure.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.secure.headers.stsPreload=true"
|
||||
- "traefik.http.middlewares.secure.headers.forceSTSHeader=true"
|
||||
- "traefik.http.middlewares.secure.headers.frameDeny=true"
|
||||
- "traefik.http.middlewares.secure.headers.contentTypeNosniff=true"
|
||||
- "traefik.http.middlewares.secure.headers.browserXSSFilter=true"
|
||||
- "traefik.http.middlewares.secure.headers.referrerPolicy=strict-origin-when-cross-origin"
|
||||
```
|
||||
|
||||
### Load Balancing
|
||||
```yaml
|
||||
services:
|
||||
app1:
|
||||
image: myapp:latest
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.app.rule=Host(`app.yourdomain.com`)"
|
||||
- "traefik.http.routers.app.entrypoints=websecure"
|
||||
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.app.loadbalancer.server.port=8080"
|
||||
- "traefik.http.services.app.loadbalancer.passHostHeader=true"
|
||||
|
||||
app2:
|
||||
image: myapp:latest
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.app.loadbalancer.server.port=8080"
|
||||
```
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
### Prometheus Metrics
|
||||
```yaml
|
||||
# Add to traefik command
|
||||
- "--metrics.prometheus=true"
|
||||
- "--metrics.prometheus.addEntryPointsLabels=true"
|
||||
- "--metrics.prometheus.addServicesLabels=true"
|
||||
- "--entrypoints.metrics.address=:8082"
|
||||
```
|
||||
|
||||
### Grafana Dashboard
|
||||
```yaml
|
||||
# Add to Prometheus scrape config
|
||||
- job_name: 'traefik'
|
||||
static_configs:
|
||||
- targets: ['traefik:8082']
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Secure Dashboard
|
||||
```yaml
|
||||
# Remove insecure dashboard
|
||||
command:
|
||||
- "--api.dashboard=true"
|
||||
- "--api.insecure=false"
|
||||
- "--entrypoints.traefik.address=:8443"
|
||||
|
||||
labels:
|
||||
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
|
||||
- "traefik.http.routers.traefik.entrypoints=websecure"
|
||||
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.routers.traefik.middlewares=auth"
|
||||
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$hash"
|
||||
```
|
||||
|
||||
### Network Security
|
||||
```yaml
|
||||
# Create internal network for services
|
||||
networks:
|
||||
traefik-public:
|
||||
driver: bridge
|
||||
traefik-internal:
|
||||
driver: bridge
|
||||
internal: true
|
||||
|
||||
services:
|
||||
traefik:
|
||||
networks:
|
||||
- traefik-public
|
||||
- traefik-internal
|
||||
|
||||
database:
|
||||
networks:
|
||||
- traefik-internal
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Let's Encrypt certificates
|
||||
tar czf letsencrypt-backup.tar.gz letsencrypt/
|
||||
|
||||
# Backup Traefik configuration
|
||||
cp traefik.yml traefik-backup.yml
|
||||
|
||||
# Restore certificates
|
||||
tar xzf letsencrypt-backup.tar.gz
|
||||
docker-compose restart traefik
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# Enable connection reuse
|
||||
command:
|
||||
- "--serversTransport.maxIdleConnsPerHost=100"
|
||||
- "--entrypoints.web.forwardingTimeouts.dialTimeout=30s"
|
||||
- "--entrypoints.web.forwardingTimeouts.responseHeaderTimeout=30s"
|
||||
- "--entrypoints.web.forwardingTimeouts.idleTimeout=180s"
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.2'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Certificate issues**: Check DNS and port 80 accessibility
|
||||
- **Service not reachable**: Verify labels and network configuration
|
||||
- **Performance problems**: Check resource usage and connection limits
|
||||
- **Dashboard access**: Verify authentication configuration
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f traefik
|
||||
|
||||
# Check certificates
|
||||
docker exec traefik ls -la /letsencrypt/
|
||||
|
||||
# Renew certificates (automatic)
|
||||
# Traefik automatically renews certificates 30 days before expiry
|
||||
|
||||
# Update Traefik
|
||||
docker-compose pull && docker-compose up -d
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Multi-tenant Setup
|
||||
```yaml
|
||||
# Different domains for different services
|
||||
services:
|
||||
service1:
|
||||
labels:
|
||||
- "traefik.http.routers.service1.rule=Host(`service1.yourdomain.com`)"
|
||||
|
||||
service2:
|
||||
labels:
|
||||
- "traefik.http.routers.service2.rule=Host(`service2.yourdomain.com`)"
|
||||
```
|
||||
|
||||
### Path-based Routing
|
||||
```yaml
|
||||
services:
|
||||
api:
|
||||
labels:
|
||||
- "traefik.http.routers.api.rule=Host(`yourdomain.com`) && PathPrefix(`/api`)"
|
||||
|
||||
web:
|
||||
labels:
|
||||
- "traefik.http.routers.web.rule=Host(`yourdomain.com`)"
|
||||
```
|
||||
|
||||
### WebSocket Support
|
||||
```yaml
|
||||
services:
|
||||
websocket-app:
|
||||
labels:
|
||||
- "traefik.http.routers.ws.rule=Host(`ws.yourdomain.com`)"
|
||||
- "traefik.http.routers.ws.entrypoints=websecure"
|
||||
- "traefik.http.services.ws.loadbalancer.server.port=8080"
|
||||
```
|
||||
@@ -0,0 +1,125 @@
|
||||
# Umami Analytics Template
|
||||
|
||||
## Overview
|
||||
Umami is a simple, fast, privacy-focused alternative to Google Analytics.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
umami:
|
||||
image: ghcr.io/umami-software/umami:postgresql-latest
|
||||
container_name: umami
|
||||
restart: always
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
DATABASE_URL: postgresql://umami:umami@db:5432/umami
|
||||
APP_SECRET: replace-with-random-string
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- umami-network
|
||||
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
container_name: umami-db
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: umami
|
||||
POSTGRES_USER: umami
|
||||
POSTGRES_PASSWORD: umami
|
||||
volumes:
|
||||
- umami-db-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- umami-network
|
||||
|
||||
volumes:
|
||||
umami-db-data:
|
||||
|
||||
networks:
|
||||
umami-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `DATABASE_URL`: PostgreSQL connection string
|
||||
- `APP_SECRET`: Random string for application secrets (generate with: `openssl rand -base64 32`)
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate APP_SECRET**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
2. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Access**: Open http://localhost:3000
|
||||
|
||||
4. **Default Login**:
|
||||
- Username: `admin`
|
||||
- Password: `umami`
|
||||
|
||||
5. **Change Password**: Update admin password immediately
|
||||
|
||||
## Configuration
|
||||
- **Tracking Code**: Get from dashboard after adding website
|
||||
- **Data Retention**: Configure in admin settings
|
||||
- **Geolocation**: Enable IP-based location tracking
|
||||
|
||||
## Volumes
|
||||
- `umami-db-data`: PostgreSQL data persistence
|
||||
|
||||
## Ports
|
||||
- `3000`: Umami web interface
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.umami.rule=Host(`analytics.yourdomain.com`)"
|
||||
- "traefik.http.routers.umami.tls=true"
|
||||
- "traefik.http.routers.umami.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.umami.loadbalancer.server.port=3000"
|
||||
```
|
||||
|
||||
## Backup
|
||||
```bash
|
||||
# Backup database
|
||||
docker exec umami-db pg_dump -U umami umami > umami-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i umami-db psql -U umami umami < umami-backup.sql
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
- **Health Check**: Container auto-restarts on failure
|
||||
- **Logs**: `docker-compose logs -f umami`
|
||||
- **Metrics**: Built-in analytics dashboard
|
||||
|
||||
## Security
|
||||
- Change default credentials
|
||||
- Use strong hash salt
|
||||
- Enable HTTPS in production
|
||||
- Regular database backups
|
||||
@@ -0,0 +1,284 @@
|
||||
# Uptime Kuma Monitoring Template
|
||||
|
||||
## Overview
|
||||
Uptime Kuma is a fancy self-hosted monitoring tool that helps you track your websites, APIs, and services.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
uptime-kuma:
|
||||
image: louislam/uptime-kuma:1
|
||||
container_name: uptime-kuma
|
||||
restart: always
|
||||
ports:
|
||||
- "3001:3001"
|
||||
volumes:
|
||||
- uptime-kuma-data:/app/data
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
networks:
|
||||
- uptime-kuma-network
|
||||
|
||||
volumes:
|
||||
uptime-kuma-data:
|
||||
|
||||
networks:
|
||||
uptime-kuma-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `NODE_ENV=production`: Run in production mode
|
||||
|
||||
## Setup Guide
|
||||
1. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
2. **Access**: Open http://localhost:3001
|
||||
|
||||
3. **Initial Setup**:
|
||||
- Create admin account
|
||||
- Set administrator password
|
||||
- Choose language preference
|
||||
|
||||
4. **Add First Monitor**:
|
||||
- Click "Add New Monitor"
|
||||
- Enter URL/IP to monitor
|
||||
- Set check interval
|
||||
- Configure notifications
|
||||
|
||||
## Monitor Types
|
||||
|
||||
### HTTP(s) Monitor
|
||||
```yaml
|
||||
# Example configuration
|
||||
Monitor Type: HTTP(s)
|
||||
Friendly Name: My Website
|
||||
URL: https://example.com
|
||||
Interval: 60 seconds
|
||||
Timeout: 30 seconds
|
||||
Retries: 3
|
||||
```
|
||||
|
||||
### TCP Port Monitor
|
||||
```yaml
|
||||
# Example configuration
|
||||
Monitor Type: TCP
|
||||
Friendly Name: SSH Server
|
||||
Hostname: server.example.com
|
||||
Port: 22
|
||||
Interval: 60 seconds
|
||||
Timeout: 10 seconds
|
||||
```
|
||||
|
||||
### Ping Monitor
|
||||
```yaml
|
||||
# Example configuration
|
||||
Monitor Type: Ping
|
||||
Friendly Name: Router
|
||||
Hostname: 192.168.1.1
|
||||
Interval: 30 seconds
|
||||
Packet Size: 56
|
||||
```
|
||||
|
||||
### DNS Monitor
|
||||
```yaml
|
||||
# Example configuration
|
||||
Monitor Type: DNS
|
||||
Friendly Name: Domain Resolution
|
||||
Hostname: example.com
|
||||
DNS Server: 8.8.8.8
|
||||
Resolve Type: A
|
||||
Interval: 300 seconds
|
||||
```
|
||||
|
||||
## Notification Channels
|
||||
|
||||
### Email Notifications
|
||||
```yaml
|
||||
# Setup in Uptime Kuma UI
|
||||
Notification Type: Email
|
||||
SMTP Host: smtp.gmail.com
|
||||
SMTP Port: 587
|
||||
Username: your-email@gmail.com
|
||||
Password: your-app-password
|
||||
From Email: monitor@example.com
|
||||
To Emails: admin@example.com
|
||||
```
|
||||
|
||||
### Discord Notifications
|
||||
```yaml
|
||||
# Setup in Uptime Kuma UI
|
||||
Notification Type: Discord
|
||||
Webhook URL: https://discord.com/api/webhooks/YOUR_WEBHOOK_URL
|
||||
```
|
||||
|
||||
### Telegram Notifications
|
||||
```yaml
|
||||
# Setup in Uptime Kuma UI
|
||||
Notification Type: Telegram
|
||||
Bot Token: YOUR_BOT_TOKEN
|
||||
Chat ID: YOUR_CHAT_ID
|
||||
```
|
||||
|
||||
### Slack Notifications
|
||||
```yaml
|
||||
# Setup in Uptime Kuma UI
|
||||
Notification Type: Slack
|
||||
Webhook URL: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.uptime-kuma.rule=Host(`status.yourdomain.com`)"
|
||||
- "traefik.http.routers.uptime-kuma.tls=true"
|
||||
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Uptime Kuma data
|
||||
docker run --rm -v uptime-kuma-data:/data -v $(pwd):/backup alpine tar czf /backup/uptime-kuma-backup.tar.gz -C /data .
|
||||
|
||||
# Restore Uptime Kuma data
|
||||
docker run --rm -v uptime-kuma-data:/data -v $(pwd):/backup alpine tar xzf /backup/uptime-kuma-backup.tar.gz -C /data
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart uptime-kuma
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For high-volume monitoring
|
||||
environment:
|
||||
- UPTIME_KUMA_MAX_MONITORS_PER_PAGE=100
|
||||
- UPTIME_KUMA_HEARTBEAT_INTERVAL=20
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.2'
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom HTTP Headers
|
||||
```yaml
|
||||
# In monitor configuration
|
||||
HTTP Headers:
|
||||
User-Agent: Uptime-Kuma/1.0.0
|
||||
Authorization: Bearer YOUR_TOKEN
|
||||
```
|
||||
|
||||
### HTTP POST Body
|
||||
```yaml
|
||||
# For API monitoring
|
||||
Method: POST
|
||||
Body: '{"key": "value"}'
|
||||
Headers:
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### Expected Status Codes
|
||||
```yaml
|
||||
# Custom status codes
|
||||
Accepted Status Codes: 200,201,202,204
|
||||
```
|
||||
|
||||
## Security
|
||||
- Change default admin password
|
||||
- Use HTTPS in production
|
||||
- Network access control
|
||||
- Regular backups
|
||||
- Monitor access logs
|
||||
|
||||
## API Usage
|
||||
```bash
|
||||
# Get all monitors
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:3001/api/monitors
|
||||
|
||||
# Get monitor status
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:3001/api/monitors/1/status
|
||||
|
||||
# Add monitor via API
|
||||
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"http","name":"Test","url":"https://example.com"}' \
|
||||
http://localhost:3001/api/monitors
|
||||
```
|
||||
|
||||
## Monitoring Best Practices
|
||||
1. **Set appropriate intervals**: Don't check too frequently
|
||||
2. **Use retries**: Handle temporary network issues
|
||||
3. **Configure timeouts**: Prevent hanging checks
|
||||
4. **Set up notifications**: Get alerts for issues
|
||||
5. **Group monitors**: Organize by service/environment
|
||||
6. **Use tags**: Filter and categorize monitors
|
||||
|
||||
## Troubleshooting
|
||||
- **Monitor failures**: Check network connectivity
|
||||
- **Notification issues**: Verify webhook/API keys
|
||||
- **Performance problems**: Reduce check frequency
|
||||
- **Database errors**: Check disk space and permissions
|
||||
- **Access problems**: Verify firewall settings
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Docker Container Monitoring
|
||||
```yaml
|
||||
Monitor Type: HTTP
|
||||
URL: http://container-ip:port/health
|
||||
Interval: 30 seconds
|
||||
Expected Status Code: 200
|
||||
```
|
||||
|
||||
### Database Monitoring
|
||||
```yaml
|
||||
Monitor Type: TCP
|
||||
Hostname: postgres-server
|
||||
Port: 5432
|
||||
Interval: 60 seconds
|
||||
```
|
||||
|
||||
### SSL Certificate Monitoring
|
||||
```yaml
|
||||
Monitor Type: HTTP(s)
|
||||
URL: https://example.com
|
||||
Check Certificate: true
|
||||
Days Before Expiry: 30
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs -f uptime-kuma
|
||||
|
||||
# Restart service
|
||||
docker-compose restart uptime-kuma
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec uptime-kuma npm run prune
|
||||
```
|
||||
@@ -0,0 +1,371 @@
|
||||
# Vaultwarden Bitwarden Alternative Template
|
||||
|
||||
## Overview
|
||||
Vaultwarden is an alternative implementation of the Bitwarden server API written in Rust, compatible with Bitwarden clients.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
# Create docker-compose.yml with the content below
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:latest
|
||||
container_name: vaultwarden
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- SIGNUPS_ALLOWED=true
|
||||
- ADMIN_TOKEN=your-secure-admin-token
|
||||
- DOMAIN=https://vault.yourdomain.com
|
||||
- DATABASE_URL=postgresql://vaultwarden:vaultwarden@postgres:5432/vaultwarden
|
||||
- SMTP_HOST=smtp.gmail.com
|
||||
- SMTP_PORT=587
|
||||
- SMTP_SECURITY=tls
|
||||
- SMTP_FROM=your-email@gmail.com
|
||||
- SMTP_USERNAME=your-email@gmail.com
|
||||
- SMTP_PASSWORD=your-app-password
|
||||
- WEBSOCKET_ENABLED=true
|
||||
- WEBSOCKET_ADDRESS=0.0.0.0:3012
|
||||
volumes:
|
||||
- vaultwarden-data:/data
|
||||
depends_on:
|
||||
- postgres
|
||||
networks:
|
||||
- vaultwarden-network
|
||||
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: vaultwarden-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=vaultwarden
|
||||
- POSTGRES_USER=vaultwarden
|
||||
- POSTGRES_PASSWORD=vaultwarden
|
||||
volumes:
|
||||
- vaultwarden-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- vaultwarden-network
|
||||
|
||||
volumes:
|
||||
vaultwarden-data:
|
||||
vaultwarden-db:
|
||||
|
||||
networks:
|
||||
vaultwarden-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
- `SIGNUPS_ALLOWED`: Allow new user registrations
|
||||
- `ADMIN_TOKEN`: Admin panel access token
|
||||
- `DOMAIN`: Your domain for proper links
|
||||
- `DATABASE_URL`: PostgreSQL connection string
|
||||
- `SMTP_*`: Email configuration for invitations
|
||||
- `WEBSOCKET_ENABLED`: Enable real-time sync
|
||||
- `WEBSOCKET_ADDRESS`: WebSocket bind address
|
||||
|
||||
## Setup Guide
|
||||
1. **Generate Admin Token**:
|
||||
```bash
|
||||
openssl rand -base64 48
|
||||
```
|
||||
|
||||
2. **Configure SMTP** (Optional but recommended):
|
||||
- Get app password from email provider
|
||||
- Configure SMTP settings
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Access**: Open http://localhost:8080
|
||||
|
||||
5. **Admin Panel**: Open http://localhost:8080/admin
|
||||
- Use your admin token to access
|
||||
- Configure settings and manage users
|
||||
|
||||
6. **Create Account**:
|
||||
- Register first user account
|
||||
- Disable signups after creating admin account
|
||||
|
||||
## Client Setup
|
||||
|
||||
### Web Vault
|
||||
- Access: http://localhost:8080
|
||||
- Login with your created account
|
||||
- Import passwords from other managers
|
||||
|
||||
### Browser Extensions
|
||||
- **Chrome**: Install Bitwarden extension
|
||||
- **Firefox**: Install Bitwarden extension
|
||||
- **Edge**: Install Bitwarden extension
|
||||
- **Safari**: Install Bitwarden extension
|
||||
|
||||
### Mobile Apps
|
||||
- **iOS**: Download from App Store
|
||||
- **Android**: Download from Google Play
|
||||
- **F-Droid**: Available on F-Droid
|
||||
|
||||
### Desktop Apps
|
||||
- **Windows**: Download from Bitwarden website
|
||||
- **macOS**: Download from Bitwarden website
|
||||
- **Linux**: Download from Bitwarden website
|
||||
|
||||
## Configuration
|
||||
|
||||
### Advanced Environment Variables
|
||||
```yaml
|
||||
environment:
|
||||
# Basic settings
|
||||
- SIGNUPS_ALLOWED=false
|
||||
- ADMIN_TOKEN=your-secure-admin-token
|
||||
- DOMAIN=https://vault.yourdomain.com
|
||||
|
||||
# Database
|
||||
- DATABASE_URL=postgresql://vaultwarden:vaultwarden@postgres:5432/vaultwarden
|
||||
|
||||
# Email
|
||||
- SMTP_HOST=smtp.gmail.com
|
||||
- SMTP_PORT=587
|
||||
- SMTP_SECURITY=tls
|
||||
- SMTP_FROM=your-email@gmail.com
|
||||
- SMTP_USERNAME=your-email@gmail.com
|
||||
- SMTP_PASSWORD=your-app-password
|
||||
|
||||
# Security
|
||||
- PASSWORD_ITERATIONS=100000
|
||||
- PBKDF2_MEMORY=64
|
||||
- PBKDF2_PARALLELISM=4
|
||||
|
||||
# Features
|
||||
- WEBSOCKET_ENABLED=true
|
||||
- WEBSOCKET_ADDRESS=0.0.0.0:3012
|
||||
- SENDS_ALLOWED=true
|
||||
- EMERGENCY_ACCESS_ALLOWED=true
|
||||
|
||||
# Limits
|
||||
- ORG_EVENTS_DAYS=90
|
||||
- ORG_ATTACHMENT_LIMIT=104857600
|
||||
- USER_ATTACHMENT_LIMIT=10485760
|
||||
```
|
||||
|
||||
### YubiKey Support
|
||||
```yaml
|
||||
environment:
|
||||
- YUBICO_CLIENT_ID=your-yubico-client-id
|
||||
- YUBICO_SECRET_KEY=your-yubico-secret-key
|
||||
```
|
||||
|
||||
## Reverse Proxy (Traefik)
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.vaultwarden.rule=Host(`vault.yourdomain.com`)"
|
||||
- "traefik.http.routers.vaultwarden.tls=true"
|
||||
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.vaultwarden.loadbalancer.server.port=8080"
|
||||
|
||||
# WebSocket support
|
||||
- "traefik.http.routers.vaultwarden-websockets.rule=Host(`vault.yourdomain.com`) && PathPrefix(`/notifications/hub`)"
|
||||
- "traefik.http.routers.vaultwarden-websockets.entrypoints=websecure"
|
||||
- "traefik.http.services.vaultwarden-websockets.loadbalancer.server.port=3012"
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
```bash
|
||||
# Backup Vaultwarden data
|
||||
docker run --rm -v vaultwarden-data:/data -v $(pwd):/backup alpine tar czf /backup/vaultwarden-backup.tar.gz -C /data .
|
||||
|
||||
# Backup PostgreSQL database
|
||||
docker exec vaultwarden-postgres pg_dump -U vaultwarden vaultwarden > vaultwarden-db-backup.sql
|
||||
|
||||
# Restore database
|
||||
docker exec -i vaultwarden-postgres psql -U vaultwarden vaultwarden < vaultwarden-db-backup.sql
|
||||
|
||||
# Restore Vaultwarden data
|
||||
docker run --rm -v vaultwarden-data:/data -v $(pwd):/backup alpine tar xzf /backup/vaultwarden-backup.tar.gz -C /data
|
||||
|
||||
# Restart after restore
|
||||
docker-compose restart vaultwarden
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Production Setup
|
||||
```yaml
|
||||
environment:
|
||||
- SIGNUPS_ALLOWED=false
|
||||
- ADMIN_TOKEN=your-secure-admin-token
|
||||
- DOMAIN=https://vault.yourdomain.com
|
||||
- PASSWORD_ITERATIONS=100000
|
||||
- PBKDF2_MEMORY=64
|
||||
- PBKDF2_PARALLELISM=4
|
||||
```
|
||||
|
||||
### SSL/TLS Configuration
|
||||
```yaml
|
||||
# Use HTTPS in production
|
||||
environment:
|
||||
- DOMAIN=https://vault.yourdomain.com
|
||||
|
||||
# Configure proper certificates
|
||||
# Traefik will handle Let's Encrypt automatically
|
||||
```
|
||||
|
||||
### Access Control
|
||||
```yaml
|
||||
# Restrict admin access
|
||||
environment:
|
||||
- ADMIN_TOKEN=your-secure-admin-token
|
||||
|
||||
# Network isolation
|
||||
networks:
|
||||
vaultwarden-internal:
|
||||
driver: bridge
|
||||
internal: true
|
||||
vaultwarden-external:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## User Management
|
||||
|
||||
### Admin Panel Features
|
||||
- **User management**: View and manage all users
|
||||
- **Organization management**: Manage organizations
|
||||
- **System diagnostics**: Check system health
|
||||
- **Configuration**: Adjust settings
|
||||
- **Audit logs**: View user activity
|
||||
|
||||
### Organization Setup
|
||||
1. Create organization in admin panel
|
||||
2. Invite users via email
|
||||
3. Set up collections and groups
|
||||
4. Configure access policies
|
||||
|
||||
### Emergency Access
|
||||
```yaml
|
||||
environment:
|
||||
- EMERGENCY_ACCESS_ALLOWED=true
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
```yaml
|
||||
# For better performance
|
||||
environment:
|
||||
- DATABASE_MAX_CONNS=10
|
||||
- WEBSOCKET_ENABLED=true
|
||||
- WEBSOCKET_HEARTBEAT_INTERVAL=30
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
# Check if service is running
|
||||
curl http://localhost:8080/alive
|
||||
|
||||
# Check admin panel
|
||||
curl http://localhost:8080/admin/diagnostics
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f vaultwarden
|
||||
|
||||
# Check for errors
|
||||
docker-compose logs vaultwarden | grep ERROR
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
- **Login issues**: Check domain configuration
|
||||
- **Email problems**: Verify SMTP settings
|
||||
- **Performance issues**: Monitor resource usage
|
||||
- **Database errors**: Check PostgreSQL connection
|
||||
- **WebSocket issues**: Verify reverse proxy configuration
|
||||
|
||||
## Migration from Bitwarden
|
||||
1. **Export from Bitwarden**: Use Bitwarden export feature
|
||||
2. **Import to Vaultwarden**: Use web vault import
|
||||
3. **Update clients**: Point clients to new server URL
|
||||
4. **Disable old account**: Cancel Bitwarden subscription
|
||||
|
||||
## API Usage
|
||||
```bash
|
||||
# Get user info
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8080/api/accounts/profile
|
||||
|
||||
# Get organizations
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" \
|
||||
http://localhost:8080/api/organizations
|
||||
|
||||
# Admin API
|
||||
curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||||
http://localhost:8080/api/users
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
```bash
|
||||
# Restart service
|
||||
docker-compose restart vaultwarden
|
||||
|
||||
# Update image
|
||||
docker-compose pull && docker-compose up -d
|
||||
|
||||
# Clean up old data
|
||||
docker exec vaultwarden vaultwarden db cleanup
|
||||
|
||||
# Check database size
|
||||
docker exec vaultwarden-postgres psql -U vaultwarden -c "SELECT pg_size_pretty(pg_database_size('vaultwarden'));"
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### SSO Integration
|
||||
```yaml
|
||||
environment:
|
||||
- SSO_ENABLED=true
|
||||
- SSO_SECRET_KEY=your-sso-secret
|
||||
- SSO_REDIRECT_URI=https://vault.yourdomain.com/sso
|
||||
```
|
||||
|
||||
### Duo 2FA
|
||||
```yaml
|
||||
environment:
|
||||
- DUO_IKEY=your-duo-ikey
|
||||
- DUO_SKEY=your-duo-skey
|
||||
- DUO_HOST=your-duo-host
|
||||
```
|
||||
|
||||
### Custom Icon Service
|
||||
```yaml
|
||||
environment:
|
||||
- ICON_SERVICE=https://icons.bitwarden.net
|
||||
- ICON_BLACKLISTED_NONPROXY_IPS=127.0.0.1,::1
|
||||
```
|
||||
|
||||
## Compliance
|
||||
- **GDPR**: Data protection and privacy
|
||||
- **SOC2**: Security controls
|
||||
- **HIPAA**: Healthcare data protection (with proper configuration)
|
||||
- **AES-256**: Encryption for all data
|
||||
- **PBKDF2**: Key derivation for passwords
|
||||
Reference in New Issue
Block a user