Deployment: Shared Hosting and VPS
Shared Hosting (No CLI)
This is the primary scenario the framework was designed for: upload files via FTP/File Manager, no SSH, no CLI commands.
Checklist
- Upload. Upload the entire project (including
vendor/— built in advance on your own machine withcomposer install --no-dev --optimize-autoloader) to the host. Most shared hosts can't run Composer, sovendor/must already be prepared. - Set the Document Root to
public/(or, if that's not possible, move the contents ofpublic/to the domain root and adjust therequirepaths inwebhook.phpaccordingly). - Environment variables. If your hosting panel doesn't support
setting env variables, you can temporarily put the real token
value directly in
config/aicrion.yaml(only after confirming this file is outside public reach — theconfig/folder must never live insidepublic/). - Make
var/writable. Both SQLite (var/data.sqlite) and the filesystem cache (var/cache/) need write access:
bash
chmod -R 775 var/
- Register the webhook (once, from your own browser, no server CLI required):
https://api.telegram.org/bot<TOKEN>/setWebhook?url=https://your-domain.com/webhook.php
- Test it. Send
/startto the bot. The very first request both discovers plugins and builds the database schema (automatic migration) — no separate install step is needed.
Why SQLite Is the Default Choice
Most shared hosts restrict provisioning a separate MySQL service or
Redis access. SQLite is just a plain file in var/ — no separate
process, no network port, no permissions beyond writing a file. If
your host does offer MySQL, you can still switch to it per
Configuration.
VPS / Docker
On environments where you have full control, it's recommended to use:
- Real Redis for shared cache/back-stack across multiple workers.
- Polling mode with a process supervisor (systemd/supervisord) if you'd rather not have a public HTTPS domain, or Webhook behind Nginx/Caddy with TLS for better performance under high load.
opcacheenabled for PHP-FPM, sinceEntityManagerFactoryreads Doctrine metadata from attributes on every boot; opcache removes the cost of parsing PHP files (not the metadata reflection itself — for that, consider a dedicated Doctrine metadata cache).
Sample systemd Unit for Polling Mode
[Unit]
Description=Aicrion Tandroid Bot (polling)
After=network.target
[Service]
ExecStart=/usr/bin/php /var/www/my-bot/bin/poll.php
Restart=always
RestartSec=3
User=www-data
WorkingDirectory=/var/www/my-bot
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now aicrion-bot.service
Sample Nginx Config for Webhook Mode
server {
listen 443 ssl http2;
server_name your-domain.com;
root /var/www/my-bot/public;
location /webhook.php {
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/webhook.php;
include fastcgi_params;
}
}
Security Checklist Before Going to Production
- [ ] Never commit the bot token in code; always use
%env(...)%. - [ ] Set a
secret_tokenwhen callingsetWebhook, and verify theX-Telegram-Bot-Api-Secret-Tokenheader matches it insidewebhook.php, so nobody can send fake Updates directly to yourwebhook.php. - [ ] Keep the
config/andvar/folders outsidepublic/so they're not downloadable through a browser. - [ ] For production, wrap
EntityManagerFactorywith a metadata caching layer (see the performance note in Database and Doctrine).