Skip to content

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.md

Sample 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 dependencies
RUN apk add --no-cache \
nginx \
supervisor \
nodejs \
npm \
git \
curl \
sqlite \
sqlite-dev \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
zip \
unzip
# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo \
pdo_mysql \
pdo_sqlite \
gd \
opcache
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Clone Flare repository
RUN git clone https://github.com/soulteary/flare.git . \
&& composer install --no-dev --optimize-autoloader \
&& npm install \
&& npm run build
# Create necessary directories
RUN 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 permissions
RUN 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 configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Copy supervisor configuration
RUN 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 script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Expose port
EXPOSE 8000
# Start supervisor
ENTRYPOINT ["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 versions
RUN 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 extensions
RUN 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 production
RUN { \
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 Composer
COPY --from=composer:2.6 /usr/bin/composer /usr/bin/composer
# Set working directory
WORKDIR /var/www/html
# Clone specific version of Flare
ARG FLARE_VERSION=main
RUN 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 structure
RUN 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 permissions
RUN 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 configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Copy supervisor configuration
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Expose port
EXPOSE 8000
# Start supervisor
ENTRYPOINT ["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/sh
set -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 set
if [ -z "$APP_KEY" ] || [ "$APP_KEY" = "base64:CHANGE_THIS_TO_RANDOM_STRING" ]; then
echo "Generating application key..."
php artisan key:generate --force
fi
# Run database migrations
echo "Running database migrations..."
php artisan migrate --force
# Create storage symlink
echo "Creating storage symlink..."
php artisan storage:link || true
# Clear and cache configuration
echo "Optimizing application..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Set proper permissions
echo "Setting permissions..."
chown -R www-data:www-data /var/www/html/storage
chown -R www-data:www-data /var/www/html/bootstrap/cache
echo "Flare initialization complete!"
# Execute the main command
exec "$@"

Supervisor Configuration

Create supervisord.conf:

[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:nginx]
command=nginx -g 'daemon off;'
autostart=true
autorestart=true
priority=10
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:php-fpm]
command=php-fpm -F
autostart=true
autorestart=true
priority=5
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:queue-worker]
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
stopwaitsecs=3600

Environment Variables

Required Environment Variables

Terminal window
# Application
APP_NAME=Flare
APP_ENV=production
APP_KEY=base64:GENERATE_WITH_ARTISAN_KEY_GENERATE
APP_DEBUG=false
APP_URL=https://example-app.klutch.sh
# Database (SQLite - Default)
DB_CONNECTION=sqlite
DB_DATABASE=/var/www/html/storage/database.sqlite
# Or MySQL Database
DB_CONNECTION=mysql
DB_HOST=your-mysql-app.klutch.sh
DB_PORT=8000
DB_DATABASE=flare
DB_USERNAME=flare_user
DB_PASSWORD=your_secure_database_password
# Redis (Optional but Recommended)
REDIS_HOST=your-redis-app.klutch.sh
REDIS_PASSWORD=your_redis_password
REDIS_PORT=8000
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
# Mail Configuration (Optional)
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="${APP_NAME}"

Optional Configuration

Terminal window
# Feed Fetching
FLARE_FEED_FETCH_INTERVAL=30
FLARE_MAX_FEEDS_PER_USER=100
FLARE_FEED_TIMEOUT=30
# Bookmarks
FLARE_MAX_BOOKMARKS_PER_USER=1000
FLARE_BOOKMARK_PREVIEW_ENABLED=true
# File Storage
FILESYSTEM_DISK=local
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
# Logging
LOG_CHANNEL=stack
LOG_LEVEL=error
# Security
SESSION_LIFETIME=120
SESSION_SECURE_COOKIE=true

Deploying to Klutch.sh

Step 1: Prepare Your Repository

    1. Create a new GitHub repository for your Flare deployment

    2. Add all the files mentioned above:

      • Dockerfile
      • nginx.conf
      • docker-entrypoint.sh
      • supervisord.conf
      • .env.example (for reference)
      • README.md (optional documentation)
    3. Commit and push to GitHub:

    Terminal window
    git init
    git add .
    git commit -m "Initial Flare deployment setup"
    git branch -M main
    git remote add origin https://github.com/yourusername/flare-deployment.git
    git push -u origin main

For optimal performance, deploy Redis separately. See the Redis deployment guide for detailed instructions.

Quick Redis setup:

    1. Create a new app in Klutch.sh for Redis
    2. Use the official Redis Docker image
    3. Set TCP traffic mode
    4. Configure internal port 6379, external port 8000
    5. Add a strong password via REDIS_PASSWORD environment variable
    6. Attach a persistent volume at /data
    7. Note the Redis connection details for Flare configuration

Step 3: Create Flare Application

    1. Log in to your Klutch.sh dashboard

    2. Click “Create New App”

    3. Select “Import from GitHub”

    4. Choose your Flare deployment repository

    5. Configure deployment settings:

      • App Name: flare-bookmarks (or your preferred name)
      • Branch: main
      • Root Directory: / (if Dockerfile is in root)

Step 4: Configure Application Settings

    1. Set Traffic Type:

      • Select HTTP traffic (Flare is a web application)
      • Set Internal Port to 8000
    2. Add Environment Variables:

      Navigate to the “Environment Variables” section and add:

      Essential Variables:

      APP_NAME=Flare
      APP_ENV=production
      APP_DEBUG=false
      APP_URL=https://your-app-name.klutch.sh
      DB_CONNECTION=sqlite
      DB_DATABASE=/var/www/html/storage/database.sqlite

      Redis Configuration (if using):

      REDIS_HOST=your-redis-app.klutch.sh
      REDIS_PORT=8000
      REDIS_PASSWORD=your_redis_password
      CACHE_DRIVER=redis
      SESSION_DRIVER=redis
      QUEUE_CONNECTION=redis

      Note: The APP_KEY will be generated automatically by the entrypoint script on first run.

Step 5: Attach Persistent Volume

Flare requires persistent storage for bookmarks, feeds, and database:

    1. Navigate to “Volumes” in your app settings

    2. Click “Attach Volume”

    3. Configure volume:

      • Mount Path: /var/www/html/storage
      • Size: Start with 5GB (adjust based on content volume)
    4. Save the volume configuration

Step 6: Deploy the Application

    1. Review all settings

    2. Click “Deploy”

    3. Klutch.sh will:

      • Clone your repository
      • Detect the Dockerfile
      • Build the container image
      • Deploy to production
      • Assign a public URL
    4. Monitor the build logs for any errors

    5. Wait for deployment to complete (typically 5-10 minutes for first build)


Initial Setup and Configuration

Accessing Flare

Once deployed, access your Flare instance:

  1. Navigate to your app URL: https://your-app-name.klutch.sh
  2. Complete the initial setup wizard:
    • Create your admin account
    • Configure basic settings
    • Set your timezone and preferences

Adding Your First Bookmarks

    1. Click “Add Bookmark” in the dashboard

    2. Enter bookmark details:

      • URL (required)
      • Title (auto-fetched or manual)
      • Description
      • Tags for organization
      • Category
    3. Flare will automatically fetch:

      • Page title and description
      • Favicon
      • Screenshot (if enabled)
      • Metadata
    4. Click “Save” to add the bookmark

Setting Up RSS Feeds

    1. Navigate to the “Feeds” section

    2. Click “Add Feed”

    3. Enter feed URL (RSS or Atom format)

    4. Configure feed settings:

      • Update frequency
      • Category/folder
      • Read/unread marking
    5. Flare will automatically:

      • Fetch feed content
      • Parse articles
      • Schedule periodic updates

Organizing Content

Create an organizational structure:

    1. Create Tags: Add relevant tags to bookmarks
    2. Set Up Categories: Organize by topic or project
    3. Create Collections: Group related bookmarks together
    4. Use Folders: Hierarchical organization for feeds
    5. Search Filters: Save common search queries
    6. Custom Views: Configure dashboard layouts

Browser Extension Setup

Flare supports browser extensions for quick bookmarking:

Chrome/Edge Extension

    1. Visit your Flare instance settings

    2. Navigate to “Integrations”“Browser Extension”

    3. Copy the API key or authentication token

    4. Install the Flare browser extension from your instance

    5. Configure extension with your Flare URL and credentials

    6. Start bookmarking with one click!

Bookmarklet Alternative

If no extension is available:

  1. Go to “Settings”“Bookmarklet”
  2. Drag the bookmarklet to your bookmarks bar
  3. Click it on any page to quickly save

Production Best Practices

Security Hardening

    1. Strong Application Key:

      Terminal window
      php artisan key:generate
    2. Secure Session Configuration:

      Terminal window
      SESSION_SECURE_COOKIE=true
      SESSION_HTTP_ONLY=true
      SESSION_SAME_SITE=lax
    3. Database Security:

      • Use strong database passwords
      • Limit database user permissions
      • Enable SSL for database connections
    4. Rate Limiting:

      • Configure API rate limits
      • Enable login throttling
      • Implement CAPTCHA for public instances

Performance Optimization

    1. Enable Redis Caching:

      • Cache configuration
      • Session management
      • Queue processing
    2. Configure OPcache:

      Terminal window
      opcache.enable=1
      opcache.memory_consumption=128
      opcache.max_accelerated_files=4000
    3. Optimize Database:

      • Regular VACUUM (SQLite)
      • Index optimization
      • Query caching
    4. Asset Optimization:

      • Minify CSS/JS
      • Enable Gzip compression
      • Use CDN for static assets

Backup Strategy

    1. Volume Backups:

      • Regular automated backups via Klutch.sh
      • Export bookmarks periodically
      • Download database snapshots
    2. Export Options:

      Terminal window
      # HTML export
      https://your-app.klutch.sh/export/html
      # JSON export
      https://your-app.klutch.sh/export/json
      # RSS export
      https://your-app.klutch.sh/export/rss
    3. Disaster Recovery:

      • Document environment variables
      • Keep Dockerfile in version control
      • Test restore procedures

Monitoring and Maintenance

    1. Application Monitoring:

      • Check CPU and memory usage in Klutch.sh dashboard
      • Monitor response times
      • Track error rates
    2. Log Management:

      Terminal window
      # View Laravel logs
      tail -f storage/logs/laravel.log
      # View Nginx logs
      tail -f /var/log/nginx/access.log
      tail -f /var/log/nginx/error.log
    3. Regular Updates:

      • Update Flare version in Dockerfile
      • Run database migrations
      • Update dependencies
      • Security patches
    4. Database Maintenance:

      Terminal window
      # Optimize database
      php artisan optimize:clear
      php artisan config:cache
      php artisan route:cache

Troubleshooting

Application Won’t Start

Symptoms: Container crashes or fails to start

Solutions:

    1. Check Klutch.sh build logs for errors

    2. Verify all required environment variables are set:

      Terminal window
      APP_KEY, APP_URL, DB_CONNECTION
    3. Ensure volume is properly attached:

      Terminal window
      Mount path: /var/www/html/storage
    4. Check file permissions:

      Terminal window
      chmod -R 775 storage bootstrap/cache

Database Connection Errors

Symptoms: “Connection refused” or “Access denied”

Solutions:

    1. Verify database credentials in environment variables

    2. For MySQL, check connection details:

      • Host: your-mysql-app.klutch.sh
      • Port: 8000 (external port for TCP traffic)
      • Database exists and user has permissions
    3. For SQLite, ensure volume is mounted correctly

    4. Test database connection:

      Terminal window
      php artisan migrate:status

Redis Connection Issues

Symptoms: Caching failures or session problems

Solutions:

    1. Verify Redis is running and accessible

    2. Check Redis configuration:

      Terminal window
      REDIS_HOST=your-redis-app.klutch.sh
      REDIS_PORT=8000
      REDIS_PASSWORD=correct_password
    3. Test Redis connection:

      Terminal window
      redis-cli -h your-redis-app.klutch.sh -p 8000 -a password PING
    4. Fall back to file-based cache if needed:

      Terminal window
      CACHE_DRIVER=file
      SESSION_DRIVER=file

Feed Updates Not Working

Symptoms: RSS feeds not updating with new content

Solutions:

    1. Check queue worker is running:

      Terminal window
      # Verify in supervisor logs
      tail -f storage/logs/worker.log
    2. Manually trigger feed update:

      Terminal window
      php artisan feeds:fetch
    3. Verify cron/scheduler is configured:

      Terminal window
      php artisan schedule:run
    4. 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:

    1. Enable Redis caching:

      Terminal window
      CACHE_DRIVER=redis
      SESSION_DRIVER=redis
    2. Optimize application:

      Terminal window
      php artisan config:cache
      php artisan route:cache
      php artisan view:cache
    3. Increase resources in Klutch.sh dashboard

    4. 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:

    1. Enable debug mode temporarily:

      Terminal window
      APP_DEBUG=true
    2. Check application logs:

      Terminal window
      storage/logs/laravel.log
    3. Verify permissions:

      Terminal window
      chown -R www-data:www-data storage bootstrap/cache
    4. Clear caches:

      Terminal window
      php artisan cache:clear
      php artisan config:clear
      php artisan view:clear

Custom Domain Configuration

To use a custom domain with Flare:

    1. In Klutch.sh dashboard, navigate to “Domains”

    2. Click “Add Custom Domain”

    3. Enter your domain (e.g., bookmarks.yourdomain.com)

    4. Follow DNS configuration instructions:

      • Add CNAME record pointing to your Klutch.sh app
      • Or add A record with provided IP address
    5. Update environment variable:

      Terminal window
      APP_URL=https://bookmarks.yourdomain.com
    6. Redeploy the application

    7. Wait for DNS propagation (typically 5-30 minutes)

    8. SSL certificate will be automatically provisioned


Advanced Configuration

S3 Storage Integration

Store favicons and screenshots in S3:

Terminal window
FILESYSTEM_DISK=s3
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your-flare-bucket
AWS_USE_PATH_STYLE_ENDPOINT=false

Email Notifications

Configure SMTP for notifications:

Terminal window
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="Flare Bookmarks"

Multi-User Configuration

Enable user registration:

Terminal window
FLARE_ALLOW_REGISTRATION=true
FLARE_REQUIRE_EMAIL_VERIFICATION=true
FLARE_MAX_USERS=100

API Access

Configure API for integrations:

Terminal window
FLARE_API_ENABLED=true
FLARE_API_RATE_LIMIT=60
FLARE_API_AUTH_TYPE=token

Integration Examples

Python - Bookmark Management

import requests
from 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
# Usage
client = FlareClient(
base_url='https://example-app.klutch.sh',
api_token='your_api_token_here'
)
# Add bookmark
bookmark = client.add_bookmark(
url='https://example.com/article',
title='Interesting Article',
description='A great read about technology',
tags=['tech', 'programming']
)
# Search bookmarks
results = client.search_bookmarks('kubernetes')
# Get bookmarks by tag
tech_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;
}
}
// Usage
const 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


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!