Compare commits
6 Commits
run-gcloud
...
0a235a0ed2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a235a0ed2 | ||
|
|
c950a72fc8 | ||
|
|
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
|
||||
137
Dockerfile
137
Dockerfile
@@ -1,81 +1,80 @@
|
||||
# Build stage
|
||||
FROM php:5.6-fpm-alpine as composer
|
||||
# Use PHP 7.0 with Apache (has native mcrypt support for Laravel 5.0)
|
||||
FROM php:7.0-apache
|
||||
|
||||
# Install system dependencies and PHP extensions required for Composer
|
||||
RUN apk add --no-cache \
|
||||
# Update to use archived Debian repositories
|
||||
RUN sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list \
|
||||
&& sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list \
|
||||
&& sed -i '/stretch-updates/d' /etc/apt/sources.list
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y --allow-unauthenticated \
|
||||
git \
|
||||
curl \
|
||||
libpng-dev \
|
||||
libxml2-dev \
|
||||
libmcrypt-dev \
|
||||
zip \
|
||||
unzip \
|
||||
libmcrypt \
|
||||
libmcrypt-dev \
|
||||
zlib-dev \
|
||||
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 \
|
||||
libfreetype6-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
openssh-client \
|
||||
&& 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-enable mcrypt \
|
||||
&& apk del .build-deps \
|
||||
&& php -m | grep -i mcrypt
|
||||
&& docker-php-ext-install -j$(nproc) gd
|
||||
|
||||
# Configure PHP for production
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
|
||||
&& 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
|
||||
# Install PHP extensions (mcrypt is built-in for PHP 7.0)
|
||||
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath mcrypt tokenizer zip
|
||||
|
||||
WORKDIR /var/www
|
||||
# Enable Apache mod_rewrite
|
||||
RUN a2enmod rewrite
|
||||
|
||||
# Copy vendor & app code from build stage
|
||||
COPY --from=composer /app/vendor ./vendor
|
||||
COPY . .
|
||||
# Install Composer (version 1.x for better compatibility with Laravel 5.0)
|
||||
COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# Set appropriate permissions and create required directories
|
||||
RUN chown -R www-data:www-data storage bootstrap \
|
||||
&& mkdir -p /run/php \
|
||||
&& chown www-data:www-data /run/php \
|
||||
&& php artisan key:generate || true
|
||||
# Set working directory
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Healthcheck (FPM listens on 9000; adjust as needed if behind nginx)
|
||||
HEALTHCHECK --interval=30s --timeout=5s CMD php -m > /dev/null || exit 1
|
||||
# Copy existing application directory contents
|
||||
COPY . /var/www/html
|
||||
|
||||
EXPOSE 9000
|
||||
CMD ["php-fpm"]
|
||||
# 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:
|
||||
|
||||
#PHP Service
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- APP_ENV=production
|
||||
image: digitalocean.com/php
|
||||
container_name: app
|
||||
image: merchbay:dev
|
||||
container_name: merchbay_app
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.50'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_DEBUG: 'false'
|
||||
PHP_OPCACHE_VALIDATE_TIMESTAMPS: 0
|
||||
working_dir: /var/www
|
||||
- APP_ENV=${APP_ENV:-production}
|
||||
- APP_DEBUG=${APP_DEBUG:-false}
|
||||
- APP_URL=${APP_URL:-http://localhost}
|
||||
- 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:
|
||||
- ./storage:/var/www/storage
|
||||
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
|
||||
- ./storage:/var/www/html/storage
|
||||
- ./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:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/"]
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
- traefik-public
|
||||
- crew-app-net
|
||||
- default
|
||||
|
||||
#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:
|
||||
app-network:
|
||||
driver: bridge
|
||||
#Volumes
|
||||
volumes:
|
||||
dbdata:
|
||||
driver: local
|
||||
traefik-public:
|
||||
external: true
|
||||
crew-app-net:
|
||||
external: true
|
||||
default:
|
||||
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 {
|
||||
listen 80;
|
||||
server_tokens off;
|
||||
|
||||
# Compression
|
||||
gzip on;
|
||||
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;
|
||||
error_log /var/log/nginx/error.log;
|
||||
access_log /var/log/nginx/access.log;
|
||||
root /var/www;
|
||||
index index.php index.html;
|
||||
|
||||
location / {
|
||||
|
||||
176
readme.md
176
readme.md
@@ -1,23 +1,171 @@
|
||||
## Laravel PHP Framework
|
||||
# MerchBay
|
||||
|
||||
[](https://travis-ci.org/laravel/framework)
|
||||
[](https://packagist.org/packages/laravel/framework)
|
||||
[](https://packagist.org/packages/laravel/framework)
|
||||
[](https://packagist.org/packages/laravel/framework)
|
||||
[](https://packagist.org/packages/laravel/framework)
|
||||
A custom merchandise and apparel design platform built with Laravel 5.0, enabling users to create, customize, and order personalized products.
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching.
|
||||
## 🚀 Tech Stack
|
||||
|
||||
Laravel is accessible, yet powerful, providing powerful tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked.
|
||||
- **Framework:** Laravel 5.0
|
||||
- **PHP:** 7.0 with native mcrypt support
|
||||
- **Web Server:** Apache 2.4
|
||||
- **Database:** MySQL
|
||||
- **Container:** Docker with Apache
|
||||
- **Reverse Proxy:** Traefik (for SSL/TLS and routing)
|
||||
|
||||
## Official Documentation
|
||||
## 📋 Prerequisites
|
||||
|
||||
Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs).
|
||||
- Docker and Docker Compose
|
||||
- Git
|
||||
- Access to deployment server (for production/dev deployments)
|
||||
|
||||
## Contributing
|
||||
## 🛠️ Local Development
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions).
|
||||
### Building the Docker Image
|
||||
|
||||
### License
|
||||
```bash
|
||||
docker build -t merchbay:dev .
|
||||
```
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
|
||||
### Running Locally
|
||||
|
||||
```bash
|
||||
# Create .env file from example
|
||||
cp .env.example .env
|
||||
|
||||
# Update .env with your local configuration
|
||||
# Set database credentials, mail settings, etc.
|
||||
|
||||
# Run with docker-compose (customize docker-compose.yml for local setup)
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The following environment variables are required:
|
||||
|
||||
#### Database Configuration
|
||||
- `DB_HOST` - Database host
|
||||
- `DB_PORT` - Database port (default: 3306)
|
||||
- `DB_DATABASE` - Database name
|
||||
- `DB_USERNAME` - Database username
|
||||
- `DB_PASSWORD` - Database password
|
||||
|
||||
#### Application URLs
|
||||
- `APP_URL` - Application base URL
|
||||
- `PROD_PRIVATE` - Production private server URL
|
||||
- `IMAGES_URL` - Images server URL
|
||||
- `UPLOAD_URL` - Upload directory URL
|
||||
|
||||
#### Mail Configuration
|
||||
- `MAIL_DRIVER` - Mail driver (smtp)
|
||||
- `MAIL_HOST` - SMTP host
|
||||
- `MAIL_PORT` - SMTP port
|
||||
- `MAIL_USERNAME` - SMTP username
|
||||
- `MAIL_PASSWORD` - SMTP password
|
||||
- `MAIL_ENCRYPTION` - Encryption type (tls/ssl)
|
||||
|
||||
#### Third-Party Services
|
||||
- `CAPTCHA_SITE_KEY` - reCAPTCHA site key
|
||||
- `CAPTCHA_SECRET_KEY` - reCAPTCHA secret key
|
||||
- `ANALYTICS_SITE_ID` - Google Analytics site ID
|
||||
- `ANALYTICS_CLIENT_ID` - Google Analytics client ID
|
||||
- `ANALYTICS_SERVICE_EMAIL` - Google Analytics service email
|
||||
|
||||
## 🚢 Deployment
|
||||
|
||||
### Automated CI/CD with Gitea Actions
|
||||
|
||||
This project includes automated deployment workflows using Gitea Actions:
|
||||
|
||||
#### Development Deployment
|
||||
Push to the `dev` branch to automatically deploy to dev environment:
|
||||
```bash
|
||||
git push origin dev
|
||||
```
|
||||
- Deploys to: `https://dev.merchbay.app`
|
||||
|
||||
#### Production Deployment
|
||||
Push to the `main` or `master` branch to automatically deploy to production:
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
- Deploys to: `https://merchbay.app`
|
||||
|
||||
#### Docker Registry
|
||||
Create version tags to build and push to Docker registry:
|
||||
```bash
|
||||
git tag -a v1.0.0 -m "Release v1.0.0"
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
### Workflow Files
|
||||
|
||||
- `.gitea/workflows/deploy-dev.yml` - Development deployment
|
||||
- `.gitea/workflows/deploy.yml` - Production deployment
|
||||
- `.gitea/workflows/build-push.yml` - Docker image build and push
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
merchbay/
|
||||
├── app/ # Application core
|
||||
│ ├── Http/ # Controllers, middleware, routes
|
||||
│ ├── Models/ # Database models
|
||||
│ └── Services/ # Business logic services
|
||||
├── config/ # Configuration files
|
||||
├── database/ # Migrations and seeds
|
||||
├── public/ # Public assets (images, CSS, JS)
|
||||
├── resources/ # Views and frontend assets
|
||||
├── storage/ # Application storage
|
||||
├── docker-compose.yml # Docker compose configuration
|
||||
├── Dockerfile # Docker image definition
|
||||
└── docker-entrypoint.sh # Container startup script
|
||||
```
|
||||
|
||||
## 🔧 Development Notes
|
||||
|
||||
### Storage Permissions
|
||||
|
||||
The Docker entrypoint automatically creates and sets proper permissions for:
|
||||
- `storage/framework/views`
|
||||
- `storage/framework/cache`
|
||||
- `storage/framework/sessions`
|
||||
- `storage/logs`
|
||||
- `bootstrap/cache`
|
||||
|
||||
### PHP Extensions
|
||||
|
||||
The following PHP extensions are installed:
|
||||
- pdo_mysql
|
||||
- mbstring
|
||||
- exif
|
||||
- pcntl
|
||||
- bcmath
|
||||
- mcrypt (native in PHP 7.0)
|
||||
- tokenizer
|
||||
- zip
|
||||
- gd (with freetype and jpeg support)
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### 500 Internal Server Error
|
||||
|
||||
1. Check container logs: `docker logs merchbay_app`
|
||||
2. Verify storage permissions are set correctly
|
||||
3. Ensure all environment variables are configured in `.env`
|
||||
4. Check database connectivity
|
||||
|
||||
### Storage Permission Issues
|
||||
|
||||
The entrypoint script automatically fixes permissions on container start. If issues persist:
|
||||
```bash
|
||||
docker exec merchbay_app chown -R www-data:www-data storage bootstrap/cache
|
||||
docker exec merchbay_app chmod -R 775 storage bootstrap/cache
|
||||
```
|
||||
|
||||
## 📄 License
|
||||
|
||||
Proprietary - All rights reserved
|
||||
|
||||
## 🤝 Support
|
||||
|
||||
For support and questions, contact the development team.
|
||||
|
||||
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