> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trypost.it/llms.txt
> Use this file to discover all available pages before exploring further.

# Production Setup

> Deploy TryPost to a production environment

# Production Setup

This guide covers deploying TryPost to a production environment.

## Environment Configuration

Set these values in your `.env` for production:

```env theme={null}
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com

SELF_HOSTED=true
```

## Optimizations

Run these commands after deployment:

```bash theme={null}
# Cache configuration
php artisan config:cache

# Cache routes
php artisan route:cache

# Cache views
php artisan view:cache

# Optimize autoloader
composer install --optimize-autoloader --no-dev
```

## Queue Worker

TryPost uses queues for critical background processing:

* **Publishing posts** to social platforms at scheduled times
* **Sending notifications** (email and in-app)
* **Verifying social account connections**
* **Processing analytics events**

Without a running queue worker, scheduled posts will not be published. Use Supervisor to keep the queue worker running.

### Install Supervisor

```bash theme={null}
# Ubuntu/Debian
sudo apt install supervisor

# CentOS/RHEL
sudo yum install supervisor
```

### Configure Supervisor

Create `/etc/supervisor/conf.d/trypost-worker.conf`:

```ini theme={null}
[program:trypost-horizon]
process_name=%(program_name)s
command=php /var/www/trypost/artisan horizon
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/trypost/storage/logs/horizon.log
stopwaitsecs=3600
```

Then start it:

```bash theme={null}
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start trypost-horizon
```

## Nginx Configuration

Example Nginx configuration:

```nginx theme={null}
server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your-domain.com;

    root /var/www/trypost/public;
    index index.php;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    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$ {
        # Replace with the FPM socket for the PHP version you installed (e.g. php8.2-fpm.sock, php8.3-fpm.sock, php8.4-fpm.sock).
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }

    client_max_body_size 2G;
}
```

## SSL Certificate

Use Let's Encrypt for free SSL:

```bash theme={null}
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
```

## Scheduled Tasks (Cron)

TryPost uses Laravel's task scheduler for several recurring jobs. The scheduler **must** run every minute or scheduled posts won't publish, expiring tokens won't refresh, and stuck posts won't recover.

| Command                          | Schedule         | Purpose                                                                     |
| -------------------------------- | ---------------- | --------------------------------------------------------------------------- |
| `posts:process-scheduled`        | every minute     | Dispatches `PublishPost` jobs for posts that are due                        |
| `social:check-connections`       | daily            | Verifies every connected social account still has a valid token             |
| `social:refresh-expiring-tokens` | hourly           | Refreshes OAuth tokens that are about to expire (proactive refresh)         |
| `social:recover-stuck-posts`     | every 30 minutes | Detects posts stuck in `publishing` and either retries or marks them failed |

Add the Laravel scheduler to cron:

```bash theme={null}
crontab -e
```

Add this line:

```
* * * * * cd /var/www/trypost && php artisan schedule:run >> /dev/null 2>&1
```

<Warning>
  This is required. Without the cron job, scheduled posts will not be published automatically, and social tokens will expire silently.
</Warning>

## WebSocket Server (Reverb)

TryPost uses [Laravel Reverb](https://laravel.com/docs/reverb) for real-time updates in the dashboard (live post status changes, notifications). Add a Supervisor config to keep it running:

Create `/etc/supervisor/conf.d/trypost-reverb.conf`:

```ini theme={null}
[program:trypost-reverb]
process_name=%(program_name)s
command=php /var/www/trypost/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/trypost/storage/logs/reverb.log
```

Then reload Supervisor:

```bash theme={null}
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start trypost-reverb
```

<Note>
  In production, proxy WebSocket connections through Nginx with SSL. Add this to your Nginx config:

  ```nginx theme={null}
  location /app {
      proxy_pass http://127.0.0.1:8080;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
  }
  ```
</Note>

## File Permissions

Set correct permissions:

```bash theme={null}
sudo chown -R www-data:www-data /var/www/trypost
sudo chmod -R 755 /var/www/trypost
sudo chmod -R 775 /var/www/trypost/storage
sudo chmod -R 775 /var/www/trypost/bootstrap/cache
```

## Checklist

Make sure all of these are running in production:

| Service       | Command                           | Purpose                                           |
| ------------- | --------------------------------- | ------------------------------------------------- |
| **Horizon**   | `php artisan horizon`             | Processes queues (post publishing, notifications) |
| **Reverb**    | `php artisan reverb:start`        | Real-time WebSocket updates                       |
| **Scheduler** | `php artisan schedule:run` (cron) | Dispatches scheduled posts                        |

<Warning>
  If any of these services are not running, TryPost will not function correctly. Scheduled posts won't publish, notifications won't send, and the dashboard won't update in real time.
</Warning>

## Monitoring

Consider setting up monitoring for:

* Server health (CPU, memory, disk)
* Application errors (Laravel logs in `storage/logs/`)
* Queue status (Horizon dashboard at `/horizon`)
* WebSocket connections (Reverb logs in `storage/logs/reverb.log`)

## Backups

Regularly backup:

* Database
* `.env` file
* Uploaded media (if using local storage)
