Edit file File name : SERVER_STORAGE_SETUP.md Content :# Server Storage Setup Guide Complete guide to setting up static storage access for blog images on your production server. ## Quick Start ### On Linux/Mac (SSH) Run this command on your server to create the storage symlink: ```bash cd /path/to/your/laravel/app php artisan storage:link ``` That's it! Your images will now be accessible at `https://yourdomain.com/storage/blog-posts/filename.jpg` --- ## Server-Specific Instructions ### 1. **Linux/Mac Servers (Recommended)** #### Via SSH/Terminal: ```bash # SSH into your server ssh user@your-server.com # Navigate to your Laravel app directory cd /var/www/html/smart_link # or wherever your Laravel app is installed # Create the storage symlink php artisan storage:link # Verify it was created ls -la public/ | grep storage ``` **Output should show:** ``` lrwxrwxrwx 1 user user 46 Jan 26 10:30 storage -> /var/www/html/smart_link/storage/app/public ``` #### Via Hosting Control Panel (cPanel/Plesk): 1. **Log in to cPanel/Plesk** 2. Go to **File Manager** 3. Navigate to your Laravel app's root directory 4. Open **Terminal** (or use SSH from control panel) 5. Run: ```bash php artisan storage:link ``` #### Troubleshooting Linux: If you get permission errors: ```bash # Fix permissions sudo chown -R www-data:www-data /var/www/html/smart_link sudo chmod -R 755 /var/www/html/smart_link sudo chmod -R 775 /var/www/html/smart_link/storage sudo chmod -R 775 /var/www/html/smart_link/public # Then create the symlink php artisan storage:link ``` --- ### 2. **Windows Server (IIS)** #### Option A: Using PowerShell (Recommended) 1. **Open PowerShell as Administrator** 2. Navigate to your Laravel app: ```powershell cd "C:\inetpub\wwwroot\smart_link" ``` 3. Create the symlink: ```powershell php artisan storage:link ``` #### Option B: Manual Symlink Creation If `artisan storage:link` doesn't work: 1. **Open PowerShell as Administrator** 2. Run: ```powershell New-Item -ItemType SymbolicLink -Path "C:\inetpub\wwwroot\smart_link\public\storage" -Target "C:\inetpub\wwwroot\smart_link\storage\app\public" ``` #### Option C: Using Command Prompt 1. **Open Command Prompt as Administrator** 2. Run: ```cmd mklink /D "C:\inetpub\wwwroot\smart_link\public\storage" "C:\inetpub\wwwroot\smart_link\storage\app\public" ``` #### IIS Configuration Make sure IIS has proper permissions: 1. Open **Internet Information Services (IIS) Manager** 2. Find your website 3. Right-click → **Edit Permissions** 4. Go to **Security** tab 5. Ensure **IUSR** and **IIS_IUSRS** have **Read** and **Read & Execute** permissions 6. Click **Apply** --- ### 3. **Shared Hosting (GoDaddy, NameCheap, Bluehost, etc.)** #### Via File Manager: **NOT RECOMMENDED** - Most shared hosting doesn't support symlinks via File Manager #### Via SSH Terminal: 1. Log in to your hosting control panel 2. Go to **File Manager** or **SSH Terminal** 3. Navigate to your app: ```bash cd ~/public_html/smart_link # or cd ~/domains/yourdomain.com ``` 4. Run: ```bash php artisan storage:link ``` #### If Symlinks Don't Work (Fallback): Some shared hosts disable symlinks. Use this fallback: 1. Create a **symbolic link manually** via FTP: - Create directory: `/public_html/storage` - Upload files from `/storage/app/public` to `/public_html/storage` 2. **OR** update your `.htaccess` to redirect: ```apache RewriteRule ^storage/(.*)$ storage/app/public/$1 [L] ``` 3. **OR** use this PHP redirect in `public/storage/index.php`: ```php <?php $file = __DIR__ . '/../storage/app/public/' . $_REQUEST['file'] ?? ''; if (file_exists($file)) { header('Content-Type: ' . mime_content_type($file)); readfile($file); } else { header('HTTP/1.0 404 Not Found'); echo 'File not found'; } ``` --- ### 4. **Docker Deployment** #### In Your Dockerfile: ```dockerfile FROM php:8.2-fpm # ... other setup ... # Create storage symlink RUN php artisan storage:link EXPOSE 9000 CMD ["php-fpm"] ``` #### In Docker Compose: ```yaml version: '3.8' services: app: build: . volumes: - ./:/var/www/html - ./storage/app/public:/var/www/html/public/storage environment: - APP_ENV=production nginx: image: nginx:latest ports: - "80:80" volumes: - ./public:/var/www/html/public - ./storage/app/public:/var/www/html/public/storage ``` #### After Deploying: ```bash # SSH into the container docker exec -it container_name bash # Create symlink php artisan storage:link ``` --- ### 5. **Heroku** **Heroku has ephemeral storage**, so symlinks won't persist between deployments. #### Solution A: Use Cloud Storage (Recommended) 1. Set up AWS S3, Google Cloud Storage, or DigitalOcean Spaces 2. Update `.env`: ``` FILESYSTEM_DRIVER=s3 AWS_ACCESS_KEY_ID=your_key AWS_SECRET_ACCESS_KEY=your_secret AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET=your-bucket ``` #### Solution B: Create Symlink in Procfile 1. Create/edit `Procfile`: ``` release: php artisan storage:link web: vendor/bin/heroku-php-apache2 public/ ``` 2. Deploy: ```bash git push heroku main ``` --- ### 6. **DigitalOcean / Linode / Vultr** #### Via SSH: ```bash # SSH into your server ssh root@your-server-ip # Navigate to app cd /var/www/smart_link # Create symlink php artisan storage:link # Fix permissions chmod -R 775 storage/ chmod -R 775 public/storage chown -R www-data:www-data storage/ chown -R www-data:www-data public/storage ``` #### Using DigitalOcean App Platform: 1. Add to your `app.yaml`: ```yaml services: - name: laravel github: repo: your-repo build_command: composer install && php artisan migrate && php artisan storage:link ``` --- ### 7. **AWS EC2** ```bash # SSH into instance ssh -i your-key.pem ubuntu@your-instance-ip # Navigate to app cd /var/www/smart_link # Create symlink php artisan storage:link # Fix permissions sudo chown -R ubuntu:ubuntu /var/www/smart_link sudo chmod -R 775 /var/www/smart_link/storage ``` --- ### 8. **Laravel Forge** Forge handles symlinks automatically! Just deploy your app normally: 1. Log in to **Laravel Forge** 2. Create a new server (or use existing) 3. Create a new site 4. In **Quick Deploy** section, paste your GitHub repo URL 5. Forge automatically runs: - `composer install` - `php artisan migrate` - `php artisan storage:link` If for some reason it doesn't: 1. Go to your site 2. Click **SSH** 3. Run: ```bash php artisan storage:link ``` --- ### 9. **Laravel Sail (Local Development)** For Docker-based local development: ```bash # Build containers ./vendor/bin/sail up -d # Run storage:link inside container ./vendor/bin/sail artisan storage:link # Or access the container directly docker exec -it sail-app php artisan storage:link ``` --- ## Verify Storage Symlink ### Check if Symlink Exists **On Linux/Mac:** ```bash ls -la public/ | grep storage # Should show: storage -> /path/to/storage/app/public ``` **On Windows (PowerShell):** ```powershell Get-Item "C:\inetpub\wwwroot\smart_link\public\storage" | Select-Object -Property FullName, Target ``` ### Test File Access 1. Upload a test image via your dashboard 2. Check the response to get the filename 3. Visit the URL directly: ``` https://yourdomain.com/storage/blog-posts/test-filename.jpg ``` 4. Should show the image, not redirect to home --- ## Troubleshooting ### Symlink Not Working #### On Linux: ```bash # Check if symlink was created ls -la public/ # If not, manually create it ln -s /var/www/html/smart_link/storage/app/public /var/www/html/smart_link/public/storage # Verify ls -la public/storage ``` #### On Windows: ```powershell # Check if symlink exists dir C:\inetpub\wwwroot\smart_link\public | findstr storage # If not, create it manually New-Item -ItemType SymbolicLink -Path "C:\inetpub\wwwroot\smart_link\public\storage" -Target "C:\inetpub\wwwroot\smart_link\storage\app\public" -Force ``` ### Images Still Redirecting to Home **Cause:** Web server isn't serving the file directly **Solution:** 1. **Check file permissions:** ```bash chmod 644 storage/app/public/blog-posts/* chmod 755 storage/app/public/blog-posts/ ``` 2. **Check web server configuration:** - Make sure `public/storage` is being served as a static directory - Not being rewritten by any routes 3. **Check `.htaccess`:** ```apache # In public/.htaccess <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php [L] </IfModule> ``` The `!-f` and `!-d` rules should prevent rewriting actual files/directories. 4. **Check nginx configuration** (if using nginx): ```nginx location ~ /storage/(.*)$ { try_files $uri $uri/ =404; } ``` ### 403 Forbidden Error **Cause:** Web server doesn't have read permissions **Solution:** ```bash # Fix ownership sudo chown -R www-data:www-data /var/www/html/smart_link/storage sudo chown -R www-data:www-data /var/www/html/smart_link/public/storage # Fix permissions sudo chmod -R 755 /var/www/html/smart_link/storage sudo chmod -R 755 /var/www/html/smart_link/public/storage ``` ### 404 Not Found Error **Cause:** Storage directory doesn't exist or symlink is broken **Solution:** ```bash # Check if storage/app/public exists ls -la storage/app/public/ # Check if symlink is valid readlink public/storage # If broken, recreate php artisan storage:link ``` --- ## After Setup ### Verify in Your App 1. **Create a test blog post with an image** 2. **Check the database** for the featured_image filename 3. **Test the API response**: ```bash curl https://yourdomain.com/api/v1/blogs/recent ``` 4. **Visit the image URL directly**: ``` https://yourdomain.com/storage/blog-posts/filename.jpg ``` ### Monitor Storage Growth ```bash # Check storage usage du -sh storage/app/public/ # List all blog post images ls -lh storage/app/public/blog-posts/ # Count total files find storage/app/public/blog-posts -type f | wc -l ``` --- ## Security Considerations ### Restrict File Types Update `app/Livewire/Apps/Tabs/Blog.php`: ```php 'featured_image' => 'nullable|image|max:2048|mimes:jpeg,png,webp,gif', ``` ### Prevent Direct Access to Sensitive Files Only allow serving from specific subdirectories. Add to `.htaccess`: ```apache <FilesMatch "\.(php|sh|pl|py)$"> Order Deny,Allow Deny from all </FilesMatch> ``` ### Enable CORS for CDN If using a CDN or external domain: ```php // In your route or middleware header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, HEAD, OPTIONS'); ``` --- ## Production Checklist - [ ] Create storage symlink: `php artisan storage:link` - [ ] Verify symlink exists: `ls -la public/storage` - [ ] Test image upload via dashboard - [ ] Test API response contains correct image URL - [ ] Test direct image access via browser - [ ] Check file permissions (644 for files, 755 for directories) - [ ] Check web server is serving static files correctly - [ ] Set up automated backups for `storage/app/public/` - [ ] Monitor storage disk usage - [ ] Set up image cleanup policy for deleted posts Save