Ferhat Gölge
Computer Worker
Deploying a Laravel AI Project on a VPS
(Apache VirtualHost + SSL + GitHub SSH Setup)
In this guide, we'll launch a subdomain like ai.kitmote.com from scratch.
The structure we will establish:
- Apache VirtualHost
- SSL (Let's Encrypt)
- GitHub SSH deploy
- Laravel folder structure compatible operation.
1️⃣ Apache VirtualHost Installation
📁 Project directory
First, make sure the project is in the right place:
mkdir -p ai.kitmote.com
cd ai.kitmote.com
The Laravel project will be here.
📄 Create a VirtualHost file
Write this inside:
<VirtualHost *:80>ServerName ai.kitmote.comServerAlias www.ai.kitmote.comDocumentRoot /var/www/ai.kitmote.com/public<Directory /var/www/ai.kitmote.com/public>AllowOverride AllRequire all granted</Directory>ErrorLog ${APACHE_LOG_DIR}/ai_error.logCustomLog ${APACHE_LOG_DIR}/ai_access.log combined</VirtualHost>🔧 Enable Apache modules
🔗 Activate the site
If it's available, disable it by default:
🔄 Apache restart
✅ Test
From the browser:
It should open if you have Laravel.
2️⃣ SSL Setup (Let's Encrypt)
📦 Certbot setup
sudo apt install certbot python3-certbot-apache -y
🔐 Get SSL
Questions:
- Email → Log in
- Redirect HTTP → Select YES (important)
🔁 Auto-renew control
✅ Test
3️⃣ GitHub SSH Key Setup
The most reliable method for production deployment is SSH.
🔑 Generate SSH key
Enter → Enter → Enter
🔍 Get public key
Copy what comes up.
🔗 Add to GitHub
GitHub →
👉 Settings → SSH and GPG Keys → New SSH Key
🔌 Test
Output:
4️⃣ Uploading the Project to the Server
name: Deploy AI Kitmote
on:push:branches:- master
concurrency:group: deploy-ai-kitmote-${{ github.ref }}cancel-in-progress: true
jobs:deploy:runs-on: ubuntu-lateststeps:- name: Checkoutuses: actions/checkout@v4- name: Setup PHPuses: shivammathur/setup-php@v2with:php-version: '8.4'extensions: mbstring, xml, ctype, iconv, intl, pdo_mysql, bcmath, zip, curltools: composer- name: Install Composer dependenciesrun: composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction --no-progress- name: Setup Nodeuses: actions/setup-node@v4with:node-version: '20'cache: npm- name: Install Node dependenciesrun: npm ci- name: Build assetsrun: npm run build- name: Start SSH agent (deploy key)uses: webfactory/ssh-agent@v0.9.0with:ssh-private-key: ${{ secrets.VPS_SSH_KEY }}- name: Trust VPS host keyenv:VPS_HOST: ${{ secrets.VPS_HOST }}run: |mkdir -p ~/.sshchmod 700 ~/.sshssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hostschmod 644 ~/.ssh/known_hosts- name: Rsync project to VPSenv:VPS_USER: ${{ secrets.VPS_USER }}VPS_HOST: ${{ secrets.VPS_HOST }}run: |export RSYNC_RSH="ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts"rsync -avz --delete \--exclude=".git" \--exclude=".github" \--exclude=".env" \--exclude=".env.*" \--exclude="node_modules" \--exclude="storage/logs" \--filter="protect .env" \--filter="protect .env.*" \./ "${VPS_USER}@${VPS_HOST}:/var/www/ai.kitmote.com/"- name: Run deploy commands on VPSenv:VPS_USER: ${{ secrets.VPS_USER }}VPS_HOST: ${{ secrets.VPS_HOST }}run: |ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$HOME/.ssh/known_hosts" \"${VPS_USER}@${VPS_HOST}" bash -s << 'REMOTE'set -euo pipefailcd /var/www/ai.kitmote.com# storage/framework Git'te yoksa rsync taşımaz; artisan down / view:clear patlarmkdir -p storage/framework/cache/datamkdir -p storage/framework/sessionsmkdir -p storage/framework/testingmkdir -p storage/framework/viewsmkdir -p storage/logsmkdir -p bootstrap/cacheexport COMPOSER_ALLOW_SUPERUSER=1php artisan down || truecomposer install --no-dev --prefer-dist --optimize-autoloader --no-interaction --no-progressphp artisan migrate --forcephp artisan optimize:clearphp artisan config:cachephp artisan route:cachephp artisan view:cachephp artisan storage:link || truephp artisan queue:restart || truechown -R www-data:www-data storage bootstrap/cachechmod -R 775 storage bootstrap/cachephp artisan upREMOTE
VPS_HOST = ip adresi
VPS_USER = kullanıcı
VPS_SSH_KEY = cat ~/.ssh/id_ed25519 gelen bütün değer. Add public key to authorized_keys
example :
sudo -u kitmotedeploy ssh-keygen -t ed25519 -C “gh-actions@kitmotedeploy” -f /home/kitmote/.ssh/gh_actions -N “”
sudo chown kitmotedeploy:kitmote /home/kitmote/.ssh/authorized_keys
sudo chmod 600 /home/kitmote/.ssh/authorized_keys
sudo chmod 700 /home/kitmote/.ssh
⚠️ Correct permissions
sudo chmod -R 755 /var/www/ai.kitmote.com
Laravel exclusive:
5️⃣ Laravel Installation Steps
📦 Addictions
⚙️ ENV
nano .env
🔑 Generate Key
🗄️ Migration
⚡ Cache optimization
php artisan route:cache
php artisan view:cache
6️⃣ Production Recommendations
🔥 Queue (optional)
Recommended with a supervisor.
🔍 Log check
🔄 Post-deployment update
composer install --no-dev
php artisan migrate --force
PHP Artisan Optimize
7️⃣ Common Mistakes
❌ 403 Forbidden
Is AllowOverride enabled?
Is Apache rewrite active?
❌ 500 Error
→ .env error
→ storage permissions
❌ 502 / blank page
Is Apache running?
🎯 Result
With this structure:
- ✅ Domain → VPS connected
- ✅ Apache → Laravel is running
- ✅ SSL → active
- ✅ GitHub → Automatic deployment ready
Keywords: VPS, SSH_KEY, github CI/CD