Install on a VPS (Control Panel)
Use this guide for a server you manage with a control panel such as CloudPanel, cPanel/WHM, Plesk, RunCloud or HestiaCP. Threadline's files live on the server's disk and PHP runs directly, with no Docker for the app itself. It is the shared-hosting install plus three things a VPS lets you add: Redis, Qdrant (the vector database) and a background queue worker.
Using aaPanel? Follow Install: VPS (aaPanel) instead. It walks through every aaPanel screen, including two settings that are easy to miss. No panel at all? Follow Install: VPS (Ubuntu, no panel), which shows every command.
This is the most hands-on way to install. If you are comfortable with Docker, Install: VPS (Docker) starts everything with one command. If you only have shared hosting, use Install: Shared Hosting.
Do you need this guide?
A VPS with a control panel can also run Threadline exactly like
shared hosting: follow
Install: Shared Hosting,
leave SERVER=shared as it is, and add the one cron
job. There is no Redis, no Qdrant and no worker to manage, and
the built-in updater works the same way. Choose this guide
instead when you expect heavy traffic or many customers and want
Redis and Qdrant. You tell Threadline which one with a single
line in .env:
Line in .env |
What runs |
|---|---|
SERVER=shared (the default) |
MySQL only. Cron runs the queue. No extra services. |
SERVER=vps |
Redis, Qdrant and a queue worker you keep running. This guide. |
Docker and Dokploy installs set this for you, so there is nothing to type there. How the files are stored (disk or container) is detected automatically.
What you need
- A Linux VPS, with at least 2 CPU cores and 2 GB of RAM (4 GB is more comfortable), and root or sudo access.
- A site in your panel for your domain, with HTTPS. The panel's own free certificate (Let's Encrypt) is fine.
- PHP 8.3 or newer with the extensions in System Requirements, and a MySQL or MariaDB database.
- Redis on the same server.
- Qdrant on the same server. The simplest way is Docker for this one service only (step 4).
- Supervisor (or systemd) to keep the queue worker running. Most panels include a supervisor screen.
Check PHP's disabled functions. Some panels
switch off PHP functions for safety, and Threadline fails
quietly without these: proc_open (every
scheduled task needs it), pcntl_signal and
pcntl_alarm (the queue worker stops at once
without them) and symlink (uploaded logos need
it). They must not appear in the disable_functions
list of the PHP version your site uses. The installer's first
page checks for them.
Steps
- Create the site and the database. In your panel, add the domain, turn on HTTPS, choose PHP 8.3 or newer for it, and create an empty database with its own user. Note the database name, user and password.
-
Point the web root at
public. Upload the Threadline ZIP you downloaded and unzip it into the site's folder, then set the site's document root (some panels call it run directory) to thepublicfolder inside it. The rest of the folder must not be reachable from the web. Upload the ZIP into the site user's own folder, not into/root, so that user can unzip it. Most panels have a "Laravel" template that sets up nginx for you. If you wrote the nginx site yourself, it needs both the Laravel rule and a PHP block (replace the socket path with your PHP-FPM one):root /var/www/threadline/public; index index.php; client_max_body_size 64M; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; } location ~ /\.(?!well-known).* { deny all; } -
Install Redis. On Ubuntu or Debian:
The second command should answersudo apt-get install -y redis-server redis-cli pingPONG. Redis listens on the local machine only by default. Leave it that way. -
Install Qdrant. If Docker is available
(
curl -fsSL https://get.docker.com | sh), run this once. It keeps Qdrant private to the server and starts it again after a reboot:
Check that it answers:docker run -d --name qdrant --restart unless-stopped \ -p 127.0.0.1:6333:6333 \ -v qdrant_data:/qdrant/storage \ qdrant/qdrant:v1.20.0
Qdrant also publishes ready-made Linux downloads if you would rather not use Docker. Whichever you use, Threadline only needs it reachable at one address. Do not open port 6333 to the internet.curl http://127.0.0.1:6333/readyz -
Fill in your settings file. The package
comes with a
.envfile in the site's folder. Open it and set these lines (change the ones that already exist; add the rest):SERVER=vps QUEUE_CONNECTION=redis CACHE_STORE=redis SESSION_DRIVER=redis REDIS_CLIENT=predis REDIS_HOST=127.0.0.1 REDIS_PORT=6379 QDRANT_URL=http://127.0.0.1:6333If you gave Redis a password, also setAll three of
QUEUE_CONNECTION,CACHE_STOREandSESSION_DRIVERmust sayredis. The example file sets them todatabase, and a value in.envwins over whatSERVER=vpswould choose.REDIS_PASSWORD. Do not fill in the database lines by hand; the installer asks for them. -
Give PHP the right to write. The user your
site's PHP runs as must own the files, or at least be able to
write to them. This also lets the built-in updater work later.
The user is shown in your panel (often
www,www-dataor the site's own name):sudo chown -R SITE_USER:SITE_USER /path/to/threadline sudo chmod -R ug+rwX storage bootstrap/cache -
Run the installer. Open your domain in a
browser. Threadline shows the same installer as on shared
hosting: a requirements check, your site URL, the database
details from step 1, and your Owner account. Follow
the steps in the shared-hosting guide
from there. It builds the database and loads the default
languages, navigation, footer and blank settings. It does not
create any sample accounts or plans: the only account is the
Owner you create.
When it has finished, make
Use an empty database. The installer drops any tables already in it.
.envreadable by the site's user only. It holds the database password and the app key:
The second command should start withchmod 600 /path/to/threadline/.env ls -l /path/to/threadline/.env-rw-------and nameSITE_USERas the owner. If another user owns it, run thechownfrom the previous step first, or the site stops loading. -
Start the queue worker. On a VPS Threadline
does not run jobs from cron, so a worker must always be
running. Without it no message is sent. Add a supervisor
program (in your panel's supervisor screen, or a file in
/etc/supervisor/conf.d/threadline-worker.conf):
Then load it:[program:threadline-worker] command=/path/to/php artisan queue:work redis --queue=default,mail,webhooks --sleep=3 --tries=3 --max-time=3600 directory=/path/to/threadline user=SITE_USER autostart=true autorestart=true stopasgroup=true redirect_stderr=true stdout_logfile=/path/to/threadline/storage/logs/worker.log stopwaitsecs=3600
The status should saysudo supervisorctl reread sudo supervisorctl update sudo supervisorctl statusRUNNING./path/to/phpis the full path of the PHP your site uses (runwhich php, or look for it in your panel). A server can have several PHP versions, and a barephpmay be another one. The worker must run as the same user as the website, never as root. -
Add the cron job. The scheduler handles
reminders, campaigns and clean-up. Add this to the cron of the
same user (your panel's cron screen, or
crontab -e -u SITE_USER):
Use the same full PHP path as for the worker. If your panel's cron screen offers a user, choose the website's user, not root. See Cron Setup.* * * * * cd /path/to/threadline && /path/to/php artisan schedule:run >> /dev/null 2>&1
Optional: send public pages as finished HTML
Search engines read your public pages (home, pricing, about and
the others) best when the server sends them already built. With
SERVER=vps Threadline does that as soon as a small
Node.js program runs next to it. Without it, pages are built in
the visitor's browser as before, and nothing else changes.
Screens behind the sign-in are always built in the browser.
-
Install Node.js 18 or newer, from your panel's Node.js screen
or with
sudo apt-get install -y nodejs. Find its full path withwhich node. -
Add a second supervisor program, the same way as the worker:
Load it with the same three[program:threadline-ssr] command=/path/to/node /path/to/threadline/bootstrap/ssr/app.js directory=/path/to/threadline user=SITE_USER autostart=true autorestart=true redirect_stderr=true stdout_logfile=/path/to/threadline/storage/logs/ssr.logsupervisorctlcommands. It must sayRUNNING. -
Open your home page in a private window and view the page
source: the page's text is in it, not only an empty
<div id="app">.
It uses about 100 MB of memory. An update restarts it on the new version by itself.
Starting on shared mode and moving later
You can install in shared mode first and move to
SERVER=vps when you outgrow it. Install Redis and
Qdrant (steps 3 and 4), then open
Maintenance → Server, check readiness, run
the reindex and press Switch. That button only
changes the SERVER line. Afterwards, also set
QUEUE_CONNECTION, CACHE_STORE and
SESSION_DRIVER to redis (step 6) and
start the queue worker (step 9). Until the queue is on Redis,
Threadline keeps running its cron-driven worker, so nothing is
left unprocessed in between.
After you install
- Open Cron & Health and Queue Monitor. Both should show recent activity within a couple of minutes.
- Connect an AI provider. See AI Provider Setup.
- Set up email in Mail & Email Templates. Without it, password-reset and invitation emails do not arrive.
Updating
Because the files are on disk, you can update from the browser
(Maintenance → App Update, upload the new
ZIP) or over SSH with
php artisan threadline:update. Both back up the
database, replace the files, apply database changes and tell the
queue worker to restart; supervisor brings it back on its own.
Full steps are in
Updating Threadline.
If something goes wrong
| What you see | Likely cause and fix |
|---|---|
| The installer shows, but styling is missing or you get a 404 on every page except the home page |
The document root is not the public folder, or
the nginx try_files rule is missing (step 2).
|
| A "permission denied" or "unable to write" error |
The PHP user cannot write to storage or
bootstrap/cache (step 7).
|
| The cron job runs, but scheduled tasks never start |
proc_open is in PHP's
disable_functions list. Remove it (see the
warning above the steps).
|
An error mentioning open_basedir restriction in effect in storage/logs |
Your panel limits PHP to the site's folder. Threadline works with that restriction. If the message names a folder Threadline needs, add it to the site's allowed paths in your panel, or ask us for help with the exact message. |
| An uploaded logo does not show |
The storage link is missing. Run
php artisan storage:link as the website's user
in the Threadline folder. It needs symlink
to be enabled in PHP.
|
| Pages load but nothing is ever sent |
The queue worker is not running (step 9), or
QUEUE_CONNECTION is not redis
(step 6).
|
| "Connection refused" mentioning Redis or port 6379 |
Redis is not running. Check
redis-cli ping (step 3).
|
| Knowledge-base answers are empty after you add documents |
Qdrant is not reachable at QDRANT_URL. Check
curl http://127.0.0.1:6333/readyz (step 4).
|
More in Troubleshooting & FAQ.