Compare commits
4 Commits
run-gcloud
...
564719412b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
564719412b | ||
|
|
cd4c7086bf | ||
|
|
0052044d6a | ||
|
|
d6a98811eb |
@@ -1,18 +0,0 @@
|
|||||||
.git
|
|
||||||
.gitignore
|
|
||||||
.env
|
|
||||||
.env.*
|
|
||||||
.editorconfig
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.md
|
|
||||||
docker-compose.yml
|
|
||||||
Dockerfile
|
|
||||||
vendor/
|
|
||||||
node_modules/
|
|
||||||
storage/framework/cache/**
|
|
||||||
storage/framework/sessions/**
|
|
||||||
storage/framework/views/**
|
|
||||||
storage/logs/**
|
|
||||||
tests/
|
|
||||||
phpunit.xml
|
|
||||||
57
.gitea/workflows/build-push.yml
Normal file
57
.gitea/workflows/build-push.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'Docker image tag (e.g., v1.0.0, latest)'
|
||||||
|
required: false
|
||||||
|
default: 'latest'
|
||||||
|
push_to_registry:
|
||||||
|
description: 'Push to registry?'
|
||||||
|
required: false
|
||||||
|
default: 'true'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Login to Docker Registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ secrets.DOCKER_REGISTRY_URL }}
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: ${{ secrets.DOCKER_REGISTRY_URL }}/merchbay
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=raw,value=latest
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=registry,ref=${{ secrets.DOCKER_REGISTRY_URL }}/merchbay:buildcache
|
||||||
|
cache-to: type=registry,ref=${{ secrets.DOCKER_REGISTRY_URL }}/merchbay:buildcache,mode=max
|
||||||
151
.gitea/workflows/deploy-dev.yml
Normal file
151
.gitea/workflows/deploy-dev.yml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
name: Deploy Development
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# 1️⃣ Checkout code
|
||||||
|
- name: Checkout code
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo
|
||||||
|
cd /workspace/repo
|
||||||
|
git checkout $GITHUB_REF_NAME
|
||||||
|
|
||||||
|
# 2️⃣ Build image
|
||||||
|
- name: Build Docker image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
cd /workspace/repo
|
||||||
|
docker build -t merchbay:dev .
|
||||||
|
docker save merchbay:dev | gzip > merchbay_dev.tar.gz
|
||||||
|
|
||||||
|
# 3️⃣ Setup SSH
|
||||||
|
- name: Setup SSH
|
||||||
|
shell: sh
|
||||||
|
env:
|
||||||
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
# 4️⃣ Upload artifacts
|
||||||
|
- name: Upload image and compose
|
||||||
|
shell: sh
|
||||||
|
env:
|
||||||
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
run: |
|
||||||
|
scp -i ~/.ssh/id_ed25519 \
|
||||||
|
/workspace/repo/merchbay_dev.tar.gz \
|
||||||
|
/workspace/repo/docker-compose.yml \
|
||||||
|
${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/
|
||||||
|
|
||||||
|
# 5️⃣ Deploy on server
|
||||||
|
- name: Deploy on server
|
||||||
|
shell: sh
|
||||||
|
env:
|
||||||
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
|
||||||
|
run: |
|
||||||
|
ssh -i ~/.ssh/id_ed25519 $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
|
||||||
|
set -e
|
||||||
|
|
||||||
|
DEPLOY_DIR="/var/www/apps/merchbay_dev"
|
||||||
|
mkdir -p "$DEPLOY_DIR"
|
||||||
|
|
||||||
|
echo "📦 Loading image"
|
||||||
|
docker load < /tmp/merchbay_dev.tar.gz
|
||||||
|
|
||||||
|
echo "📄 Updating compose file"
|
||||||
|
cp /tmp/docker-compose.yml "$DEPLOY_DIR/"
|
||||||
|
|
||||||
|
cd "$DEPLOY_DIR"
|
||||||
|
|
||||||
|
echo "🔍 Checking .env file"
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo "❌ .env file not found at $DEPLOY_DIR/.env"
|
||||||
|
echo "Please create it first with required variables:"
|
||||||
|
echo " - DB_*, PROD_PRIVATE, IMAGES_URL, UPLOAD_URL"
|
||||||
|
echo " - MAIL_*, CAPTCHA_*, ANALYTICS_*"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔧 Fixing .env permissions"
|
||||||
|
sudo chown $USER:$USER .env
|
||||||
|
sudo chmod 600 .env
|
||||||
|
|
||||||
|
echo "🌐 Ensure networks"
|
||||||
|
docker network inspect traefik-public >/dev/null 2>&1 || \
|
||||||
|
docker network create traefik-public
|
||||||
|
docker network inspect crew-app-net >/dev/null 2>&1 || \
|
||||||
|
docker network create crew-app-net
|
||||||
|
|
||||||
|
echo "🚀 Starting containers (env vars from .env file)"
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
echo "⏳ Waiting for app container"
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
if docker ps --format '{{.Names}}' | grep -q merchbay_app; then
|
||||||
|
echo "🧹 Clearing and rebuilding config cache"
|
||||||
|
docker compose exec -T app php artisan config:clear
|
||||||
|
docker compose exec -T app php artisan config:cache
|
||||||
|
else
|
||||||
|
echo "❌ App container not running"
|
||||||
|
docker compose logs
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🧹 Cleanup"
|
||||||
|
rm -f /tmp/merchbay_dev.tar.gz /tmp/docker-compose.yml
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
echo "✅ Deployment completed"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
# 6️⃣ Health check
|
||||||
|
- name: Health check
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
echo "⏳ Waiting for app to be ready..."
|
||||||
|
sleep 20
|
||||||
|
|
||||||
|
echo "🔍 Testing health check (ignoring SSL cert for now)..."
|
||||||
|
HTTP_CODE=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 30 https://dev.merchbay.app || echo "000")
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "301" ]; then
|
||||||
|
echo "✅ Health check passed! (HTTP $HTTP_CODE)"
|
||||||
|
echo "⚠️ Note: Using -k to ignore SSL cert. Check Traefik logs if cert not ready."
|
||||||
|
else
|
||||||
|
echo "❌ Health check failed! (HTTP $HTTP_CODE)"
|
||||||
|
echo ""
|
||||||
|
echo "💡 Troubleshooting:"
|
||||||
|
echo " 1. Check if container is running:"
|
||||||
|
echo " docker ps | grep merchbay_app"
|
||||||
|
echo ""
|
||||||
|
echo " 2. Check app logs:"
|
||||||
|
echo " docker logs merchbay_app"
|
||||||
|
echo ""
|
||||||
|
echo " 3. Check Traefik logs:"
|
||||||
|
echo " docker logs traefik"
|
||||||
|
echo ""
|
||||||
|
echo " 4. Test manually:"
|
||||||
|
echo " curl -Ik https://dev.merchbay.app"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
82
.gitea/workflows/deploy.yml
Normal file
82
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: Deploy Production
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: catthehacker/ubuntu:act-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git /workspace/repo || true
|
||||||
|
cd /workspace/repo
|
||||||
|
git fetch origin $GITHUB_REF_NAME
|
||||||
|
git checkout $GITHUB_REF_NAME
|
||||||
|
git pull origin $GITHUB_REF_NAME
|
||||||
|
|
||||||
|
- name: Build Docker Image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
cd /workspace/repo
|
||||||
|
docker build -t merchbay:latest .
|
||||||
|
docker save merchbay:latest | gzip > merchbay.tar.gz
|
||||||
|
|
||||||
|
- name: Setup SSH and Deploy
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
echo "$PROD_DEPLOY_SSH_KEY" > ~/.ssh/deploy_key
|
||||||
|
chmod 600 ~/.ssh/deploy_key
|
||||||
|
ssh-keygen -y -f ~/.ssh/deploy_key > /dev/null 2>&1 || { echo "Error: Invalid SSH key format"; exit 1; }
|
||||||
|
|
||||||
|
cd /workspace/repo
|
||||||
|
scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key merchbay.tar.gz docker-compose.yml "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST:/tmp/"
|
||||||
|
|
||||||
|
ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key "$PROD_DEPLOY_USER@$PROD_DEPLOY_HOST" "
|
||||||
|
DEPLOY_DIR='/var/www/merchbay'
|
||||||
|
mkdir -p \$DEPLOY_DIR
|
||||||
|
cd /tmp
|
||||||
|
docker load < merchbay.tar.gz
|
||||||
|
cp docker-compose.yml \$DEPLOY_DIR/
|
||||||
|
cd \$DEPLOY_DIR
|
||||||
|
|
||||||
|
# .env file should already exist on server with all required variables
|
||||||
|
# Required: DB_*, PROD_PRIVATE, IMAGES_URL, UPLOAD_URL
|
||||||
|
# Required: MAIL_*, CAPTCHA_*, ANALYTICS_*
|
||||||
|
# If it doesn't exist, deployment will fail (this is intentional for security)
|
||||||
|
|
||||||
|
docker compose down || true
|
||||||
|
docker image prune -f
|
||||||
|
docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public
|
||||||
|
export DOMAIN=merchbay.app
|
||||||
|
export APP_URL=https://merchbay.app
|
||||||
|
docker compose up -d
|
||||||
|
sleep 10
|
||||||
|
docker compose exec -T app php artisan migrate --force
|
||||||
|
docker compose exec -T app php artisan config:cache
|
||||||
|
docker compose exec -T app php artisan route:cache
|
||||||
|
docker compose exec -T app php artisan view:cache
|
||||||
|
rm -f /tmp/merchbay.tar.gz /tmp/docker-compose.yml
|
||||||
|
echo 'Production deployment completed successfully!'
|
||||||
|
echo 'Application available at: https://merchbay.app'
|
||||||
|
"
|
||||||
|
env:
|
||||||
|
PROD_DEPLOY_SSH_KEY: ${{ secrets.PROD_DEPLOY_SSH_KEY }}
|
||||||
|
PROD_DEPLOY_USER: ${{ secrets.PROD_DEPLOY_USER }}
|
||||||
|
PROD_DEPLOY_HOST: ${{ secrets.PROD_DEPLOY_HOST }}
|
||||||
|
|
||||||
|
- name: Health Check
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
sleep 10
|
||||||
|
curl -f https://merchbay.app || exit 1
|
||||||
138
Dockerfile
138
Dockerfile
@@ -1,81 +1,81 @@
|
|||||||
# Build stage
|
# Use PHP 7.3 with Apache (compatible with Laravel 5.0)
|
||||||
FROM php:5.6-fpm-alpine as composer
|
FROM php:7.3-apache
|
||||||
|
|
||||||
# Install system dependencies and PHP extensions required for Composer
|
# Install system dependencies
|
||||||
RUN apk add --no-cache \
|
RUN apt-get update && apt-get install -y \
|
||||||
git \
|
git \
|
||||||
curl \
|
curl \
|
||||||
|
libpng-dev \
|
||||||
|
libonig-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libzip-dev \
|
||||||
zip \
|
zip \
|
||||||
unzip \
|
unzip \
|
||||||
libmcrypt \
|
libfreetype6-dev \
|
||||||
libmcrypt-dev \
|
libjpeg62-turbo-dev \
|
||||||
zlib-dev \
|
openssh-client \
|
||||||
libzip-dev \
|
|
||||||
autoconf \
|
|
||||||
make \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
&& docker-php-ext-install mcrypt mbstring zip \
|
|
||||||
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
|
|
||||||
&& composer self-update --1
|
|
||||||
|
|
||||||
ENV COMPOSER_ALLOW_SUPERUSER=1
|
|
||||||
WORKDIR /app
|
|
||||||
COPY composer.* ./
|
|
||||||
|
|
||||||
# Install dependencies with Composer (optimize later after full copy)
|
|
||||||
RUN composer config platform.php 5.6.40 \
|
|
||||||
&& composer install --prefer-dist --no-dev --no-scripts --no-autoloader
|
|
||||||
|
|
||||||
# Copy the rest of the application and optimize autoload
|
|
||||||
COPY . .
|
|
||||||
RUN composer dump-autoload --optimize --no-dev --classmap-authoritative
|
|
||||||
|
|
||||||
# Production stage
|
|
||||||
FROM php:5.6-fpm-alpine
|
|
||||||
|
|
||||||
# Install runtime dependencies & build PHP extensions
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
nginx \
|
|
||||||
curl \
|
|
||||||
libpng \
|
|
||||||
libjpeg-turbo \
|
|
||||||
freetype \
|
|
||||||
libzip \
|
|
||||||
libmcrypt \
|
|
||||||
zlib \
|
|
||||||
&& apk add --no-cache --virtual .build-deps \
|
|
||||||
autoconf make gcc g++ \
|
|
||||||
libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev libmcrypt-dev zlib-dev \
|
|
||||||
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
||||||
&& docker-php-ext-install -j"$(nproc)" gd pdo pdo_mysql zip mcrypt mbstring opcache \
|
&& docker-php-ext-install -j$(nproc) gd
|
||||||
&& docker-php-ext-enable mcrypt \
|
|
||||||
&& apk del .build-deps \
|
|
||||||
&& php -m | grep -i mcrypt
|
|
||||||
|
|
||||||
# Configure PHP for production
|
# Install PHP extensions
|
||||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
|
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath zip tokenizer
|
||||||
&& echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini \
|
|
||||||
&& echo "opcache.memory_consumption=128" >> /usr/local/etc/php/conf.d/opcache.ini \
|
|
||||||
&& echo "opcache.interned_strings_buffer=8" >> /usr/local/etc/php/conf.d/opcache.ini \
|
|
||||||
&& echo "opcache.max_accelerated_files=4000" >> /usr/local/etc/php/conf.d/opcache.ini \
|
|
||||||
&& echo "opcache.revalidate_freq=60" >> /usr/local/etc/php/conf.d/opcache.ini \
|
|
||||||
&& echo "opcache.fast_shutdown=1" >> /usr/local/etc/php/conf.d/opcache.ini
|
|
||||||
|
|
||||||
WORKDIR /var/www
|
# Install mcrypt via PECL (required for Laravel 5.0)
|
||||||
|
RUN apt-get install -y libmcrypt-dev \
|
||||||
|
&& pecl install mcrypt-1.0.4 \
|
||||||
|
&& docker-php-ext-enable mcrypt
|
||||||
|
|
||||||
# Copy vendor & app code from build stage
|
# Enable Apache mod_rewrite
|
||||||
COPY --from=composer /app/vendor ./vendor
|
RUN a2enmod rewrite
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Set appropriate permissions and create required directories
|
# Install Composer (version 1.x for better compatibility with Laravel 5.0)
|
||||||
RUN chown -R www-data:www-data storage bootstrap \
|
COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer
|
||||||
&& mkdir -p /run/php \
|
|
||||||
&& chown www-data:www-data /run/php \
|
|
||||||
&& php artisan key:generate || true
|
|
||||||
|
|
||||||
# Healthcheck (FPM listens on 9000; adjust as needed if behind nginx)
|
# Set working directory
|
||||||
HEALTHCHECK --interval=30s --timeout=5s CMD php -m > /dev/null || exit 1
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
EXPOSE 9000
|
# Copy existing application directory contents
|
||||||
CMD ["php-fpm"]
|
COPY . /var/www/html
|
||||||
|
|
||||||
|
# Create storage directories and set permissions
|
||||||
|
RUN mkdir -p storage/framework/views \
|
||||||
|
storage/framework/cache \
|
||||||
|
storage/framework/sessions \
|
||||||
|
storage/logs \
|
||||||
|
bootstrap/cache
|
||||||
|
|
||||||
|
# Set proper ownership and permissions
|
||||||
|
RUN chown -R www-data:www-data /var/www/html \
|
||||||
|
&& chmod -R 775 /var/www/html/storage \
|
||||||
|
&& chmod -R 775 /var/www/html/bootstrap/cache
|
||||||
|
|
||||||
|
# Create .env file if it doesn't exist
|
||||||
|
RUN if [ ! -f .env ]; then cp .env.example .env; fi
|
||||||
|
|
||||||
|
# Install PHP dependencies (Laravel 5.0 compatible)
|
||||||
|
RUN composer install --no-dev --no-interaction --prefer-dist
|
||||||
|
|
||||||
|
# Generate application key
|
||||||
|
RUN php artisan key:generate || true
|
||||||
|
|
||||||
|
# Run Laravel 5.0 optimization
|
||||||
|
RUN php artisan clear-compiled && php artisan optimize
|
||||||
|
|
||||||
|
# Configure Apache DocumentRoot to point to Laravel's public directory
|
||||||
|
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
|
||||||
|
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
|
||||||
|
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
|
||||||
|
|
||||||
|
# Suppress Apache ServerName warning
|
||||||
|
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
|
||||||
|
|
||||||
|
# Copy entrypoint script
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Use entrypoint to set up permissions before starting Apache
|
||||||
|
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||||
|
CMD ["apache2-foreground"]
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
# Combined image for Cloud Run: nginx + php-fpm (PHP 5.6) for legacy Laravel 5
|
|
||||||
# NOTE: PHP 5.6 is EOL; use only for legacy maintenance. Consider upgrading.
|
|
||||||
|
|
||||||
FROM php:5.6-fpm
|
|
||||||
|
|
||||||
# Set build args/env
|
|
||||||
ARG APP_ENV=production
|
|
||||||
ENV APP_ENV=${APP_ENV} \
|
|
||||||
APP_DEBUG=false \
|
|
||||||
OPCACHE_VALIDATE_TIMESTAMPS=0 \
|
|
||||||
COMPOSER_ALLOW_SUPERUSER=1 \
|
|
||||||
PORT=8080 \
|
|
||||||
PATH="/var/www/artisan:$PATH"
|
|
||||||
|
|
||||||
WORKDIR /var/www
|
|
||||||
|
|
||||||
# Install system deps (Debian variant easier than alpine for mixed services)
|
|
||||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
git curl unzip zip supervisor nginx \
|
|
||||||
libmcrypt4 libmcrypt-dev \
|
|
||||||
libpng-dev libjpeg62-turbo-dev libfreetype6-dev libzip-dev zlib1g-dev \
|
|
||||||
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
|
||||||
&& docker-php-ext-install gd mcrypt mbstring pdo pdo_mysql zip opcache \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Composer (v1)
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
|
|
||||||
&& composer self-update --1
|
|
||||||
|
|
||||||
# Copy composer files & install deps first (cache layer)
|
|
||||||
COPY composer.* ./
|
|
||||||
RUN composer config platform.php 5.6.40 \
|
|
||||||
&& composer install --no-dev --no-scripts --no-autoloader --prefer-dist
|
|
||||||
|
|
||||||
# Copy application code
|
|
||||||
COPY . .
|
|
||||||
RUN composer dump-autoload --optimize --no-dev --classmap-authoritative || true
|
|
||||||
|
|
||||||
# Nginx config
|
|
||||||
COPY cloudrun/nginx.conf /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
# Supervisord config
|
|
||||||
COPY cloudrun/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
|
||||||
|
|
||||||
# Remove default nginx site configs if present
|
|
||||||
RUN rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf || true
|
|
||||||
|
|
||||||
# Create runtime dirs
|
|
||||||
RUN mkdir -p /run/php /var/log/supervisor /var/www/storage /var/www/bootstrap/cache \
|
|
||||||
&& chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache
|
|
||||||
|
|
||||||
# PHP production ini tweaks
|
|
||||||
RUN { \
|
|
||||||
echo "opcache.enable=1"; \
|
|
||||||
echo "opcache.memory_consumption=128"; \
|
|
||||||
echo "opcache.interned_strings_buffer=8"; \
|
|
||||||
echo "opcache.max_accelerated_files=4000"; \
|
|
||||||
echo "opcache.revalidate_freq=60"; \
|
|
||||||
echo "opcache.fast_shutdown=1"; \
|
|
||||||
echo "date.timezone=UTC"; \
|
|
||||||
} > /usr/local/etc/php/conf.d/zz-custom.ini
|
|
||||||
|
|
||||||
# Generate app key if missing (non-fatal if artisan fails early)
|
|
||||||
RUN php artisan key:generate || true
|
|
||||||
|
|
||||||
# Cloud Run listens on $PORT
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
# Health check path suggestion: /healthz (configure in Cloud Run if desired)
|
|
||||||
|
|
||||||
# Start supervisor (manages php-fpm + nginx)
|
|
||||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
user nginx;
|
|
||||||
worker_processes auto;
|
|
||||||
error_log /dev/stderr warn;
|
|
||||||
pid /var/run/nginx.pid;
|
|
||||||
|
|
||||||
events { worker_connections 1024; }
|
|
||||||
|
|
||||||
http {
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
access_log /dev/stdout main;
|
|
||||||
sendfile on;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
server_tokens off;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 8080 default_server;
|
|
||||||
listen [::]:8080 default_server;
|
|
||||||
root /var/www/public;
|
|
||||||
index index.php index.html;
|
|
||||||
|
|
||||||
location /healthz { return 200 'ok'; add_header Content-Type text/plain; }
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.php?$query_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.php$ {
|
|
||||||
include fastcgi_params;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
fastcgi_pass 127.0.0.1:9000; # php-fpm
|
|
||||||
fastcgi_index index.php;
|
|
||||||
fastcgi_buffers 16 16k;
|
|
||||||
fastcgi_buffer_size 32k;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
|
||||||
expires 30d;
|
|
||||||
access_log off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
[supervisord]
|
|
||||||
nodaemon=true
|
|
||||||
logfile=/dev/stdout
|
|
||||||
logfile_maxbytes=0
|
|
||||||
|
|
||||||
[program:php-fpm]
|
|
||||||
command=/usr/sbin/php-fpm5.6 -F
|
|
||||||
priority=10
|
|
||||||
autostart=true
|
|
||||||
autorestart=true
|
|
||||||
stdout_logfile=/dev/stdout
|
|
||||||
stdout_logfile_maxbytes=0
|
|
||||||
stderr_logfile=/dev/stderr
|
|
||||||
stderr_logfile_maxbytes=0
|
|
||||||
|
|
||||||
[program:nginx]
|
|
||||||
command=/usr/sbin/nginx -g 'daemon off;'
|
|
||||||
priority=20
|
|
||||||
autostart=true
|
|
||||||
autorestart=true
|
|
||||||
stdout_logfile=/dev/stdout
|
|
||||||
stdout_logfile_maxbytes=0
|
|
||||||
stderr_logfile=/dev/stderr
|
|
||||||
stderr_logfile_maxbytes=0
|
|
||||||
@@ -1,74 +1,56 @@
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
#PHP Service
|
|
||||||
app:
|
app:
|
||||||
build:
|
image: merchbay:dev
|
||||||
context: .
|
container_name: merchbay_app
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
- APP_ENV=production
|
|
||||||
image: digitalocean.com/php
|
|
||||||
container_name: app
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: '0.50'
|
|
||||||
memory: 512M
|
|
||||||
reservations:
|
|
||||||
cpus: '0.25'
|
|
||||||
memory: 256M
|
|
||||||
environment:
|
environment:
|
||||||
APP_ENV: production
|
- APP_ENV=${APP_ENV:-production}
|
||||||
APP_DEBUG: 'false'
|
- APP_DEBUG=${APP_DEBUG:-false}
|
||||||
PHP_OPCACHE_VALIDATE_TIMESTAMPS: 0
|
- APP_URL=${APP_URL:-http://localhost}
|
||||||
working_dir: /var/www
|
- DB_CONNECTION=mysql
|
||||||
|
- DB_HOST=${DB_HOST}
|
||||||
|
- DB_PORT=${DB_PORT:-3306}
|
||||||
|
- DB_DATABASE=${DB_DATABASE}
|
||||||
|
- DB_USERNAME=${DB_USERNAME}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD}
|
||||||
|
- PROD_PRIVATE=${PROD_PRIVATE}
|
||||||
|
- IMAGES_URL=${IMAGES_URL}
|
||||||
|
- UPLOAD_URL=${UPLOAD_URL}
|
||||||
|
- MAIL_DRIVER=${MAIL_DRIVER}
|
||||||
|
- MAIL_HOST=${MAIL_HOST}
|
||||||
|
- MAIL_PORT=${MAIL_PORT}
|
||||||
|
- MAIL_USERNAME=${MAIL_USERNAME}
|
||||||
|
- MAIL_PASSWORD=${MAIL_PASSWORD}
|
||||||
|
- MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
|
||||||
|
- CAPTCHA_SITE_KEY=${CAPTCHA_SITE_KEY}
|
||||||
|
- CAPTCHA_SECRET_KEY=${CAPTCHA_SECRET_KEY}
|
||||||
|
- ANALYTICS_SITE_ID=${ANALYTICS_SITE_ID}
|
||||||
|
- ANALYTICS_CLIENT_ID=${ANALYTICS_CLIENT_ID}
|
||||||
|
- ANALYTICS_SERVICE_EMAIL=${ANALYTICS_SERVICE_EMAIL}
|
||||||
volumes:
|
volumes:
|
||||||
- ./storage:/var/www/storage
|
- ./storage:/var/www/html/storage
|
||||||
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
|
- ./public/uploads:/var/www/html/public/uploads
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.merchbay-dev.rule=Host(`dev.merchbay.app`)"
|
||||||
|
- "traefik.http.routers.merchbay-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.merchbay-dev.tls=true"
|
||||||
|
- "traefik.http.routers.merchbay-dev.tls.certresolver=le"
|
||||||
|
- "traefik.http.services.merchbay-dev.loadbalancer.server.port=80"
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.routers.merchbay-dev-http.rule=Host(`dev.merchbay.app`)"
|
||||||
|
- "traefik.http.routers.merchbay-dev-http.entrypoints=web"
|
||||||
|
- "traefik.http.routers.merchbay-dev-http.middlewares=https-redirect"
|
||||||
|
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- traefik-public
|
||||||
healthcheck:
|
- crew-app-net
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:9000/"]
|
- default
|
||||||
interval: 30s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
#Nginx Service
|
|
||||||
webserver:
|
|
||||||
image: nginx:alpine
|
|
||||||
container_name: webserver
|
|
||||||
restart: unless-stopped
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: '0.30'
|
|
||||||
memory: 256M
|
|
||||||
reservations:
|
|
||||||
cpus: '0.10'
|
|
||||||
memory: 128M
|
|
||||||
ports:
|
|
||||||
- "10003:80"
|
|
||||||
- "10443:443"
|
|
||||||
volumes:
|
|
||||||
- ./public:/var/www/public
|
|
||||||
- ./nginx/conf.d/:/etc/nginx/conf.d/
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:80/"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 3
|
|
||||||
depends_on:
|
|
||||||
app:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
#Docker Networks
|
|
||||||
networks:
|
networks:
|
||||||
app-network:
|
traefik-public:
|
||||||
driver: bridge
|
external: true
|
||||||
#Volumes
|
crew-app-net:
|
||||||
volumes:
|
external: true
|
||||||
dbdata:
|
default:
|
||||||
driver: local
|
driver: bridge
|
||||||
17
docker-entrypoint.sh
Normal file
17
docker-entrypoint.sh
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Create storage directory structure if it doesn't exist
|
||||||
|
mkdir -p storage/framework/views
|
||||||
|
mkdir -p storage/framework/cache
|
||||||
|
mkdir -p storage/framework/sessions
|
||||||
|
mkdir -p storage/logs
|
||||||
|
mkdir -p storage/app/public
|
||||||
|
mkdir -p bootstrap/cache
|
||||||
|
|
||||||
|
# Set proper permissions
|
||||||
|
chown -R www-data:www-data storage bootstrap/cache
|
||||||
|
chmod -R 775 storage bootstrap/cache
|
||||||
|
|
||||||
|
# Execute the main command
|
||||||
|
exec "$@"
|
||||||
@@ -1,30 +1,9 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_tokens off;
|
index index.php index.html;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
# Compression
|
access_log /var/log/nginx/access.log;
|
||||||
gzip on;
|
root /var/www;
|
||||||
gzip_comp_level 5;
|
|
||||||
gzip_min_length 256;
|
|
||||||
gzip_proxied any;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_types
|
|
||||||
application/javascript
|
|
||||||
application/json
|
|
||||||
application/x-javascript
|
|
||||||
application/xml
|
|
||||||
text/css
|
|
||||||
text/javascript
|
|
||||||
text/plain
|
|
||||||
text/xml;
|
|
||||||
|
|
||||||
client_max_body_size 100M;
|
|
||||||
fastcgi_read_timeout 1800;
|
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log warn;
|
|
||||||
access_log /var/log/nginx/access.log combined buffer=512k flush=1m;
|
|
||||||
|
|
||||||
root /var/www/public;
|
|
||||||
index index.php index.html;
|
index index.php index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
|||||||
68
run.sh
68
run.sh
@@ -1,68 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Helper script for docker compose workflow
|
|
||||||
# Usage examples:
|
|
||||||
# ./run.sh up # build (if needed) and start in background
|
|
||||||
# ./run.sh rebuild # force full rebuild (no cache) and start
|
|
||||||
# ./run.sh down # stop and remove containers
|
|
||||||
# ./run.sh logs # follow logs
|
|
||||||
# ./run.sh artisan migrate
|
|
||||||
# ./run.sh sh # shell into PHP app container
|
|
||||||
# ./run.sh restart # restart containers
|
|
||||||
# ./run.sh build # build images (uses cache)
|
|
||||||
|
|
||||||
CMD=${1:-up}
|
|
||||||
shift || true
|
|
||||||
|
|
||||||
case "$CMD" in
|
|
||||||
build)
|
|
||||||
echo "[build] Building images (with cache)..."
|
|
||||||
docker compose build
|
|
||||||
;;
|
|
||||||
up)
|
|
||||||
echo "[up] Starting services (build if needed)..."
|
|
||||||
docker compose up -d --build
|
|
||||||
;;
|
|
||||||
rebuild)
|
|
||||||
echo "[rebuild] Full rebuild without cache..."
|
|
||||||
docker compose down || true
|
|
||||||
docker compose build --no-cache
|
|
||||||
docker compose up -d
|
|
||||||
;;
|
|
||||||
down)
|
|
||||||
echo "[down] Stopping and removing services..."
|
|
||||||
docker compose down
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
echo "[restart] Restarting services..."
|
|
||||||
docker compose restart
|
|
||||||
;;
|
|
||||||
logs)
|
|
||||||
echo "[logs] Following logs (Ctrl+C to exit)..."
|
|
||||||
docker compose logs -f --tail=200 "$@"
|
|
||||||
;;
|
|
||||||
artisan)
|
|
||||||
echo "[artisan] php artisan $*"
|
|
||||||
docker compose exec app php artisan "$@"
|
|
||||||
;;
|
|
||||||
sh)
|
|
||||||
echo "[sh] Opening shell in app container..."
|
|
||||||
docker compose exec app sh
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
cat <<EOF
|
|
||||||
Usage: ./run.sh <command> [args]
|
|
||||||
Commands:
|
|
||||||
up Build (if needed) and start containers
|
|
||||||
build Build images using cache
|
|
||||||
rebuild Rebuild images without cache then start
|
|
||||||
down Stop and remove containers
|
|
||||||
restart Restart running containers
|
|
||||||
logs Follow logs (pass service names optionally)
|
|
||||||
artisan Run php artisan <args>
|
|
||||||
sh Shell into app container
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
Reference in New Issue
Block a user