Deploying Flare
Introduction
Flare is a beautiful, self-hosted bookmark manager and RSS feed reader that combines elegant design with powerful functionality. Built with PHP and Laravel, Flare provides a unified dashboard for organizing your bookmarks, tracking RSS feeds, and managing web content in one centralized location. With its clean interface inspired by modern design principles, Flare makes content organization feel effortless and enjoyable.
Deploying Flare on Klutch.sh gives you complete control over your bookmarks and feeds with automatic Dockerfile detection, persistent storage for your content library, and seamless Redis integration for caching. Whether you’re consolidating scattered bookmarks, building a personal knowledge base, or creating a curated content hub, this guide provides everything you need to deploy Flare with production-ready configurations.
Why Deploy Flare on Klutch.sh?
- One-Click Deployment: Automatic Dockerfile detection and container orchestration
- Persistent Storage: Dedicated volumes for bookmarks, feeds, and application data
- Secure Secrets Management: Environment variables for sensitive credentials
- Auto-Scaling: Resources scale based on your content library size
- Custom Domains: Use your own domain for professional branding
- Automated Backups: Built-in backup solutions for your content
- Redis Integration: Seamless caching layer for improved performance
- SSL/TLS: Automatic HTTPS certificates for secure access
- GitHub Integration: Deploy directly from your repository with auto-updates
Prerequisites
Before deploying Flare on Klutch.sh, ensure you have:
- A Klutch.sh account
- A GitHub account with a repository for your project
- Docker installed locally for testing (optional but recommended)
- Basic familiarity with Docker and environment variables
- Access to a Redis instance (deploy separately on Klutch.sh - see Redis guide)
- Understanding of bookmarking and RSS feed concepts
Understanding Flare Architecture
Flare is built on the Laravel PHP framework and requires:
- PHP 8.1+ for running the application
- MySQL or SQLite database for storing bookmarks, feeds, and user data
- Redis (optional but recommended) for caching and session management
- Web server (Nginx or Apache) for serving the application
- Feed fetcher for periodic RSS/Atom feed updates
- File storage for favicons, thumbnails, and cached content
The application runs on port 8000 by default. For Klutch.sh deployments with HTTP traffic, you’ll configure the internal port to 8000.
Project Structure
A standard Flare deployment structure:
flare-deployment/├── Dockerfile├── docker-entrypoint.sh├── .env.example├── nginx.conf (optional)└── README.mdSample Dockerfile
Create a Dockerfile in the root of your repository. Klutch.sh will automatically detect and use it for deployment.
Basic Dockerfile
FROM php:8.2-fpm-alpine
# Install system dependenciesRUN apk add --no-cache \ nginx \ supervisor \ nodejs \ npm \ git \ curl \ sqlite \ sqlite-dev \ libpng-dev \ libjpeg-turbo-dev \ freetype-dev \ zip \ unzip
# Install PHP extensionsRUN docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) \ pdo \ pdo_mysql \ pdo_sqlite \ gd \ opcache
# Install ComposerCOPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directoryWORKDIR /var/www/html
# Clone Flare repositoryRUN git clone https://github.com/soulteary/flare.git . \ && composer install --no-dev --optimize-autoloader \ && npm install \ && npm run build
# Create necessary directoriesRUN mkdir -p /var/www/html/storage/app/public \ && mkdir -p /var/www/html/storage/framework/cache \ && mkdir -p /var/www/html/storage/framework/sessions \ && mkdir -p /var/www/html/storage/framework/views \ && mkdir -p /var/www/html/storage/logs \ && mkdir -p /var/www/html/bootstrap/cache
# Set permissionsRUN chown -R www-data:www-data /var/www/html/storage \ && chown -R www-data:www-data /var/www/html/bootstrap/cache \ && chmod -R 775 /var/www/html/storage \ && chmod -R 775 /var/www/html/bootstrap/cache
# Copy Nginx configurationCOPY nginx.conf /etc/nginx/nginx.conf
# Copy supervisor configurationRUN echo "[supervisord]" > /etc/supervisor/conf.d/supervisord.conf \ && echo "nodaemon=true" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "[program:nginx]" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "command=nginx -g 'daemon off;'" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "autostart=true" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "autorestart=true" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stdout_logfile=/dev/stdout" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stdout_logfile_maxbytes=0" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stderr_logfile=/dev/stderr" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stderr_logfile_maxbytes=0" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "[program:php-fpm]" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "command=php-fpm" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "autostart=true" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "autorestart=true" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stdout_logfile=/dev/stdout" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stdout_logfile_maxbytes=0" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stderr_logfile=/dev/stderr" >> /etc/supervisor/conf.d/supervisord.conf \ && echo "stderr_logfile_maxbytes=0" >> /etc/supervisor/conf.d/supervisord.conf
# Copy entrypoint scriptCOPY docker-entrypoint.sh /usr/local/bin/RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Expose portEXPOSE 8000
# Start supervisorENTRYPOINT ["docker-entrypoint.sh"]CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]Production Dockerfile with Version Pinning
FROM php:8.2.15-fpm-alpine3.19
# Install system dependencies with specific versionsRUN apk add --no-cache \ nginx=1.24.0-r15 \ supervisor=4.2.5-r4 \ nodejs=20.11.0-r0 \ npm=10.2.5-r0 \ git=2.43.0-r0 \ curl=8.5.0-r0 \ sqlite=3.44.2-r0 \ sqlite-dev=3.44.2-r0 \ libpng-dev=1.6.40-r0 \ libjpeg-turbo-dev=3.0.1-r0 \ freetype-dev=2.13.2-r0 \ zip=3.0-r12 \ unzip=6.0-r14
# Install PHP extensionsRUN docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) \ pdo \ pdo_mysql \ pdo_sqlite \ gd \ opcache
# Configure PHP for productionRUN { \ echo 'opcache.memory_consumption=128'; \ echo 'opcache.interned_strings_buffer=8'; \ echo 'opcache.max_accelerated_files=4000'; \ echo 'opcache.revalidate_freq=2'; \ echo 'opcache.fast_shutdown=1'; \ echo 'opcache.enable=1'; \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache.ini
# Install ComposerCOPY --from=composer:2.6 /usr/bin/composer /usr/bin/composer
# Set working directoryWORKDIR /var/www/html
# Clone specific version of FlareARG FLARE_VERSION=mainRUN git clone --depth 1 --branch ${FLARE_VERSION} https://github.com/soulteary/flare.git . \ && composer install --no-dev --optimize-autoloader --no-interaction \ && npm ci --only=production \ && npm run build \ && rm -rf node_modules
# Create necessary directories with proper structureRUN mkdir -p \ /var/www/html/storage/app/public \ /var/www/html/storage/framework/cache/data \ /var/www/html/storage/framework/sessions \ /var/www/html/storage/framework/views \ /var/www/html/storage/logs \ /var/www/html/bootstrap/cache \ /var/www/html/public/storage
# Set permissionsRUN chown -R www-data:www-data /var/www/html \ && chmod -R 775 /var/www/html/storage \ && chmod -R 775 /var/www/html/bootstrap/cache
# Copy Nginx configurationCOPY nginx.conf /etc/nginx/nginx.conf
# Copy supervisor configurationCOPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Copy entrypoint scriptCOPY docker-entrypoint.sh /usr/local/bin/RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1
# Expose portEXPOSE 8000
# Start supervisorENTRYPOINT ["docker-entrypoint.sh"]CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]Configuration Files
Nginx Configuration
Create nginx.conf:
worker_processes auto;error_log /var/log/nginx/error.log warn;pid /var/run/nginx.pid;
events { worker_connections 1024;}
http { include /etc/nginx/mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; client_max_body_size 20M;
gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
server { listen 8000; server_name _; root /var/www/html/public; index index.php index.html;
charset utf-8;
location / { try_files $uri $uri/ /index.php?$query_string; }
location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; fastcgi_hide_header X-Powered-By; }
location ~ /\.(?!well-known).* { deny all; } }}Docker Entrypoint Script
Create docker-entrypoint.sh:
#!/bin/shset -e
echo "Starting Flare initialization..."
# Wait for database to be ready (if using external database)if [ -n "$DB_HOST" ]; then echo "Waiting for database connection..." timeout=30 while ! nc -z "$DB_HOST" "${DB_PORT:-3306}" 2>/dev/null; do timeout=$((timeout - 1)) if [ $timeout -le 0 ]; then echo "Database connection timeout!" exit 1 fi echo "Waiting for database... ($timeout seconds remaining)" sleep 1 done echo "Database is ready!"fi
# Wait for Redis to be ready (if configured)if [ -n "$REDIS_HOST" ]; then echo "Waiting for Redis connection..." timeout=30 while ! nc -z "$REDIS_HOST" "${REDIS_PORT:-6379}" 2>/dev/null; do timeout=$((timeout - 1)) if [ $timeout -le 0 ]; then echo "Redis connection timeout!" exit 1 fi echo "Waiting for Redis... ($timeout seconds remaining)" sleep 1 done echo "Redis is ready!"fi
# Generate application key if not setif [ -z "$APP_KEY" ] || [ "$APP_KEY" = "base64:CHANGE_THIS_TO_RANDOM_STRING" ]; then echo "Generating application key..." php artisan key:generate --forcefi
# Run database migrationsecho "Running database migrations..."php artisan migrate --force
# Create storage symlinkecho "Creating storage symlink..."php artisan storage:link || true
# Clear and cache configurationecho "Optimizing application..."php artisan config:cachephp artisan route:cachephp artisan view:cache
# Set proper permissionsecho "Setting permissions..."chown -R www-data:www-data /var/www/html/storagechown -R www-data:www-data /var/www/html/bootstrap/cache
echo "Flare initialization complete!"
# Execute the main commandexec "$@"Supervisor Configuration
Create supervisord.conf:
[supervisord]nodaemon=trueuser=rootlogfile=/var/log/supervisor/supervisord.logpidfile=/var/run/supervisord.pid
[program:nginx]command=nginx -g 'daemon off;'autostart=trueautorestart=truepriority=10stdout_logfile=/dev/stdoutstdout_logfile_maxbytes=0stderr_logfile=/dev/stderrstderr_logfile_maxbytes=0
[program:php-fpm]command=php-fpm -Fautostart=trueautorestart=truepriority=5stdout_logfile=/dev/stdoutstdout_logfile_maxbytes=0stderr_logfile=/dev/stderrstderr_logfile_maxbytes=0
[program:queue-worker]command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --max-time=3600autostart=trueautorestart=trueuser=www-datanumprocs=2redirect_stderr=truestdout_logfile=/var/www/html/storage/logs/worker.logstopwaitsecs=3600Environment Variables
Required Environment Variables
# ApplicationAPP_NAME=FlareAPP_ENV=productionAPP_KEY=base64:GENERATE_WITH_ARTISAN_KEY_GENERATEAPP_DEBUG=falseAPP_URL=https://example-app.klutch.sh
# Database (SQLite - Default)DB_CONNECTION=sqliteDB_DATABASE=/var/www/html/storage/database.sqlite
# Or MySQL DatabaseDB_CONNECTION=mysqlDB_HOST=your-mysql-app.klutch.shDB_PORT=8000DB_DATABASE=flareDB_USERNAME=flare_userDB_PASSWORD=your_secure_database_password
# Redis (Optional but Recommended)REDIS_HOST=your-redis-app.klutch.shREDIS_PASSWORD=your_redis_passwordREDIS_PORT=8000CACHE_DRIVER=redisSESSION_DRIVER=redisQUEUE_CONNECTION=redis
# Mail Configuration (Optional)MAIL_MAILER=smtpMAIL_HOST=smtp.mailtrap.ioMAIL_PORT=2525MAIL_USERNAME=nullMAIL_PASSWORD=nullMAIL_ENCRYPTION=tlsMAIL_FROM_ADDRESS=noreply@example.comMAIL_FROM_NAME="${APP_NAME}"Optional Configuration
# Feed FetchingFLARE_FEED_FETCH_INTERVAL=30FLARE_MAX_FEEDS_PER_USER=100FLARE_FEED_TIMEOUT=30
# BookmarksFLARE_MAX_BOOKMARKS_PER_USER=1000FLARE_BOOKMARK_PREVIEW_ENABLED=true
# File StorageFILESYSTEM_DISK=localAWS_ACCESS_KEY_ID=AWS_SECRET_ACCESS_KEY=AWS_DEFAULT_REGION=us-east-1AWS_BUCKET=
# LoggingLOG_CHANNEL=stackLOG_LEVEL=error
# SecuritySESSION_LIFETIME=120SESSION_SECURE_COOKIE=trueDeploying to Klutch.sh
Step 1: Prepare Your Repository
-
Create a new GitHub repository for your Flare deployment
-
Add all the files mentioned above:
Dockerfilenginx.confdocker-entrypoint.shsupervisord.conf.env.example(for reference)README.md(optional documentation)
-
Commit and push to GitHub:
git initgit add .git commit -m "Initial Flare deployment setup"git branch -M maingit remote add origin https://github.com/yourusername/flare-deployment.gitgit push -u origin mainStep 2: Deploy Redis (Optional but Recommended)
For optimal performance, deploy Redis separately. See the Redis deployment guide for detailed instructions.
Quick Redis setup:
- Create a new app in Klutch.sh for Redis
- Use the official Redis Docker image
- Set TCP traffic mode
- Configure internal port 6379, external port 8000
- Add a strong password via
REDIS_PASSWORDenvironment variable - Attach a persistent volume at
/data - Note the Redis connection details for Flare configuration
Step 3: Create Flare Application
-
Log in to your Klutch.sh dashboard
-
Click “Create New App”
-
Select “Import from GitHub”
-
Choose your Flare deployment repository
-
Configure deployment settings:
- App Name:
flare-bookmarks(or your preferred name) - Branch:
main - Root Directory:
/(if Dockerfile is in root)
- App Name:
Step 4: Configure Application Settings
-
Set Traffic Type:
- Select HTTP traffic (Flare is a web application)
- Set Internal Port to
8000
-
Add Environment Variables:
Navigate to the “Environment Variables” section and add:
Essential Variables:
APP_NAME=FlareAPP_ENV=productionAPP_DEBUG=falseAPP_URL=https://your-app-name.klutch.shDB_CONNECTION=sqliteDB_DATABASE=/var/www/html/storage/database.sqliteRedis Configuration (if using):
REDIS_HOST=your-redis-app.klutch.shREDIS_PORT=8000REDIS_PASSWORD=your_redis_passwordCACHE_DRIVER=redisSESSION_DRIVER=redisQUEUE_CONNECTION=redisNote: The
APP_KEYwill be generated automatically by the entrypoint script on first run.
Step 5: Attach Persistent Volume
Flare requires persistent storage for bookmarks, feeds, and database:
-
Navigate to “Volumes” in your app settings
-
Click “Attach Volume”
-
Configure volume:
- Mount Path:
/var/www/html/storage - Size: Start with 5GB (adjust based on content volume)
- Mount Path:
-
Save the volume configuration
Step 6: Deploy the Application
-
Review all settings
-
Click “Deploy”
-
Klutch.sh will:
- Clone your repository
- Detect the Dockerfile
- Build the container image
- Deploy to production
- Assign a public URL
-
Monitor the build logs for any errors
-
Wait for deployment to complete (typically 5-10 minutes for first build)
Initial Setup and Configuration
Accessing Flare
Once deployed, access your Flare instance:
- Navigate to your app URL:
https://your-app-name.klutch.sh - Complete the initial setup wizard:
- Create your admin account
- Configure basic settings
- Set your timezone and preferences
Adding Your First Bookmarks
-
Click “Add Bookmark” in the dashboard
-
Enter bookmark details:
- URL (required)
- Title (auto-fetched or manual)
- Description
- Tags for organization
- Category
-
Flare will automatically fetch:
- Page title and description
- Favicon
- Screenshot (if enabled)
- Metadata
-
Click “Save” to add the bookmark
Setting Up RSS Feeds
-
Navigate to the “Feeds” section
-
Click “Add Feed”
-
Enter feed URL (RSS or Atom format)
-
Configure feed settings:
- Update frequency
- Category/folder
- Read/unread marking
-
Flare will automatically:
- Fetch feed content
- Parse articles
- Schedule periodic updates
Organizing Content
Create an organizational structure:
- Create Tags: Add relevant tags to bookmarks
- Set Up Categories: Organize by topic or project
- Create Collections: Group related bookmarks together
- Use Folders: Hierarchical organization for feeds
- Search Filters: Save common search queries
- Custom Views: Configure dashboard layouts
Browser Extension Setup
Flare supports browser extensions for quick bookmarking:
Chrome/Edge Extension
-
Visit your Flare instance settings
-
Navigate to “Integrations” → “Browser Extension”
-
Copy the API key or authentication token
-
Install the Flare browser extension from your instance
-
Configure extension with your Flare URL and credentials
-
Start bookmarking with one click!
Bookmarklet Alternative
If no extension is available:
- Go to “Settings” → “Bookmarklet”
- Drag the bookmarklet to your bookmarks bar
- Click it on any page to quickly save
Production Best Practices
Security Hardening
-
Strong Application Key:
Terminal window php artisan key:generate -
Secure Session Configuration:
Terminal window SESSION_SECURE_COOKIE=trueSESSION_HTTP_ONLY=trueSESSION_SAME_SITE=lax -
Database Security:
- Use strong database passwords
- Limit database user permissions
- Enable SSL for database connections
-
Rate Limiting:
- Configure API rate limits
- Enable login throttling
- Implement CAPTCHA for public instances
Performance Optimization
-
Enable Redis Caching:
- Cache configuration
- Session management
- Queue processing
-
Configure OPcache:
Terminal window opcache.enable=1opcache.memory_consumption=128opcache.max_accelerated_files=4000 -
Optimize Database:
- Regular VACUUM (SQLite)
- Index optimization
- Query caching
-
Asset Optimization:
- Minify CSS/JS
- Enable Gzip compression
- Use CDN for static assets
Backup Strategy
-
Volume Backups:
- Regular automated backups via Klutch.sh
- Export bookmarks periodically
- Download database snapshots
-
Export Options:
Terminal window # HTML exporthttps://your-app.klutch.sh/export/html# JSON exporthttps://your-app.klutch.sh/export/json# RSS exporthttps://your-app.klutch.sh/export/rss -
Disaster Recovery:
- Document environment variables
- Keep Dockerfile in version control
- Test restore procedures
Monitoring and Maintenance
-
Application Monitoring:
- Check CPU and memory usage in Klutch.sh dashboard
- Monitor response times
- Track error rates
-
Log Management:
Terminal window # View Laravel logstail -f storage/logs/laravel.log# View Nginx logstail -f /var/log/nginx/access.logtail -f /var/log/nginx/error.log -
Regular Updates:
- Update Flare version in Dockerfile
- Run database migrations
- Update dependencies
- Security patches
-
Database Maintenance:
Terminal window # Optimize databasephp artisan optimize:clearphp artisan config:cachephp artisan route:cache
Troubleshooting
Application Won’t Start
Symptoms: Container crashes or fails to start
Solutions:
-
Check Klutch.sh build logs for errors
-
Verify all required environment variables are set:
Terminal window APP_KEY, APP_URL, DB_CONNECTION -
Ensure volume is properly attached:
Terminal window Mount path: /var/www/html/storage -
Check file permissions:
Terminal window chmod -R 775 storage bootstrap/cache
Database Connection Errors
Symptoms: “Connection refused” or “Access denied”
Solutions:
-
Verify database credentials in environment variables
-
For MySQL, check connection details:
- Host:
your-mysql-app.klutch.sh - Port:
8000(external port for TCP traffic) - Database exists and user has permissions
- Host:
-
For SQLite, ensure volume is mounted correctly
-
Test database connection:
Terminal window php artisan migrate:status
Redis Connection Issues
Symptoms: Caching failures or session problems
Solutions:
-
Verify Redis is running and accessible
-
Check Redis configuration:
Terminal window REDIS_HOST=your-redis-app.klutch.shREDIS_PORT=8000REDIS_PASSWORD=correct_password -
Test Redis connection:
Terminal window redis-cli -h your-redis-app.klutch.sh -p 8000 -a password PING -
Fall back to file-based cache if needed:
Terminal window CACHE_DRIVER=fileSESSION_DRIVER=file
Feed Updates Not Working
Symptoms: RSS feeds not updating with new content
Solutions:
-
Check queue worker is running:
Terminal window # Verify in supervisor logstail -f storage/logs/worker.log -
Manually trigger feed update:
Terminal window php artisan feeds:fetch -
Verify cron/scheduler is configured:
Terminal window php artisan schedule:run -
Check feed URL validity:
- Test feed URL in browser
- Verify feed format (RSS/Atom)
- Check for SSL certificate issues
Slow Performance
Symptoms: Pages load slowly or timeout
Solutions:
-
Enable Redis caching:
Terminal window CACHE_DRIVER=redisSESSION_DRIVER=redis -
Optimize application:
Terminal window php artisan config:cachephp artisan route:cachephp artisan view:cache -
Increase resources in Klutch.sh dashboard
-
Check for large volumes of data:
- Archive old bookmarks
- Clean up unused feeds
- Optimize database
500 Internal Server Error
Symptoms: HTTP 500 errors when accessing pages
Solutions:
-
Enable debug mode temporarily:
Terminal window APP_DEBUG=true -
Check application logs:
Terminal window storage/logs/laravel.log -
Verify permissions:
Terminal window chown -R www-data:www-data storage bootstrap/cache -
Clear caches:
Terminal window php artisan cache:clearphp artisan config:clearphp artisan view:clear
Custom Domain Configuration
To use a custom domain with Flare:
-
In Klutch.sh dashboard, navigate to “Domains”
-
Click “Add Custom Domain”
-
Enter your domain (e.g.,
bookmarks.yourdomain.com) -
Follow DNS configuration instructions:
- Add CNAME record pointing to your Klutch.sh app
- Or add A record with provided IP address
-
Update environment variable:
Terminal window APP_URL=https://bookmarks.yourdomain.com -
Redeploy the application
-
Wait for DNS propagation (typically 5-30 minutes)
-
SSL certificate will be automatically provisioned
Advanced Configuration
S3 Storage Integration
Store favicons and screenshots in S3:
FILESYSTEM_DISK=s3AWS_ACCESS_KEY_ID=your_access_keyAWS_SECRET_ACCESS_KEY=your_secret_keyAWS_DEFAULT_REGION=us-east-1AWS_BUCKET=your-flare-bucketAWS_USE_PATH_STYLE_ENDPOINT=falseEmail Notifications
Configure SMTP for notifications:
MAIL_MAILER=smtpMAIL_HOST=smtp.gmail.comMAIL_PORT=587MAIL_USERNAME=your-email@gmail.comMAIL_PASSWORD=your-app-passwordMAIL_ENCRYPTION=tlsMAIL_FROM_ADDRESS=noreply@yourdomain.comMAIL_FROM_NAME="Flare Bookmarks"Multi-User Configuration
Enable user registration:
FLARE_ALLOW_REGISTRATION=trueFLARE_REQUIRE_EMAIL_VERIFICATION=trueFLARE_MAX_USERS=100API Access
Configure API for integrations:
FLARE_API_ENABLED=trueFLARE_API_RATE_LIMIT=60FLARE_API_AUTH_TYPE=tokenIntegration Examples
Python - Bookmark Management
import requestsfrom typing import List, Dict
class FlareClient: def __init__(self, base_url: str, api_token: str): self.base_url = base_url.rstrip('/') self.api_token = api_token self.headers = { 'Authorization': f'Bearer {api_token}', 'Content-Type': 'application/json' }
def add_bookmark(self, url: str, title: str = None, description: str = None, tags: List[str] = None) -> Dict: """Add a new bookmark""" payload = { 'url': url, 'title': title, 'description': description, 'tags': tags or [] }
response = requests.post( f'{self.base_url}/api/bookmarks', json=payload, headers=self.headers ) response.raise_for_status() return response.json()
def get_bookmarks(self, tag: str = None, limit: int = 100) -> List[Dict]: """Retrieve bookmarks""" params = {'limit': limit} if tag: params['tag'] = tag
response = requests.get( f'{self.base_url}/api/bookmarks', params=params, headers=self.headers ) response.raise_for_status() return response.json()
def search_bookmarks(self, query: str) -> List[Dict]: """Search bookmarks""" response = requests.get( f'{self.base_url}/api/bookmarks/search', params={'q': query}, headers=self.headers ) response.raise_for_status() return response.json()
def delete_bookmark(self, bookmark_id: int) -> bool: """Delete a bookmark""" response = requests.delete( f'{self.base_url}/api/bookmarks/{bookmark_id}', headers=self.headers ) response.raise_for_status() return True
# Usageclient = FlareClient( base_url='https://example-app.klutch.sh', api_token='your_api_token_here')
# Add bookmarkbookmark = client.add_bookmark( url='https://example.com/article', title='Interesting Article', description='A great read about technology', tags=['tech', 'programming'])
# Search bookmarksresults = client.search_bookmarks('kubernetes')
# Get bookmarks by tagtech_bookmarks = client.get_bookmarks(tag='tech', limit=50)JavaScript/Node.js - Feed Reader
const axios = require('axios');
class FlareFeedClient { constructor(baseUrl, apiToken) { this.baseUrl = baseUrl.replace(/\/$/, ''); this.apiToken = apiToken; this.client = axios.create({ baseURL: this.baseUrl, headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' } }); }
async addFeed(feedUrl, category = null) { const response = await this.client.post('/api/feeds', { url: feedUrl, category: category }); return response.data; }
async getFeeds(category = null) { const params = category ? { category } : {}; const response = await this.client.get('/api/feeds', { params }); return response.data; }
async getFeedItems(feedId, limit = 20, unreadOnly = false) { const response = await this.client.get(`/api/feeds/${feedId}/items`, { params: { limit, unread: unreadOnly } }); return response.data; }
async markAsRead(itemId) { const response = await this.client.post(`/api/items/${itemId}/read`); return response.data; }
async markAllAsRead(feedId) { const response = await this.client.post(`/api/feeds/${feedId}/mark-all-read`); return response.data; }
async refreshFeed(feedId) { const response = await this.client.post(`/api/feeds/${feedId}/refresh`); return response.data; }}
// Usageconst flareClient = new FlareFeedClient( 'https://example-app.klutch.sh', 'your_api_token_here');
// Add a feed(async () => { try { const feed = await flareClient.addFeed( 'https://news.ycombinator.com/rss', 'Technology' ); console.log('Feed added:', feed);
// Get unread items const items = await flareClient.getFeedItems(feed.id, 10, true); console.log('Unread items:', items);
// Mark item as read if (items.length > 0) { await flareClient.markAsRead(items[0].id); console.log('Item marked as read'); }
// Refresh feed await flareClient.refreshFeed(feed.id); console.log('Feed refreshed'); } catch (error) { console.error('Error:', error.message); }})();Go - Bookmark Sync
package main
import ( "bytes" "encoding/json" "fmt" "net/http" "time")
type FlareClient struct { BaseURL string APIToken string Client *http.Client}
type Bookmark struct { ID int `json:"id,omitempty"` URL string `json:"url"` Title string `json:"title"` Description string `json:"description"` Tags []string `json:"tags"` CreatedAt time.Time `json:"created_at,omitempty"`}
func NewFlareClient(baseURL, apiToken string) *FlareClient { return &FlareClient{ BaseURL: baseURL, APIToken: apiToken, Client: &http.Client{Timeout: 30 * time.Second}, }}
func (c *FlareClient) doRequest(method, path string, body interface{}) (*http.Response, error) { var reqBody []byte var err error
if body != nil { reqBody, err = json.Marshal(body) if err != nil { return nil, err } }
req, err := http.NewRequest(method, c.BaseURL+path, bytes.NewBuffer(reqBody)) if err != nil { return nil, err }
req.Header.Set("Authorization", "Bearer "+c.APIToken) req.Header.Set("Content-Type", "application/json")
return c.Client.Do(req)}
func (c *FlareClient) AddBookmark(bookmark Bookmark) (*Bookmark, error) { resp, err := c.doRequest("POST", "/api/bookmarks", bookmark) if err != nil { return nil, err } defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated { return nil, fmt.Errorf("failed to add bookmark: %s", resp.Status) }
var result Bookmark if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err }
return &result, nil}
func (c *FlareClient) GetBookmarks(tag string) ([]Bookmark, error) { path := "/api/bookmarks" if tag != "" { path += "?tag=" + tag }
resp, err := c.doRequest("GET", path, nil) if err != nil { return nil, err } defer resp.Body.Close()
var bookmarks []Bookmark if err := json.NewDecoder(resp.Body).Decode(&bookmarks); err != nil { return nil, err }
return bookmarks, nil}
func main() { client := NewFlareClient( "https://example-app.klutch.sh", "your_api_token_here", )
// Add a bookmark bookmark := Bookmark{ URL: "https://example.com/article", Title: "Great Article", Description: "Must read content", Tags: []string{"tech", "golang"}, }
created, err := client.AddBookmark(bookmark) if err != nil { fmt.Printf("Error adding bookmark: %v\n", err) return }
fmt.Printf("Bookmark created: %+v\n", created)
// Get all bookmarks with 'golang' tag bookmarks, err := client.GetBookmarks("golang") if err != nil { fmt.Printf("Error fetching bookmarks: %v\n", err) return }
fmt.Printf("Found %d bookmarks\n", len(bookmarks)) for _, b := range bookmarks { fmt.Printf("- %s: %s\n", b.Title, b.URL) }}Additional Resources
- Flare Official Repository
- Laravel Documentation
- Redis Documentation
- Klutch.sh Redis Deployment Guide
- Klutch.sh Persistent Volumes
- Klutch.sh Custom Domains
- Docker Resources
Summary
You’ve successfully deployed Flare on Klutch.sh! Your self-hosted bookmark manager and RSS feed reader is now running with:
- ✅ Automated Dockerfile-based deployment
- ✅ Persistent storage for bookmarks and feeds
- ✅ Optional Redis caching for performance
- ✅ Secure environment variable management
- ✅ Production-ready Nginx configuration
- ✅ Automated queue workers for feed updates
- ✅ Custom domain support with SSL
- ✅ Comprehensive backup and monitoring
Flare provides a beautiful, unified platform for managing your digital content. With deployment on Klutch.sh, you have complete control over your bookmarks and feeds while enjoying the benefits of managed infrastructure, automatic backups, and seamless scaling.
Start organizing your digital life with Flare on Klutch.sh today!