Adiciona configuração inicial da stack Docker para projetos Laravel, incluindo Dockerfile, docker-compose, scripts de gerenciamento e configuração do Nginx.
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Sistema
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Segredos locais
|
||||
.env
|
||||
.env.local
|
||||
|
||||
# Pastas geradas no host
|
||||
projects/
|
||||
nginx-dynamic/
|
||||
composer-cache/
|
||||
npm-cache/
|
||||
73
Dockerfile
Normal file
73
Dockerfile
Normal file
@@ -0,0 +1,73 @@
|
||||
FROM php:8.3-fpm-bookworm
|
||||
|
||||
ARG NODE_MAJOR=20
|
||||
|
||||
ENV COMPOSER_ALLOW_SUPERUSER=1 \
|
||||
COMPOSER_CACHE_DIR=/tmp/composer-cache \
|
||||
NPM_CONFIG_CACHE=/root/.npm
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
nginx \
|
||||
supervisor \
|
||||
git \
|
||||
bash \
|
||||
curl \
|
||||
unzip \
|
||||
zip \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
libpq-dev \
|
||||
libzip-dev \
|
||||
libpng-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libfreetype6-dev \
|
||||
libicu-dev \
|
||||
libonig-dev \
|
||||
libxml2-dev \
|
||||
libssl-dev \
|
||||
libcurl4-openssl-dev \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j"$(nproc)" \
|
||||
pdo \
|
||||
pdo_pgsql \
|
||||
pgsql \
|
||||
pdo_mysql \
|
||||
mysqli \
|
||||
zip \
|
||||
gd \
|
||||
intl \
|
||||
bcmath \
|
||||
exif \
|
||||
opcache \
|
||||
pcntl \
|
||||
&& pecl install redis \
|
||||
&& docker-php-ext-enable redis \
|
||||
&& curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
|
||||
|
||||
RUN mkdir -p /home/deploy/projects \
|
||||
/home/deploy/scripts \
|
||||
/etc/nginx/sites-dynamic \
|
||||
/var/log/nginx \
|
||||
/run/nginx \
|
||||
/var/log/supervisor \
|
||||
/tmp/composer-cache \
|
||||
/root/.npm
|
||||
|
||||
COPY php/php.ini /usr/local/etc/php/conf.d/99-laravel-stack.ini
|
||||
COPY nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
COPY scripts/ /home/deploy/scripts/
|
||||
|
||||
RUN chmod +x /home/deploy/scripts/*.sh \
|
||||
&& chown -R www-data:www-data /home/deploy/projects /tmp/composer-cache
|
||||
|
||||
WORKDIR /home/deploy
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["/home/deploy/scripts/start.sh"]
|
||||
408
README.md
Normal file
408
README.md
Normal file
@@ -0,0 +1,408 @@
|
||||
# Laravel Multi-Projeto Stack
|
||||
|
||||
Stack Docker para hospedar vários projetos Laravel no mesmo container, acessando por rota:
|
||||
|
||||
```txt
|
||||
https://laravel.juancjc.com.br/projeto1
|
||||
https://laravel.juancjc.com.br/projeto2
|
||||
https://laravel.juancjc.com.br/sistema-alunos
|
||||
```
|
||||
|
||||
A ideia é parecida com sua stack NestJS, mas para Laravel:
|
||||
|
||||
- Nginx na frente.
|
||||
- PHP-FPM para rodar Laravel.
|
||||
- Composer dentro do container.
|
||||
- Node + NPM dentro do container para projetos com Vite/Vue.
|
||||
- Detecta automaticamente:
|
||||
- `laravel-vue`
|
||||
- `laravel-blade-vite`
|
||||
- `laravel-blade`
|
||||
- `laravel-node`
|
||||
- Cria automaticamente a rota `/nome-da-pasta`.
|
||||
|
||||
---
|
||||
|
||||
## Estrutura do repositório
|
||||
|
||||
```txt
|
||||
laravel-stack/
|
||||
├── Dockerfile
|
||||
├── docker-compose.yml
|
||||
├── .gitignore
|
||||
├── nginx/
|
||||
│ └── nginx.conf
|
||||
├── php/
|
||||
│ └── php.ini
|
||||
├── supervisor/
|
||||
│ └── supervisord.conf
|
||||
├── scripts/
|
||||
│ ├── start.sh
|
||||
│ ├── deploy.sh
|
||||
│ ├── remove.sh
|
||||
│ └── status.sh
|
||||
├── host-deploy.sh
|
||||
├── host-remove.sh
|
||||
└── host-status.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Estrutura no servidor
|
||||
|
||||
```txt
|
||||
/srv/projects/laravel/
|
||||
├── projects/
|
||||
│ ├── projeto1/
|
||||
│ ├── projeto2/
|
||||
│ └── sistema-alunos/
|
||||
├── nginx-dynamic/
|
||||
├── composer-cache/
|
||||
└── npm-cache/
|
||||
```
|
||||
|
||||
Cada pasta dentro de `/srv/projects/laravel/projects` vira uma rota.
|
||||
|
||||
Exemplo:
|
||||
|
||||
```txt
|
||||
/srv/projects/laravel/projects/sistema-alunos
|
||||
```
|
||||
|
||||
vira:
|
||||
|
||||
```txt
|
||||
https://laravel.juancjc.com.br/sistema-alunos
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup inicial no servidor
|
||||
|
||||
```bash
|
||||
mkdir -p /srv/projects/laravel/projects
|
||||
mkdir -p /srv/projects/laravel/nginx-dynamic
|
||||
mkdir -p /srv/projects/laravel/composer-cache
|
||||
mkdir -p /srv/projects/laravel/npm-cache
|
||||
```
|
||||
|
||||
Clone esta stack:
|
||||
|
||||
```bash
|
||||
git clone <repo-da-laravel-stack> /srv/projects/laravel/laravel-stack
|
||||
cd /srv/projects/laravel/laravel-stack
|
||||
chmod +x host-*.sh
|
||||
```
|
||||
|
||||
Suba com Docker Compose:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Ou pelo Portainer:
|
||||
|
||||
1. Stacks
|
||||
2. Add Stack
|
||||
3. Repository
|
||||
4. Cole a URL deste repositório
|
||||
5. Deploy
|
||||
|
||||
---
|
||||
|
||||
## Adicionar um projeto Laravel
|
||||
|
||||
Entre na pasta de projetos:
|
||||
|
||||
```bash
|
||||
cd /srv/projects/laravel/projects
|
||||
```
|
||||
|
||||
Clone ou coloque o código:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/seu-usuario/meu-projeto.git meu-projeto
|
||||
```
|
||||
|
||||
Crie ou edite o `.env`:
|
||||
|
||||
```bash
|
||||
nano /srv/projects/laravel/projects/meu-projeto/.env
|
||||
```
|
||||
|
||||
Depois faça o deploy:
|
||||
|
||||
```bash
|
||||
/srv/projects/laravel/laravel-stack/host-deploy.sh meu-projeto
|
||||
```
|
||||
|
||||
Acesse:
|
||||
|
||||
```txt
|
||||
https://laravel.juancjc.com.br/meu-projeto
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Atualizar um projeto
|
||||
|
||||
```bash
|
||||
cd /srv/projects/laravel/projects/meu-projeto
|
||||
git pull
|
||||
|
||||
/srv/projects/laravel/laravel-stack/host-deploy.sh meu-projeto
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ver status
|
||||
|
||||
```bash
|
||||
/srv/projects/laravel/laravel-stack/host-status.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Remover projeto
|
||||
|
||||
Remove rota Nginx e arquivos:
|
||||
|
||||
```bash
|
||||
/srv/projects/laravel/laravel-stack/host-remove.sh meu-projeto
|
||||
```
|
||||
|
||||
Remove só a rota, mantendo os arquivos:
|
||||
|
||||
```bash
|
||||
/srv/projects/laravel/laravel-stack/host-remove.sh meu-projeto --keep-files
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Como ele identifica Vue ou Blade
|
||||
|
||||
O script olha os arquivos do projeto:
|
||||
|
||||
### Laravel Vue
|
||||
|
||||
Se existir `package.json` com:
|
||||
|
||||
```json
|
||||
"vue"
|
||||
```
|
||||
|
||||
ou:
|
||||
|
||||
```json
|
||||
"@inertiajs/vue3"
|
||||
```
|
||||
|
||||
ou:
|
||||
|
||||
```json
|
||||
"@vitejs/plugin-vue"
|
||||
```
|
||||
|
||||
ele marca como:
|
||||
|
||||
```txt
|
||||
laravel-vue
|
||||
```
|
||||
|
||||
### Laravel Blade com Vite
|
||||
|
||||
Se existir `package.json` com Vite, mas sem Vue:
|
||||
|
||||
```txt
|
||||
laravel-blade-vite
|
||||
```
|
||||
|
||||
### Laravel Blade simples
|
||||
|
||||
Se não tiver `package.json`:
|
||||
|
||||
```txt
|
||||
laravel-blade
|
||||
```
|
||||
|
||||
O tipo fica salvo em:
|
||||
|
||||
```txt
|
||||
.projeto/.project-type
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Importante para rodar em `/projeto`
|
||||
|
||||
Como cada sistema roda em subpasta, o deploy ajusta automaticamente no `.env` do projeto:
|
||||
|
||||
```env
|
||||
APP_URL=https://laravel.juancjc.com.br/meu-projeto
|
||||
ASSET_URL=/meu-projeto
|
||||
```
|
||||
|
||||
Isso ajuda CSS, JS, imagens e links gerados pelo Laravel.
|
||||
|
||||
---
|
||||
|
||||
## Projetos Vue/Inertia com Vite
|
||||
|
||||
Se algum projeto Vue tiver problema com assets em `/build`, ajuste o `vite.config.js` para respeitar `VITE_BASE`.
|
||||
|
||||
Exemplo:
|
||||
|
||||
```js
|
||||
import { defineConfig } from 'vite';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
export default defineConfig({
|
||||
base: process.env.VITE_BASE || '/',
|
||||
plugins: [
|
||||
laravel({
|
||||
input: 'resources/js/app.js',
|
||||
refresh: true,
|
||||
}),
|
||||
vue(),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
O deploy já executa:
|
||||
|
||||
```bash
|
||||
ASSET_URL="/meu-projeto" VITE_BASE="/meu-projeto/build/" npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rodar migrations automaticamente
|
||||
|
||||
Por padrão, a stack não roda migrations para evitar acidente em produção.
|
||||
|
||||
Se quiser que rode no deploy, coloque no `.env` do projeto:
|
||||
|
||||
```env
|
||||
RUN_MIGRATIONS=true
|
||||
```
|
||||
|
||||
Aí no deploy ele executa:
|
||||
|
||||
```bash
|
||||
php artisan migrate --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comandos úteis
|
||||
|
||||
Logs do container:
|
||||
|
||||
```bash
|
||||
docker logs laravel-stack -f
|
||||
```
|
||||
|
||||
Entrar no container:
|
||||
|
||||
```bash
|
||||
docker exec -it laravel-stack bash
|
||||
```
|
||||
|
||||
Deploy manual dentro do container:
|
||||
|
||||
```bash
|
||||
docker exec laravel-stack /home/deploy/scripts/deploy.sh meu-projeto
|
||||
```
|
||||
|
||||
Ver Nginx:
|
||||
|
||||
```bash
|
||||
docker exec laravel-stack nginx -T
|
||||
```
|
||||
|
||||
Testar Nginx:
|
||||
|
||||
```bash
|
||||
docker exec laravel-stack nginx -t
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variáveis principais no docker-compose
|
||||
|
||||
```env
|
||||
PROJECTS_DIR=/home/deploy/projects
|
||||
DOMAIN=laravel.juancjc.com.br
|
||||
PUBLIC_BASE_URL=https://laravel.juancjc.com.br
|
||||
AUTO_DEPLOY_ON_START=false
|
||||
PHP_MEMORY_LIMIT=512M
|
||||
```
|
||||
|
||||
### `AUTO_DEPLOY_ON_START`
|
||||
|
||||
Se deixar:
|
||||
|
||||
```env
|
||||
AUTO_DEPLOY_ON_START=false
|
||||
```
|
||||
|
||||
o container apenas recria as rotas Nginx ao iniciar.
|
||||
|
||||
Se trocar para:
|
||||
|
||||
```env
|
||||
AUTO_DEPLOY_ON_START=true
|
||||
```
|
||||
|
||||
o container roda deploy em todos os projetos sempre que iniciar.
|
||||
|
||||
Eu recomendo deixar `false` e usar:
|
||||
|
||||
```bash
|
||||
./host-deploy.sh projeto
|
||||
```
|
||||
|
||||
quando quiser atualizar.
|
||||
|
||||
---
|
||||
|
||||
## Banco Postgres
|
||||
|
||||
A stack já está ligada na rede externa:
|
||||
|
||||
```yaml
|
||||
postgres-18_default:
|
||||
external: true
|
||||
```
|
||||
|
||||
Então, no `.env` do Laravel, use o nome do serviço/container do Postgres como host.
|
||||
|
||||
Exemplo:
|
||||
|
||||
```env
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=postgres
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=meu_banco
|
||||
DB_USERNAME=meu_usuario
|
||||
DB_PASSWORD=minha_senha
|
||||
```
|
||||
|
||||
Se seu container Postgres tiver outro nome, ajuste o `DB_HOST`.
|
||||
|
||||
---
|
||||
|
||||
## Observação
|
||||
|
||||
Para produção, prefira colocar o domínio principal no Nginx Proxy Manager apontando para:
|
||||
|
||||
```txt
|
||||
laravel-stack:80
|
||||
```
|
||||
|
||||
ou para a porta publicada:
|
||||
|
||||
```txt
|
||||
IP_DO_SERVIDOR:3452
|
||||
```
|
||||
31
docker-compose.yml
Normal file
31
docker-compose.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
services:
|
||||
laravel-stack:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: laravel-stack
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3452:80"
|
||||
volumes:
|
||||
- /srv/projects/laravel/projects:/home/deploy/projects
|
||||
- /srv/projects/laravel/nginx-dynamic:/etc/nginx/sites-dynamic
|
||||
- /srv/projects/laravel/composer-cache:/tmp/composer-cache
|
||||
- /srv/projects/laravel/npm-cache:/root/.npm
|
||||
environment:
|
||||
- PROJECTS_DIR=/home/deploy/projects
|
||||
- DOMAIN=laravel.juancjc.com.br
|
||||
- PUBLIC_BASE_URL=https://laravel.juancjc.com.br
|
||||
- AUTO_DEPLOY_ON_START=false
|
||||
- PHP_MEMORY_LIMIT=512M
|
||||
labels:
|
||||
- "com.laravelstack.managed=true"
|
||||
networks:
|
||||
- proxy-net
|
||||
- postgres-18_default
|
||||
|
||||
networks:
|
||||
proxy-net:
|
||||
external: true
|
||||
postgres-18_default:
|
||||
external: true
|
||||
15
host-deploy.sh
Normal file
15
host-deploy.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# host-deploy.sh — rode NO HOST para deployar um projeto Laravel
|
||||
# Uso: ./host-deploy.sh meu-projeto
|
||||
# Uso: ./host-deploy.sh # deploya todos
|
||||
|
||||
CONTAINER="${CONTAINER:-laravel-stack}"
|
||||
TARGET="${1:-}"
|
||||
|
||||
if [ -n "$TARGET" ]; then
|
||||
echo ">>> Deployando $TARGET via container..."
|
||||
docker exec "$CONTAINER" /home/deploy/scripts/deploy.sh "$TARGET"
|
||||
else
|
||||
echo ">>> Deployando todos os projetos via container..."
|
||||
docker exec "$CONTAINER" /home/deploy/scripts/deploy.sh
|
||||
fi
|
||||
17
host-remove.sh
Normal file
17
host-remove.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# host-remove.sh — remove um projeto da Laravel Stack
|
||||
# Uso: ./host-remove.sh meu-projeto
|
||||
# Uso: ./host-remove.sh meu-projeto --keep-files
|
||||
|
||||
CONTAINER="${CONTAINER:-laravel-stack}"
|
||||
TARGET="${1:-}"
|
||||
KEEP_FILES="${2:-}"
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo "❌ Informe o nome do projeto."
|
||||
echo "Uso: ./host-remove.sh meu-projeto"
|
||||
echo "Uso: ./host-remove.sh meu-projeto --keep-files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker exec "$CONTAINER" /home/deploy/scripts/remove.sh "$TARGET" "$KEEP_FILES"
|
||||
6
host-status.sh
Normal file
6
host-status.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
# host-status.sh — status dos projetos Laravel
|
||||
|
||||
CONTAINER="${CONTAINER:-laravel-stack}"
|
||||
|
||||
docker exec "$CONTAINER" /home/deploy/scripts/status.sh
|
||||
66
nginx/nginx.conf
Normal file
66
nginx/nginx.conf
Normal file
@@ -0,0 +1,66 @@
|
||||
user www-data;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
server_tokens off;
|
||||
client_max_body_size 100M;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
image/svg+xml;
|
||||
|
||||
map $http_x_forwarded_proto $fastcgi_https {
|
||||
default "";
|
||||
https on;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
absolute_redirect off;
|
||||
|
||||
location = / {
|
||||
add_header Content-Type text/plain;
|
||||
return 200 'Laravel Stack pronta. Use /nome-do-projeto para acessar seus projetos.';
|
||||
}
|
||||
|
||||
location = /health {
|
||||
add_header Content-Type text/plain;
|
||||
return 200 'ok';
|
||||
}
|
||||
|
||||
include /etc/nginx/sites-dynamic/*.conf;
|
||||
|
||||
location ~ /\.(?!well-known).* {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
php/php.ini
Normal file
14
php/php.ini
Normal file
@@ -0,0 +1,14 @@
|
||||
memory_limit=${PHP_MEMORY_LIMIT}
|
||||
upload_max_filesize=100M
|
||||
post_max_size=100M
|
||||
max_execution_time=300
|
||||
max_input_time=300
|
||||
date.timezone=America/Rio_Branco
|
||||
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.validate_timestamps=0
|
||||
opcache.max_accelerated_files=20000
|
||||
opcache.memory_consumption=256
|
||||
opcache.interned_strings_buffer=16
|
||||
opcache.fast_shutdown=1
|
||||
284
scripts/deploy.sh
Normal file
284
scripts/deploy.sh
Normal file
@@ -0,0 +1,284 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
PROJECTS_DIR="${PROJECTS_DIR:-/home/deploy/projects}"
|
||||
DOMAIN="${DOMAIN:-localhost}"
|
||||
PUBLIC_BASE_URL="${PUBLIC_BASE_URL:-http://${DOMAIN}}"
|
||||
TARGET=""
|
||||
NGINX_ONLY=false
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--nginx-only) NGINX_ONLY=true ;;
|
||||
*) TARGET="$arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
safe_name() {
|
||||
echo "$1" | sed 's/[^A-Za-z0-9._-]/-/g'
|
||||
}
|
||||
|
||||
env_get() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
|
||||
if [ -f "$file" ]; then
|
||||
grep -E "^${key}=" "$file" | tail -n1 | cut -d '=' -f2- | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//"
|
||||
fi
|
||||
}
|
||||
|
||||
env_set() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
local value="$3"
|
||||
|
||||
touch "$file"
|
||||
|
||||
if grep -qE "^${key}=" "$file"; then
|
||||
sed -i "s|^${key}=.*|${key}=${value}|g" "$file"
|
||||
else
|
||||
echo "${key}=${value}" >> "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_type() {
|
||||
local project_dir="$1"
|
||||
|
||||
if [ ! -f "$project_dir/artisan" ]; then
|
||||
echo "nao-laravel"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -f "$project_dir/package.json" ]; then
|
||||
if grep -qiE '"(@inertiajs/vue3|vue|@vitejs/plugin-vue)"' "$project_dir/package.json"; then
|
||||
echo "laravel-vue"
|
||||
elif grep -qiE '"vite"|'"'@laravel/vite-plugin'" "$project_dir/package.json"; then
|
||||
echo "laravel-blade-vite"
|
||||
else
|
||||
echo "laravel-node"
|
||||
fi
|
||||
else
|
||||
echo "laravel-blade"
|
||||
fi
|
||||
}
|
||||
|
||||
has_npm_build() {
|
||||
node -e "const p=require('./package.json'); process.exit(p.scripts && p.scripts.build ? 0 : 1)" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
reload_nginx_if_running() {
|
||||
if pgrep nginx >/dev/null 2>&1; then
|
||||
nginx -t && nginx -s reload
|
||||
fi
|
||||
}
|
||||
|
||||
generate_nginx_config() {
|
||||
local project="$1"
|
||||
local project_dir="$2"
|
||||
local safe_project
|
||||
safe_project="$(safe_name "$project")"
|
||||
|
||||
cat > "/etc/nginx/sites-dynamic/${safe_project}.conf" <<EOF
|
||||
# Gerado automaticamente pela Laravel Stack
|
||||
# Projeto: ${project}
|
||||
# Pasta: ${project_dir}
|
||||
|
||||
location = /${project} {
|
||||
return 301 /${project}/;
|
||||
}
|
||||
|
||||
location ^~ /${project}/ {
|
||||
alias ${project_dir}/public/;
|
||||
index index.php index.html;
|
||||
try_files \$uri \$uri/ /${project}/index.php?\$query_string;
|
||||
}
|
||||
|
||||
location ~ ^/${project}/index\.php(/|$) {
|
||||
internal;
|
||||
|
||||
include fastcgi_params;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
|
||||
fastcgi_param SCRIPT_FILENAME ${project_dir}/public/index.php;
|
||||
fastcgi_param DOCUMENT_ROOT ${project_dir}/public;
|
||||
|
||||
# Importante para Laravel funcionar em subpasta /${project}
|
||||
fastcgi_param SCRIPT_NAME /${project}/index.php;
|
||||
fastcgi_param PHP_SELF /${project}/index.php;
|
||||
fastcgi_param REQUEST_URI \$request_uri;
|
||||
|
||||
fastcgi_param HTTPS \$fastcgi_https;
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 16 16k;
|
||||
}
|
||||
|
||||
location ~ ^/${project}/.*\.php$ {
|
||||
return 404;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
deploy_project() {
|
||||
local project="$1"
|
||||
local project_dir="$PROJECTS_DIR/$project"
|
||||
local safe_project
|
||||
local type
|
||||
local env_file
|
||||
local project_url
|
||||
local run_migrations
|
||||
|
||||
safe_project="$(safe_name "$project")"
|
||||
env_file="$project_dir/.env"
|
||||
project_url="${PUBLIC_BASE_URL%/}/${project}"
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Deployando: $project"
|
||||
echo " URL: $project_url"
|
||||
echo "================================================"
|
||||
|
||||
if [ ! -d "$project_dir" ]; then
|
||||
echo "✗ Pasta $project_dir não encontrada"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$project_dir/artisan" ]; then
|
||||
echo "⚠ $project ignorado: não encontrei artisan. Não parece Laravel."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -f "$project_dir/public/index.php" ]; then
|
||||
echo "✗ $project sem public/index.php"
|
||||
return 1
|
||||
fi
|
||||
|
||||
type="$(detect_type "$project_dir")"
|
||||
echo "$type" > "$project_dir/.project-type"
|
||||
|
||||
echo "→ Tipo identificado: $type"
|
||||
|
||||
generate_nginx_config "$project" "$project_dir"
|
||||
echo "✓ Nginx criado: /${project}"
|
||||
|
||||
if [ "$NGINX_ONLY" = "true" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
cd "$project_dir"
|
||||
|
||||
if [ ! -f "$env_file" ] && [ -f "$project_dir/.env.example" ]; then
|
||||
echo "→ .env não encontrado, copiando .env.example"
|
||||
cp "$project_dir/.env.example" "$env_file"
|
||||
fi
|
||||
|
||||
if [ -f "$env_file" ]; then
|
||||
env_set "$env_file" "APP_URL" "$project_url"
|
||||
env_set "$env_file" "ASSET_URL" "/${project}"
|
||||
else
|
||||
echo "⚠ Sem .env. Crie $env_file antes de usar banco/cache em produção."
|
||||
fi
|
||||
|
||||
echo "→ composer install..."
|
||||
composer install \
|
||||
--no-dev \
|
||||
--prefer-dist \
|
||||
--no-interaction \
|
||||
--optimize-autoloader
|
||||
|
||||
if [ -f "$env_file" ]; then
|
||||
app_key="$(env_get "$env_file" "APP_KEY")"
|
||||
if [ -z "$app_key" ] || [ "$app_key" = "null" ]; then
|
||||
echo "→ Gerando APP_KEY..."
|
||||
php artisan key:generate --force
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "→ Limpando caches Laravel..."
|
||||
php artisan optimize:clear || true
|
||||
|
||||
if [ -f "package.json" ]; then
|
||||
echo "→ Dependências front-end encontradas."
|
||||
|
||||
if [ -f "package-lock.json" ]; then
|
||||
echo "→ npm ci..."
|
||||
npm ci --no-audit --no-fund
|
||||
else
|
||||
echo "→ npm install..."
|
||||
npm install --no-audit --no-fund
|
||||
fi
|
||||
|
||||
if has_npm_build; then
|
||||
echo "→ npm run build..."
|
||||
ASSET_URL="/${project}" VITE_BASE="/${project}/build/" npm run build
|
||||
else
|
||||
echo "⚠ package.json sem script build. Pulando build."
|
||||
fi
|
||||
else
|
||||
echo "→ Sem package.json. Projeto identificado como Blade/PHP puro."
|
||||
fi
|
||||
|
||||
echo "→ storage:link..."
|
||||
php artisan storage:link || true
|
||||
|
||||
run_migrations="$(env_get "$env_file" "RUN_MIGRATIONS")"
|
||||
if [ "$run_migrations" = "true" ]; then
|
||||
echo "→ RUN_MIGRATIONS=true, rodando migrations..."
|
||||
php artisan migrate --force
|
||||
fi
|
||||
|
||||
echo "→ Otimizando Laravel..."
|
||||
php artisan config:cache || true
|
||||
php artisan route:cache || {
|
||||
echo "⚠ route:cache falhou, limpando cache de rotas."
|
||||
php artisan route:clear || true
|
||||
}
|
||||
php artisan view:cache || true
|
||||
php artisan event:cache || true
|
||||
|
||||
echo "→ Ajustando permissões..."
|
||||
mkdir -p storage bootstrap/cache
|
||||
chown -R www-data:www-data storage bootstrap/cache public || true
|
||||
chmod -R ug+rwX storage bootstrap/cache || true
|
||||
|
||||
echo "✓ $project deployado em /$project"
|
||||
}
|
||||
|
||||
deploy_all() {
|
||||
local found=0
|
||||
|
||||
for project_dir in "$PROJECTS_DIR"/*/; do
|
||||
[ -d "$project_dir" ] || continue
|
||||
project="$(basename "$project_dir")"
|
||||
found=$((found + 1))
|
||||
deploy_project "$project" || true
|
||||
done
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "Nenhum projeto encontrado em $PROJECTS_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "$PROJECTS_DIR" /etc/nginx/sites-dynamic
|
||||
|
||||
if [ -n "$TARGET" ]; then
|
||||
deploy_project "$TARGET"
|
||||
else
|
||||
deploy_all
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "→ Recarregando Nginx se estiver em execução..."
|
||||
reload_nginx_if_running || true
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Deploy concluído!"
|
||||
for project_dir in "$PROJECTS_DIR"/*/; do
|
||||
[ -d "$project_dir" ] || continue
|
||||
project="$(basename "$project_dir")"
|
||||
type="$(cat "$project_dir/.project-type" 2>/dev/null || echo '?')"
|
||||
echo " ✓ /$project → $type"
|
||||
done
|
||||
echo "================================================"
|
||||
41
scripts/remove.sh
Normal file
41
scripts/remove.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
PROJECTS_DIR="${PROJECTS_DIR:-/home/deploy/projects}"
|
||||
TARGET="${1:-}"
|
||||
KEEP_FILES="${2:-}"
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo "❌ Informe o nome do projeto."
|
||||
echo "Uso: /home/deploy/scripts/remove.sh meu-projeto"
|
||||
echo "Uso: /home/deploy/scripts/remove.sh meu-projeto --keep-files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
safe_target="$(echo "$TARGET" | sed 's/[^A-Za-z0-9._-]/-/g')"
|
||||
|
||||
echo "================================================"
|
||||
echo " Removendo projeto: $TARGET"
|
||||
echo "================================================"
|
||||
|
||||
echo "→ Removendo config do Nginx..."
|
||||
rm -f "/etc/nginx/sites-dynamic/${safe_target}.conf"
|
||||
|
||||
if pgrep nginx >/dev/null 2>&1; then
|
||||
echo "→ Recarregando Nginx..."
|
||||
nginx -t && nginx -s reload
|
||||
fi
|
||||
|
||||
if [ "$KEEP_FILES" = "--keep-files" ]; then
|
||||
echo "→ Arquivos mantidos em $PROJECTS_DIR/$TARGET"
|
||||
else
|
||||
if [ -d "$PROJECTS_DIR/$TARGET" ]; then
|
||||
echo "→ Removendo arquivos do projeto..."
|
||||
rm -rf "$PROJECTS_DIR/$TARGET"
|
||||
echo "✓ Pasta removida"
|
||||
else
|
||||
echo "⚠ Pasta não encontrada"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✓ Projeto $TARGET removido."
|
||||
31
scripts/start.sh
Normal file
31
scripts/start.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
PROJECTS_DIR="${PROJECTS_DIR:-/home/deploy/projects}"
|
||||
AUTO_DEPLOY_ON_START="${AUTO_DEPLOY_ON_START:-false}"
|
||||
|
||||
echo "================================================"
|
||||
echo " Laravel Stack — Iniciando..."
|
||||
echo "================================================"
|
||||
|
||||
mkdir -p "$PROJECTS_DIR" /etc/nginx/sites-dynamic /run/nginx /var/log/nginx
|
||||
|
||||
echo "→ Verificando projetos em $PROJECTS_DIR"
|
||||
|
||||
if [ "$AUTO_DEPLOY_ON_START" = "true" ]; then
|
||||
echo "→ AUTO_DEPLOY_ON_START=true, rodando deploy de todos os projetos..."
|
||||
/home/deploy/scripts/deploy.sh || true
|
||||
else
|
||||
echo "→ AUTO_DEPLOY_ON_START=false, apenas recriando configs Nginx existentes..."
|
||||
/home/deploy/scripts/deploy.sh --nginx-only || true
|
||||
fi
|
||||
|
||||
echo "→ Testando Nginx..."
|
||||
nginx -t
|
||||
|
||||
echo "================================================"
|
||||
echo " Stack pronta!"
|
||||
echo " Acesse: ${PUBLIC_BASE_URL:-http://${DOMAIN:-localhost}}/<projeto>"
|
||||
echo "================================================"
|
||||
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
64
scripts/status.sh
Normal file
64
scripts/status.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
PROJECTS_DIR="${PROJECTS_DIR:-/home/deploy/projects}"
|
||||
PUBLIC_BASE_URL="${PUBLIC_BASE_URL:-http://${DOMAIN:-localhost}}"
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Laravel Stack — Status dos Projetos"
|
||||
echo "================================================"
|
||||
|
||||
if [ ! -d "$PROJECTS_DIR" ]; then
|
||||
echo "✗ Pasta $PROJECTS_DIR não encontrada"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
found=0
|
||||
|
||||
for project_dir in "$PROJECTS_DIR"/*/; do
|
||||
[ -d "$project_dir" ] || continue
|
||||
project="$(basename "$project_dir")"
|
||||
type="$(cat "$project_dir/.project-type" 2>/dev/null || echo '?')"
|
||||
nginx_file="/etc/nginx/sites-dynamic/${project}.conf"
|
||||
|
||||
found=$((found + 1))
|
||||
|
||||
if [ -f "$project_dir/artisan" ]; then
|
||||
laravel="✓"
|
||||
else
|
||||
laravel="✗"
|
||||
fi
|
||||
|
||||
if [ -f "$project_dir/vendor/autoload.php" ]; then
|
||||
vendor="✓"
|
||||
else
|
||||
vendor="✗"
|
||||
fi
|
||||
|
||||
if [ -d "$project_dir/public/build" ]; then
|
||||
build="✓"
|
||||
elif [ -f "$project_dir/package.json" ]; then
|
||||
build="✗"
|
||||
else
|
||||
build="-"
|
||||
fi
|
||||
|
||||
if [ -f "$nginx_file" ]; then
|
||||
nginx="✓"
|
||||
else
|
||||
nginx="✗"
|
||||
fi
|
||||
|
||||
echo "Projeto: $project"
|
||||
echo "URL: ${PUBLIC_BASE_URL%/}/$project"
|
||||
echo "Tipo: $type"
|
||||
echo "Laravel: $laravel | vendor: $vendor | build front: $build | nginx: $nginx"
|
||||
echo ""
|
||||
done
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "Nenhum projeto encontrado em $PROJECTS_DIR"
|
||||
fi
|
||||
|
||||
echo "================================================"
|
||||
echo ""
|
||||
25
supervisor/supervisord.conf
Normal file
25
supervisor/supervisord.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
|
||||
[program:php-fpm]
|
||||
command=php-fpm -F
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:nginx]
|
||||
command=nginx -g "daemon off;"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=20
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
Reference in New Issue
Block a user