> For the complete documentation index, see [llms.txt](https://redberry.gitbook.io/resources/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://redberry.gitbook.io/resources/laravel/laravelis-proektis-serverze-gamartva.md).

# ლარაველის პროექტის სერვერზე გამართვა

![](https://392590438-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrgmjFj4NNSsoaQmAk09Z%2Fuploads%2F4jZd9OpfMpSgiaVd3paG%2Fimage.png?alt=media\&token=f829433d-40e4-4b16-aa0f-91739c523635)

## შესავალი <a href="#id-40ab" id="id-40ab"></a>

და დგება ის მომენტი, როდესაც შენს აპლიკაციას სული უნდა შთაჰბერო, სერვერზე გამართო, დომენი მიაბა და [https://my-app.ge](https://your-not-so-cool-app.ge/) -ზე შესვლა შენ გარდა სხვასაც შეეძლოს.

ჩვენ ვიცით ლოკალურად როგორ უნდა გავუშვათ დეველოპმენტ სერვერი: `php artisan serve` და ეგ არი.

მაგრამ… პროდაქშენის სერვერზეც ვიზამთ მსგავსად?

ჰმმ.. კი შეგვიძლია. მაგრმ არ უნდა ვქნათ - ამაზე ოდნავ მერე.

პროდაქშენში უნდა გამოვიყენოთ სხვადასხვა ხელსასწყო იმისათვის, რომ სერვერზე ჩვენი აპლიკაცია საათვით მუშაობდეს. ამ ხელსაწყოებს წარმოადგენს nginx და php-fpm.

ეს ორი ხელსაწყო უზრუნველყოფს იმას, რომ ჩვენმა აპლიკაციამ ოპტიმალურად გამოიყენოს სერვერის რესურსი, გვაძლევს საშუალებას არაერთი აპლიკაცია გავმართოთ სერვერზე, გვქონდეს ქეშირება და ა.შ.

## **სერვერზე ხელსაწყოებისა და პროგრამების დაყენება** <a href="#c61b" id="c61b"></a>

პირველ რიგში, როდესაც დავლოგინდებით სერვერზე საჭიროა, რომ გავუშვათ ბრძანება:\
`sudo apt update`

ეს ბრძანება ფექიჯების შესახებ ინფორმაციას დაააფდეითებს სერვერზე იმისათვის, რომ შემდგომში `sudo apt install something` -ს რომ გავუშვებთ, იცოდეს ეს `something` საიდან გადმოწეროს.

შემდგომ გვჭირდება, რომ php-ის custom რეპოზიტორია დავამატოთ უბუნტუს package manager-ში, იმისათვის, რომ უახლესი php დავაინსტალიროთ.

გავუშვათ ბრძანება:\
`sudo add-apt-repository ppa:ondrej/php`

შემდეგ კი დავაინსტალიროთ php-ის 8 ვერსია რამოდენიმე ექსთენშენთან ერთად:\
`sudo apt install php8.5 php8.5-curl php8.5-mbstring php8.5-xml php8.5-sqlite3 php8.5-zip`

*apt რეპოზიტორიის დამატების შემდგომ სტანდარტულად აპაჩეს ვებსერვერიც ყენდება, ჩვენ აპაჩე არ გვჭირდება და წავშალოთ სისტემიდან შემდეგი ბრძანებით:*\
`sudo apt purge apache2`

გარდა ამისა, რამოდენიმე დამატებითი ფექიჯიც, იმისათვის, რომ ამ ყველაფერმა გამართულად იმუშაოს:\
`sudo apt install zip sqlite3`

ამათ გარდა გვჭირდება კომპოუზერი და ნოუდიც. კომპოუზერის დაინსტალირებისთვის გავუშვათ შემდეგი ბრძანებები:\
`curl` [`https://getcomposer.org/installer`](https://getcomposer.org/installer) `| php`\
`sudo mv composer.phar /usr/bin/composer`

{% hint style="info" %}
როდესაც ბრძანებას `sudo mv composer.phar /usr/bin/composer` უშვებთ, თქვენ გადაგაქვთ კომპოუზერის ფაილი სისტემურ `PATH`-ში. ეს საშუალებას გაძლევთ, სერვერის ნებისმიერი წერტილიდან გამოიძახოთ ბრძანება `composer` გლობალურად, ნაცვლად იმისა, რომ ყოველ ჯერზე `php composer.phar` წეროთ.
{% endhint %}

ნოუდისათვის კი:\
`curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash`\
`sudo apt install nodejs`

## სერვერზე Laravel-ის პროექტის ჩამოტვირთვა <a href="#ab19" id="ab19"></a>

ჩვენს home ფოლდერში შევქმნათ apps ფოლდერი სადაც გვექნება აპლიკაციები, რომელსაც ჩვენს სერვერზე გავმართავთ.\
შემდეგ შევიდეთ apps ფოლდერში და დავკლონოთ გიტჰაბიდან რეპოზიტორია:

`cd ~`\
`mkdir apps`\
`cd apps`\
`git clone https://github.com/my-app.git`

თუ ვნახავთ apps ფოლდერის შიგთავსს, დავინახავთ, რომ გვაქვს ჩამოტვირთული ჩვენი პროექტი. შევიდეთ ჩვენს პროექტში და დავიწყოთ მისი გამართვა.<br>

{% hint style="warning" %}
თუ ძველი პროექტია და ვიყენებთ webpack-ს vite-ის ნაცვლად, მომდევნო ბრძანებებში npm run build -ის ნაცვლად უნდა გავუშვად npm run prod&#x20;
{% endhint %}

`cd my-app`\
`composer install`\
`npm install`\
`npm run build`\
`cp .env.example .env`\
`php artisan key:generate`\
`php artisan storage:link`\
`touch database/database.sqlite`<br>

ამ ქომანდების შემდეგ გვჭირდება, რომ .env ფაილი შევცვალოთ და sqlite დავაყენოთ ჩვენს ბაზად(სტანდარტულად mysql არის მონაცემთა ბაზის დრაივერი).

როდესაც .env -ს შევცვლით გავუშვათ შემდეგი ბრძანებები:

`php artisan optimize`\
`php artisan migrate`

და ასევე ნებისმიერი ბრძანება, რაც ჩვენს პროექტს სჭირდება.

## php artisan serve და რატომ — არა? <a href="#f973" id="f973"></a>

ჩვენ შეგვიძლია შევიდეთ ახლა ჩვენს პროექტში და გავუშვათ შედეგი ბრძანება:

`cd ~/apps/my-app`\
`sudo php artisan serve --host=0.0.0.0 --port=80`

ამის შემდგომ თუ შევალთ ჩვენი სერვერის IP-ზე დავინახავთ ჩვენს პროექტს.\
შესაბამისად `php artisan serve` -ის გამოყენება პროდაქშენში სავსებით შესაძლებელია.

და, რატომ არ უნდა გამოვიყენოთ?\
მავანმა, ამ კითხვაზე შეიძლება პასუხების ვრცელი ნუსხა გაჩვენოთ, მაგრამ ჩვენ დავკონცენტრირდეთ მთავარ მომენტებზე რაც ჩვენს რეალობაშსთანაა შესაბამისობაში:

* პირველი და მთავარი მიზეზი: PHP სტანდარტულად არ არის მრავალნაკადიანი(სრედიანი) ენა, რაც იმას ნიშნავს, რომ როდესაც `php artisan serve` -ს ვუშვებთ ჩვენი პროექტი გაშვებულია მხოლოდ და მხოლოდ პროცესორის ერთ ნაკადზე.\
  წარმოიდგინეთ — გაქვთ არანორმალურად მძლავრი სერვერი, მაგალითისთვის ვთქვათ — 32 ნაკადიანი პროცესორით. ჩვენ თუ ამ სერვერზე `php artisan serve` -ით გვექნება ჩვენი ლარაველის პროექტი გაშვებული გამოდის, რომ 32 ნაკადიდან მხოლოდ ერთს ვიყენებ. ეს იმასაც ნიშნავს, რომ სერვერი მომენტში მხოლოდ ერთ რექვესთს დაამუშავებს. და თუ ერთდროულად1-ის ნაცვლად 100 რექვესთი მიიღო — შესაბამისად დანარჩენი 99 რექვესთი რიგში უნდა ჩადგეს, რაც იმას ნიშნავს, რომ იქმნება bottleneck და მომხმარებელს უწევს ლოდინი სანამ საიტი ჩაეტვირთება.
* ვერ დავაყენებთ SSL-ს რაიმე დამატებითი ხელსაწყოს გარეშე, როგორიცაა Nginx, Apache ან სერვისი მაგალითად — cloudflare.
* თუ კოდში მოხდა fatal error ან შეივსო მეხსიერების ლიმიტი (memory limit), `artisan serve` პროცესი უბრალოდ "კვდება" (იქრაშება) და საიტი სრულად ითიშება, სანამ სერვერზე ხელით არ შეხვალთ და თავიდან არ გაუშვებთ.
* ვერ გავუშვებთ სერვერზე ერთზე მეტ ვებგვერდს(ერთი და იმავე პორტზე).
* ვერ გვექნება სწრაფი სტატიკური ფაილების serving-ი - სურათების, CSS-ის და JS ფაილების ჩატვირთვა ხდება PHP-ის მიერ, რაც ძალიან ანელებს პროცესს. არ არსებობს ქეშირების კონტროლი.
* არ გვაქვს სტატიკური ფაილების ქეშირება: Cache Control Policy

ეს მიზეზები საკმაოდ საკმარისია, იმისათვის, რომ ცოტა nginx-სა და php-fpm-სკენ გავიხედოთ.

## Nginx, PHP-FPM და Laravel <a href="#id-0c3b" id="id-0c3b"></a>

![](https://392590438-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrgmjFj4NNSsoaQmAk09Z%2Fuploads%2FwcTc2IJXbzxUq3g0MbMZ%2Fimage.png?alt=media\&token=cd8331bf-0e16-4a02-9699-0183e51fd9ca)

რა ურთიერთ დამოკიდებულებაში არიან Nginx, PHP-FPM და Laravel- ი?

პროდაქშენ გარემოში ჩვენ ვიყენებთ ორ დამოუკიდებელ სერვისს: Nginx (ვებ-სერვერი) და PHP-FPM (FastCGI პროცესების მენეჯერი).

განვიხილოთ 2 ვარიანტი.

ვთქვათ, ვაგზავნით რექვესთს <https://my-app.ge/cars/list> -ზე. სადაც blade-ით უნდა დაგენერირდეს მანქანების html სია და უნდა შეიცავდეს მანქანების შესახებ ინფორმაციას, რომელიც უნდა იქნას წამოღებული მონაცემთა ბაზიდან.\
როდესაც ბრაუზერიდან გავაგზავნით რექვესთს,\
**პირველი რაც შეხვდება რექვესთს არის Nginx.**\
ვებსერვერი, ამ შემთხვევაში nginx ნახავს url-ს, სერვერზე თუ არსებობს მსგავსი ფაილი შეამოწმებს — ამ შემთხვევაში:\
`/home/user/apps/my-project/public/`**`cars/list`** რაიმე ასეთი ფაილი თუ არსებობს. თუ ნახა, რომ არ არსებს Nginx ამ რექვესთს გადაამისამართებს PHP FPM-თან. შესაბამისად\
**მეორე რაც რექვეთს შეხვდება არის PHP FPM.** არსებობს ერთი მთავარი PHP FPM პროცესი, რომელსაც ქვია Master Process და ამ მთავარი პროცესის გარდა არიან შვილი პროცესები — child processes.\
მთავარი პროცესი ამენეჯებს შვილ პროცესებს და როდესაც რექვესთი შემოდის ერთ-ერთთან გადაამისამართებს.

შემდეგ შვილი FPM პროცესი დაამუშავებს ამ რექვესთს: გააკეთებს მონაცემთა ბაზასთან კომუნიკაციას, ბლეიდით ააწყობს html-ს და ა.შ. და ბოლოს დააბრუნებს Response-ს უკან.\
Master პროცესი პასუხს Nginx-ს დაუბრუნებს, ხოლო Nginx ბრაუზერს.\
აქედან ვხედავთ, რომ რა პრობლემაც `php artisan serve` -ს ჰქონდა, ეგ პრობლემა PHP FPM-ის შვილი პროცესებით არის მოგვარებული. გვაქვს დასტარტული ბევრი შევილი პროცესი და როგორც კი შემოვა რექვესთი, რომელი შვილი პროცესიც თავისუფალია მასთან ვამისამართებთ და ვამუშავებინებთ რექვესთს.

ახლა განვიხილოთ **მეორე ვარიანტი**.\
ვთქვათ, ვაგზავნით რექვესთს <https://my-app.ge/css/app.css> — ზე.\
ამ შემთხვევაში Nginx შეამოწმებს რაიმე ფაილი თუ არსებობს შემდეგ მისამართზე: `/home/user/my-project/public/`**`css/app.css`** და თუ ნახავს, რომ ასეთი ფაილი არსებობს უკვე პირდაპირ ბრაუზერს თითონ გაუგზავნის ამ ფაილს და php-ს და ლარაველს საერთოდ აღარც შეეხება.

## PHP FPM-ის კონფიგურაცია <a href="#id-6abb" id="id-6abb"></a>

პირველრიგში უნდა დავაინსტალიროთ PHP FPM:\
`sudo apt install php8.5-fpm`

სერვერზე შევიდეთ შემდეგ ფოლდერში:\
`cd /etc/php/8.5/fpm/pool.d`

წავშალოთ სტანდარტული კონფიგურაცია:\
`rm www.conf`

შევქმნათ ახალი ფაილი:\
`touch my-app.conf`

და შიგნით ჩავწეროთ შემდეგი კონფიგურაცია:

```
; Your application name
[my-app]

; Set these two variables to your user name
user = YOUR_USER_NAME
group = YOUR_USER_NAME

; With this configuration line, php-fpm will
; Create unix socket for our application and
; We will redirect request to this socket from Nginx
; ! change 'my-app' to you project specific name
listen = /run/php/php8.5-my-app-fpm.sock

; Keep this two lines as it is.
listen.owner = www-data
listen.group = www-data

; Dynamicly increase and decrease number of child processes
pm = dynamic

; Max number of child processes that can be alive at 
; any given moment
pm.max_children = 5

; Number of child process that will be started at FPM startup
pm.start_servers = 2

; Min child processes that can be without any job
pm.min_spare_servers = 1

; Max child procesess that can be without any job
pm.max_spare_servers = 3
```

შეინახეთ ფაილი და გადატვირთეთ fpm-ის პროცესი:\
`sudo systemctl restart php8.5-fpm.service`

გადატვირთვისას შეიქმნებოდა unix-ის სოკეტი:\
`/run/php/php8.5-my-app-fpm.sock`

{% hint style="info" %}

FPM კონფიგურაციის პარამეტრების განმარტება:

* `[my-app]` - პულის (pool) უნიკალური სახელი. თითოეულ პროექტს სერვერზე უნდა ჰქონდეს თავისი პული იზოლაციისთვის.
* `pm = dynamic` - პროცესების მართვის დინამიური რეჟიმი. პროცესების რაოდენობა გაიზრდება და შემცირდება დატვირთვის მიხედვით.
* `pm.max_children = 5` - მაქსიმუმ რამდენი პარალელური შვილი პროცესი (child process) შეიძლება არსებობდეს. ეს განსაზღვრავს, თუ რამდენი PHP მოთხოვნის პარალელურად დამუშავება შეუძლია სერვერს მოცემულ მომენტში. თუ საიტს ბევრი მომხმარებელი ყავს, ეს ციფრი სერვერის RAM-ის შესაბამისად უნდა გაიზარდოს.
  {% endhint %}

## NGINX-ის კონფიგურაცია <a href="#id-46a6" id="id-46a6"></a>

პირველ რიგში დავინსტალიროთ nginx:\
`sudo apt install nginx`

სერვერზე შევიდეთ შემდეგ ფოლდერში:\
`cd /etc/nginx/sites-enabled`

წავშალოთ არსებული default კონფიგურაციის ფაილი:\
`sudo rm default`

შევქმნათ ახალი კონფიგურაციის ფაილი:\
`touch my-app.ge`

და შიგნით ჩავწეროთ შემდეგი კონფიგურაცია:

```
 server {
 
 listen 80;
 
 # change this line according to your app's public path
 root /home/user/apps/my-app/public;
 
 # change this [!] DOMAIN [!] according to your domain
 server_name my-app.ge;
 
 index index.php;
 
 location / {
    try_files $uri $uri/ /index.php?$query_string;
 }
 
 location ~ \.php$ {
     include snippets/fastcgi-php.conf;
     
     # change socket address according to your created socket path
     fastcgi_pass unix:/run/php/php8.5-my-app-fpm.sock;
 }
}
```

ასევე საჭიროა, რომ nginx-ის მომხმარებელს მივცეთ წვდომა ჩვენი მომხმარებლის ფოლდერებსა და ფაილებზე იმისათვის, რომ ჩვენი აპლიკაციის დამუშავებისათვის ჰქონდეს შესაბამისი უფლებები. ამისათვის გაუშვით ქვემოთ შემდეგი ორი ბრძანება:

```
sudo usermod -aG [your-username] www-data 
sudo systemctl restart nginx
```

## SSL-ის დაყენება LetsEncrypt-ით <a href="#id-4d3a" id="id-4d3a"></a>

იმისათვის, რომ LetsEncrypt-ის სერტიფიკატი დავაყენოთ ჩვენს საიტზე, საჭიროა, რომ რამოდენიმე ფექიჯი დავაინსტალიროთ:\
`sudo apt install certbot python3-certbot-nginx`

შემდგომ გავუშვათ ბრძანება:\
`sudo certbot`

და მივყვეთ certbot-ის ინსტრუქციებს.

## დასკვნა <a href="#id-8e7d" id="id-8e7d"></a>

ლარაველის პროექტის Production სერვერზე გასამართად ჩასატარებელია რიგი პროცედურები:

* სერვერზე საჭირო ფექიჯების დაყენება
* პროექტის ჩამოტვირთვა და შესაბამისი dependencies-ების დაინსტალირება
* PHP FPM-ის კონფიგურაცია
* Nginx-ის კონფიგურაცია
* LetsEncrypt-ით SSL-ის დაყენება

აბა თქვენ იცით,\
ღმერთი თქვენსკენ 🙏
