mirror of https://github.com/pixelfed/pixelfed
Merge pull request #6331 from shleeable/servesideupbuild
BREAKING - Docker: Replace existing Dockerfile / docker-compose.yml - using ServerSideUp/PHP base image - Mergablepull/6335/merge
commit
002dc394b0
@ -1,30 +1,20 @@
|
||||
.DS_Store
|
||||
/.bash_history
|
||||
/.bash_profile
|
||||
/.bashrc
|
||||
/.composer
|
||||
/.env
|
||||
/.env.dottie-backup
|
||||
/.git
|
||||
/.git-credentials
|
||||
/.gitconfig
|
||||
/.gitignore
|
||||
/.idea
|
||||
/.vagrant
|
||||
/bootstrap/cache
|
||||
/docker-compose-state/
|
||||
/Homestead.json
|
||||
/Homestead.yaml
|
||||
/node_modules
|
||||
/npm-debug.log
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/vendor/horizon
|
||||
/storage/*.key
|
||||
/storage/docker
|
||||
/vendor
|
||||
/yarn-error.log
|
||||
# Folders
|
||||
.git/
|
||||
tests/
|
||||
mariadb-11-data/
|
||||
redis-data/
|
||||
node_modules/
|
||||
vendor/
|
||||
.ddev/
|
||||
|
||||
# Exceptions - these *MUST* be last
|
||||
!/bootstrap/cache/.gitignore
|
||||
!/public/vendor/horizon/.gitignore
|
||||
#Files
|
||||
.gitignore
|
||||
.env
|
||||
.env.*
|
||||
.env.example
|
||||
.env.docker.example
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
README.md
|
||||
.editorconfig
|
||||
.phpunit.result.cache
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,87 @@
|
||||
# Pixelfed Docker Environment Configuration
|
||||
# Copy this file to .env.docker and update the values
|
||||
|
||||
# Application Configuration
|
||||
APP_NAME="Pixelfed"
|
||||
APP_ENV="production"
|
||||
APP_KEY=
|
||||
APP_DEBUG="false"
|
||||
|
||||
# Instance Configuration
|
||||
OPEN_REGISTRATION="false"
|
||||
ENFORCE_EMAIL_VERIFICATION="true"
|
||||
PF_MAX_USERS="1000"
|
||||
OAUTH_ENABLED="true"
|
||||
ENABLE_CONFIG_CACHE="true"
|
||||
INSTANCE_DISCOVER_PUBLIC="true"
|
||||
|
||||
# Media Configuration
|
||||
PF_OPTIMIZE_IMAGES="true"
|
||||
IMAGE_QUALITY="80"
|
||||
MAX_PHOTO_SIZE="15000"
|
||||
MAX_CAPTION_LENGTH="500"
|
||||
MAX_ALBUM_LENGTH="4"
|
||||
|
||||
# Instance URL Configuration
|
||||
# IMPORTANT: Update these with your actual domain
|
||||
APP_URL="https://yourdomain.com"
|
||||
APP_DOMAIN="yourdomain.com"
|
||||
ADMIN_DOMAIN="yourdomain.com"
|
||||
SESSION_DOMAIN="yourdomain.com"
|
||||
TRUST_PROXIES="*"
|
||||
|
||||
# Database Configuration
|
||||
DB_CONNECTION="mysql"
|
||||
DB_HOST="db"
|
||||
DB_PORT="3306"
|
||||
DB_DATABASE="pixelfed"
|
||||
DB_USERNAME="pixelfed"
|
||||
DB_PASSWORD="change_this_secure_password"
|
||||
DB_ROOT_PASSWORD="change_this_root_password"
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_CLIENT="phpredis"
|
||||
REDIS_SCHEME="tcp"
|
||||
REDIS_HOST="redis"
|
||||
REDIS_PASSWORD="null"
|
||||
REDIS_PORT="6379"
|
||||
|
||||
# Laravel Configuration
|
||||
SESSION_DRIVER="database"
|
||||
CACHE_DRIVER="redis"
|
||||
QUEUE_DRIVER="redis"
|
||||
BROADCAST_DRIVER="log"
|
||||
LOG_CHANNEL="stack"
|
||||
HORIZON_PREFIX="horizon-"
|
||||
|
||||
# ActivityPub Configuration
|
||||
ACTIVITY_PUB="true"
|
||||
AP_REMOTE_FOLLOW="true"
|
||||
AP_INBOX="true"
|
||||
AP_OUTBOX="true"
|
||||
AP_SHAREDINBOX="true"
|
||||
|
||||
# Experimental Configuration
|
||||
EXP_EMC="true"
|
||||
|
||||
# Mail Configuration
|
||||
# Configure after initial setup
|
||||
MAIL_DRIVER="smtp"
|
||||
MAIL_HOST="smtp.mailtrap.io"
|
||||
MAIL_PORT="2525"
|
||||
MAIL_USERNAME="null"
|
||||
MAIL_PASSWORD="null"
|
||||
MAIL_ENCRYPTION="tls"
|
||||
MAIL_FROM_ADDRESS="pixelfed@yourdomain.com"
|
||||
MAIL_FROM_NAME="Pixelfed"
|
||||
|
||||
# S3 Configuration (Optional)
|
||||
PF_ENABLE_CLOUD="false"
|
||||
FILESYSTEM_CLOUD="s3"
|
||||
#AWS_ACCESS_KEY_ID=
|
||||
#AWS_SECRET_ACCESS_KEY=
|
||||
#AWS_DEFAULT_REGION=
|
||||
#AWS_BUCKET=
|
||||
#AWS_URL=
|
||||
#AWS_ENDPOINT=
|
||||
#AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
@ -1,6 +0,0 @@
|
||||
ignored:
|
||||
- DL3002 # warning: Last USER should not be root
|
||||
- DL3008 # warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
|
||||
- DL3029 # warning: Do not use --platform flag with FROM
|
||||
- SC2046 # warning: Quote this to prevent word splitting.
|
||||
- SC2086 # info: Double quote to prevent globbing and word splitting.
|
||||
@ -0,0 +1,121 @@
|
||||
# Pixelfed Docker Compose Setup with serversideup/php container
|
||||
|
||||
This setup uses `serversideup/php:8.4-fpm-nginx` as the base image and is designed to work behind a reverse proxy like Cloudflare Tunnel, or Nginx (Proxy Manager) for HTTPS termination.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- A reverse proxy (e.g., Nginx Proxy Manager) for HTTPS
|
||||
- Domain name
|
||||
- Email Provider for sending emails
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Clone and prepare the privledges**
|
||||
```bash
|
||||
git clone https://github.com/pixelfed/pixelfed
|
||||
cd pixelfed
|
||||
sudo chown -R www-data:www-data storage/ bootstrap/cache/
|
||||
```
|
||||
|
||||
1. **Copy the environment file:**
|
||||
```bash
|
||||
cp .env.docker.example .env
|
||||
```
|
||||
|
||||
2. **Update `.env` with your configuration:**
|
||||
- Set `APP_KEY` ( generate with https://laravel-encryption-key-generator.vercel.app/ )
|
||||
- Update `APP_URL`, `APP_DOMAIN`, `ADMIN_DOMAIN`, `SESSION_DOMAIN` with your domain
|
||||
- Set secure database passwords for `DB_PASSWORD` and `DB_ROOT_PASSWORD`
|
||||
- Configure mail settings
|
||||
|
||||
3. **Build container**
|
||||
```bash
|
||||
docker compose build
|
||||
```
|
||||
|
||||
4. **Build and start the containers:**
|
||||
```bash
|
||||
docker compose up -d db redis # Bootstrap the database and Redis.
|
||||
# Wait 30 seconds for them to complete first boot.
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
5. **Generate application keys (Critical for Federation) and other tasks:**
|
||||
```bash
|
||||
docker compose exec pixelfed php artisan instance:actor
|
||||
docker compose exec pixelfed php artisan import:cities
|
||||
docker compose exec pixelfed php artisan passport:keys
|
||||
```
|
||||
|
||||
6. **Create admin user:**
|
||||
```bash
|
||||
docker compose exec pixelfed php artisan user:create
|
||||
```
|
||||
|
||||
## Reverse Proxy Configuration
|
||||
|
||||
### Cloudflare Tunnel
|
||||
|
||||
1. Doco coming soon
|
||||
|
||||
### Nginx Proxy Manager
|
||||
|
||||
1. Add a new Proxy Host in Nginx Proxy Manager
|
||||
2. Set the following:
|
||||
- **Domain Names:** Your domain (e.g., `pixelfed.yourdomain.com`)
|
||||
- **Scheme:** `http`
|
||||
- **Forward Hostname/IP:** `pixelfed-app` (or the Docker host IP)
|
||||
- **Forward Port:** `8080`
|
||||
- **Enable:** Websockets Support, Block Common Exploits
|
||||
3. Configure SSL certificate (Let's Encrypt recommended)
|
||||
4. Add custom Nginx configuration if needed:
|
||||
```nginx
|
||||
client_max_body_size 500M;
|
||||
proxy_read_timeout 300s;
|
||||
```
|
||||
|
||||
### Manual Nginx Configuration
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name yourdomain.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
client_max_body_size 500M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
|
||||
# Run artisan commands
|
||||
docker compose exec pixelfed php artisan [command]
|
||||
|
||||
# Access container shell
|
||||
docker compose exec pixelfed bash
|
||||
|
||||
# Restart services
|
||||
docker compose restart
|
||||
|
||||
# Stop services
|
||||
docker compose down
|
||||
|
||||
# Stop and remove volumes (WARNING: deletes data)
|
||||
docker compose down -v
|
||||
```
|
||||
@ -1,364 +1,53 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
# See https://hub.docker.com/r/docker/dockerfile
|
||||
FROM serversideup/php:8.4-fpm-nginx
|
||||
|
||||
#######################################################
|
||||
# Configuration
|
||||
#######################################################
|
||||
|
||||
# See: https://github.com/mlocati/docker-php-extension-installer
|
||||
ARG DOCKER_PHP_EXTENSION_INSTALLER_VERSION="2.1.80"
|
||||
|
||||
# See: https://github.com/composer/composer
|
||||
ARG COMPOSER_VERSION="2.6"
|
||||
|
||||
# See: https://nginx.org/
|
||||
ARG NGINX_VERSION="1.25.3"
|
||||
|
||||
# See: https://github.com/ddollar/forego
|
||||
ARG FOREGO_VERSION="0.17.2"
|
||||
|
||||
# See: https://github.com/hairyhenderson/gomplate
|
||||
ARG GOMPLATE_VERSION="v3.11.6"
|
||||
|
||||
# See: https://github.com/jippi/dottie
|
||||
ARG DOTTIE_VERSION="v0.9.5"
|
||||
|
||||
###
|
||||
# PHP base configuration
|
||||
###
|
||||
|
||||
# See: https://hub.docker.com/_/php/tags
|
||||
ARG PHP_VERSION="8.3"
|
||||
|
||||
# See: https://github.com/docker-library/docs/blob/master/php/README.md#image-variants
|
||||
ARG PHP_BASE_TYPE="apache"
|
||||
ARG PHP_DEBIAN_RELEASE="bookworm"
|
||||
|
||||
ARG RUNTIME_UID=33 # often called 'www-data'
|
||||
ARG RUNTIME_GID=33 # often called 'www-data'
|
||||
|
||||
# APT extra packages
|
||||
ARG APT_PACKAGES_EXTRA=
|
||||
|
||||
# Extensions installed via [pecl install]
|
||||
# ! NOTE: imagick is installed from [master] branch on GitHub due to 8.3 bug on ARM that haven't
|
||||
# ! been released yet (after +10 months)!
|
||||
# ! See: https://github.com/Imagick/imagick/pull/641
|
||||
ARG PHP_PECL_EXTENSIONS="redis https://codeload.github.com/Imagick/imagick/tar.gz/28f27044e435a2b203e32675e942eb8de620ee58"
|
||||
ARG PHP_PECL_EXTENSIONS_EXTRA=
|
||||
|
||||
# Extensions installed via [docker-php-ext-install]
|
||||
ARG PHP_EXTENSIONS="intl bcmath zip pcntl exif curl gd"
|
||||
ARG PHP_EXTENSIONS_EXTRA=""
|
||||
ARG PHP_EXTENSIONS_DATABASE="pdo_pgsql pdo_mysql pdo_sqlite"
|
||||
|
||||
# GPG key for nginx apt repository
|
||||
ARG NGINX_GPGKEY="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62"
|
||||
|
||||
# GPP key path for nginx apt repository
|
||||
ARG NGINX_GPGKEY_PATH="/usr/share/keyrings/nginx-archive-keyring.gpg"
|
||||
|
||||
#######################################################
|
||||
# Docker "copy from" images
|
||||
#######################################################
|
||||
|
||||
# Composer docker image from Docker Hub
|
||||
#
|
||||
# NOTE: Docker will *not* pull this image unless it's referenced (via build target)
|
||||
FROM composer:${COMPOSER_VERSION} AS composer-image
|
||||
|
||||
# php-extension-installer image from Docker Hub
|
||||
#
|
||||
# NOTE: Docker will *not* pull this image unless it's referenced (via build target)
|
||||
FROM mlocati/php-extension-installer:${DOCKER_PHP_EXTENSION_INSTALLER_VERSION} AS php-extension-installer
|
||||
|
||||
# nginx webserver from Docker Hub.
|
||||
# Used to copy some docker-entrypoint files for [nginx-runtime]
|
||||
#
|
||||
# NOTE: Docker will *not* pull this image unless it's referenced (via build target)
|
||||
FROM nginx:${NGINX_VERSION} AS nginx-image
|
||||
|
||||
# Forego is a Procfile "runner" that makes it trival to run multiple
|
||||
# processes under a simple init / PID 1 process.
|
||||
#
|
||||
# NOTE: Docker will *not* pull this image unless it's referenced (via build target)
|
||||
#
|
||||
# See: https://github.com/nginx-proxy/forego
|
||||
FROM nginxproxy/forego:${FOREGO_VERSION}-debian AS forego-image
|
||||
|
||||
# Dottie makes working with .env files easier and safer
|
||||
#
|
||||
# NOTE: Docker will *not* pull this image unless it's referenced (via build target)
|
||||
#
|
||||
# See: https://github.com/jippi/dottie
|
||||
FROM ghcr.io/jippi/dottie:${DOTTIE_VERSION} AS dottie-image
|
||||
|
||||
# gomplate-image grabs the gomplate binary from GitHub releases
|
||||
#
|
||||
# It's in its own layer so it can be fetched in parallel with other build steps
|
||||
FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS gomplate-image
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG TARGETOS
|
||||
ARG GOMPLATE_VERSION
|
||||
|
||||
RUN set -ex \
|
||||
&& curl \
|
||||
--silent \
|
||||
--show-error \
|
||||
--location \
|
||||
--output /usr/local/bin/gomplate \
|
||||
https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS}-${TARGETARCH} \
|
||||
&& chmod +x /usr/local/bin/gomplate \
|
||||
&& /usr/local/bin/gomplate --version
|
||||
|
||||
#######################################################
|
||||
# Base image
|
||||
#######################################################
|
||||
|
||||
FROM php:${PHP_VERSION}-${PHP_BASE_TYPE}-${PHP_DEBIAN_RELEASE} AS base
|
||||
|
||||
ARG BUILDKIT_SBOM_SCAN_STAGE="true"
|
||||
|
||||
ARG APT_PACKAGES_EXTRA
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG PHP_VERSION
|
||||
ARG RUNTIME_GID
|
||||
ARG RUNTIME_UID
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
|
||||
# Ensure we run all scripts through 'bash' rather than 'sh'
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
# Set www-data to be RUNTIME_UID/RUNTIME_GID
|
||||
RUN groupmod --gid ${RUNTIME_GID} www-data \
|
||||
&& usermod --uid ${RUNTIME_UID} --gid ${RUNTIME_GID} www-data
|
||||
|
||||
RUN set -ex \
|
||||
&& mkdir -pv /var/www/ \
|
||||
&& chown -R ${RUNTIME_UID}:${RUNTIME_GID} /var/www
|
||||
|
||||
WORKDIR /var/www/
|
||||
|
||||
ENV APT_PACKAGES_EXTRA=${APT_PACKAGES_EXTRA}
|
||||
|
||||
# Install and configure base layer
|
||||
COPY docker/shared/root/docker/install/base.sh /docker/install/base.sh
|
||||
|
||||
RUN --mount=type=cache,id=pixelfed-apt-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt \
|
||||
--mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
|
||||
/docker/install/base.sh
|
||||
|
||||
#######################################################
|
||||
# PHP: extensions
|
||||
#######################################################
|
||||
|
||||
FROM base AS php-extensions
|
||||
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG PHP_EXTENSIONS
|
||||
ARG PHP_EXTENSIONS_DATABASE
|
||||
ARG PHP_EXTENSIONS_EXTRA
|
||||
ARG PHP_PECL_EXTENSIONS
|
||||
ARG PHP_PECL_EXTENSIONS_EXTRA
|
||||
ARG PHP_VERSION
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
|
||||
|
||||
COPY docker/shared/root/docker/install/php-extensions.sh /docker/install/php-extensions.sh
|
||||
|
||||
RUN --mount=type=cache,id=pixelfed-pear-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/tmp/pear \
|
||||
--mount=type=cache,id=pixelfed-apt-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt \
|
||||
--mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
|
||||
PHP_EXTENSIONS=${PHP_EXTENSIONS} \
|
||||
PHP_EXTENSIONS_DATABASE=${PHP_EXTENSIONS_DATABASE} \
|
||||
PHP_EXTENSIONS_EXTRA=${PHP_EXTENSIONS_EXTRA} \
|
||||
PHP_PECL_EXTENSIONS=${PHP_PECL_EXTENSIONS} \
|
||||
PHP_PECL_EXTENSIONS_EXTRA=${PHP_PECL_EXTENSIONS_EXTRA} \
|
||||
/docker/install/php-extensions.sh
|
||||
|
||||
#######################################################
|
||||
# Node: Build frontend
|
||||
#######################################################
|
||||
|
||||
# NOTE: Since the nodejs build is CPU architecture agnostic,
|
||||
# we only want to build once and cache it for other architectures.
|
||||
# We force the (CPU) [--platform] here to be architecture
|
||||
# of the "builder"/"server" and not the *target* CPU architecture
|
||||
# (e.g.) building the ARM version of Pixelfed on AMD64.
|
||||
FROM --platform=${BUILDARCH} node:lts AS frontend-build
|
||||
|
||||
ARG BUILDARCH
|
||||
ARG BUILD_FRONTEND=0
|
||||
ARG RUNTIME_UID
|
||||
ARG RUNTIME_GID
|
||||
|
||||
ARG NODE_ENV=production
|
||||
ENV NODE_ENV=$NODE_ENV
|
||||
|
||||
WORKDIR /var/www/
|
||||
|
||||
SHELL [ "/usr/bin/bash", "-c" ]
|
||||
|
||||
# Install NPM dependencies
|
||||
RUN --mount=type=cache,id=pixelfed-node-${BUILDARCH},sharing=locked,target=/tmp/cache \
|
||||
--mount=type=bind,source=package.json,target=/var/www/package.json \
|
||||
--mount=type=bind,source=package-lock.json,target=/var/www/package-lock.json \
|
||||
<<EOF
|
||||
if [[ $BUILD_FRONTEND -eq 1 ]];
|
||||
then
|
||||
npm install --cache /tmp/cache --no-save --dev
|
||||
else
|
||||
echo "Skipping [npm install] as --build-arg [BUILD_FRONTEND] is not set to '1'"
|
||||
fi
|
||||
EOF
|
||||
|
||||
# Copy the frontend source into the image before building
|
||||
COPY --chown=${RUNTIME_UID}:${RUNTIME_GID} . /var/www
|
||||
|
||||
# Build the frontend with "mix" (See package.json)
|
||||
RUN \
|
||||
<<EOF
|
||||
if [[ $BUILD_FRONTEND -eq 1 ]];
|
||||
then
|
||||
npm run production
|
||||
else
|
||||
echo "Skipping [npm run production] as --build-arg [BUILD_FRONTEND] is not set to '1'"
|
||||
fi
|
||||
EOF
|
||||
|
||||
#######################################################
|
||||
# PHP: composer and source code
|
||||
#######################################################
|
||||
|
||||
FROM php-extensions AS composer-and-src
|
||||
|
||||
ARG PHP_VERSION
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG RUNTIME_UID
|
||||
ARG RUNTIME_GID
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Make sure composer cache is targeting our cache mount later
|
||||
ENV COMPOSER_CACHE_DIR="/cache/composer"
|
||||
|
||||
# Don't enforce any memory limits for composer
|
||||
ENV COMPOSER_MEMORY_LIMIT=-1
|
||||
|
||||
# Disable interactvitity from composer
|
||||
ENV COMPOSER_NO_INTERACTION=1
|
||||
|
||||
# Copy composer from https://hub.docker.com/_/composer
|
||||
COPY --link --from=composer-image /usr/bin/composer /usr/bin/composer
|
||||
|
||||
#! Changing user to runtime user
|
||||
USER ${RUNTIME_UID}:${RUNTIME_GID}
|
||||
|
||||
|
||||
# Install composer dependencies
|
||||
# NOTE: we skip the autoloader generation here since we don't have all files avaliable (yet)
|
||||
RUN --mount=type=cache,id=pixelfed-composer-${PHP_VERSION},sharing=locked,uid=${RUNTIME_UID},gid=${RUNTIME_GID},target=/cache/composer \
|
||||
--mount=type=bind,source=composer.json,target=/var/www/composer.json \
|
||||
--mount=type=bind,source=composer.lock,target=/var/www/composer.lock \
|
||||
set -ex \
|
||||
&& composer install --prefer-dist --no-autoloader --ignore-platform-reqs --no-scripts
|
||||
|
||||
# Copy all other files over
|
||||
COPY --chown=${RUNTIME_UID}:${RUNTIME_GID} . /var/www/
|
||||
|
||||
# Generate optimized autoloader now that we have all files around
|
||||
RUN set -ex \
|
||||
&& ENABLE_CONFIG_CACHE=false composer dump-autoload --optimize
|
||||
|
||||
# Now we can run the post-install scripts
|
||||
RUN set -ex \
|
||||
&& composer run-script post-update-cmd
|
||||
|
||||
#######################################################
|
||||
# Runtime: base
|
||||
#######################################################
|
||||
|
||||
FROM php-extensions AS shared-runtime
|
||||
|
||||
ARG RUNTIME_GID
|
||||
ARG RUNTIME_UID
|
||||
|
||||
ENV RUNTIME_UID=${RUNTIME_UID}
|
||||
ENV RUNTIME_GID=${RUNTIME_GID}
|
||||
|
||||
COPY --link --from=forego-image /usr/local/bin/forego /usr/local/bin/forego
|
||||
COPY --link --from=dottie-image /dottie /usr/local/bin/dottie
|
||||
COPY --link --from=gomplate-image /usr/local/bin/gomplate /usr/local/bin/gomplate
|
||||
COPY --link --from=composer-image /usr/bin/composer /usr/bin/composer
|
||||
COPY --link --from=composer-and-src --chown=${RUNTIME_UID}:${RUNTIME_GID} /var/www /var/www
|
||||
COPY --link --from=frontend-build --chown=${RUNTIME_UID}:${RUNTIME_GID} /var/www/public /var/www/public
|
||||
# Set working directory
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Switch to root to install packages
|
||||
USER root
|
||||
|
||||
# for detail why storage is copied this way, pls refer to https://github.com/pixelfed/pixelfed/pull/2137#discussion_r434468862
|
||||
RUN set -ex \
|
||||
&& cp --recursive --link --preserve=all storage storage.skel \
|
||||
&& rm -rf html && ln -s public html
|
||||
|
||||
COPY docker/shared/root /
|
||||
|
||||
ENTRYPOINT ["/docker/entrypoint.sh"]
|
||||
|
||||
#######################################################
|
||||
# Runtime: apache
|
||||
#######################################################
|
||||
|
||||
FROM shared-runtime AS apache-runtime
|
||||
|
||||
COPY docker/apache/root /
|
||||
|
||||
RUN set -ex \
|
||||
&& a2enmod rewrite remoteip proxy proxy_http \
|
||||
&& a2enconf remoteip
|
||||
# Install system dependencies and PHP extensions
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ffmpeg \
|
||||
unzip \
|
||||
zip \
|
||||
jpegoptim \
|
||||
optipng \
|
||||
pngquant \
|
||||
gifsicle \
|
||||
libvips42 \
|
||||
git \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PHP extensions using the built-in helper
|
||||
RUN install-php-extensions \
|
||||
bcmath \
|
||||
curl \
|
||||
gd \
|
||||
intl \
|
||||
mbstring \
|
||||
xml \
|
||||
zip \
|
||||
pdo_mysql \
|
||||
redis \
|
||||
vips \
|
||||
ffi
|
||||
|
||||
# Copy application files
|
||||
COPY --chown=www-data:www-data . /var/www/html
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R www-data:www-data /var/www/html \
|
||||
&& find /var/www/html -type f -exec chmod 644 {} \; \
|
||||
&& find /var/www/html -type d -exec chmod 755 {} \; \
|
||||
&& chmod -R ug+rwx /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
|
||||
CMD ["apache2-foreground"]
|
||||
|
||||
#######################################################
|
||||
# Runtime: fpm
|
||||
#######################################################
|
||||
|
||||
FROM shared-runtime AS fpm-runtime
|
||||
|
||||
COPY docker/fpm/root /
|
||||
|
||||
CMD ["php-fpm"]
|
||||
|
||||
#######################################################
|
||||
# Runtime: nginx
|
||||
#######################################################
|
||||
|
||||
FROM shared-runtime AS nginx-runtime
|
||||
|
||||
ARG NGINX_GPGKEY
|
||||
ARG NGINX_GPGKEY_PATH
|
||||
ARG NGINX_VERSION
|
||||
ARG PHP_DEBIAN_RELEASE
|
||||
ARG PHP_VERSION
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Install nginx dependencies
|
||||
RUN --mount=type=cache,id=pixelfed-apt-lists-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/lib/apt/lists \
|
||||
--mount=type=cache,id=pixelfed-apt-cache-${PHP_VERSION}-${PHP_DEBIAN_RELEASE}-${TARGETPLATFORM},sharing=locked,target=/var/cache/apt \
|
||||
set -ex \
|
||||
&& gpg1 --keyserver "hkp://keyserver.ubuntu.com:80" --keyserver-options timeout=10 --recv-keys "${NGINX_GPGKEY}" \
|
||||
&& gpg1 --export "$NGINX_GPGKEY" > "$NGINX_GPGKEY_PATH" \
|
||||
&& echo "deb [signed-by=${NGINX_GPGKEY_PATH}] https://nginx.org/packages/mainline/debian/ ${PHP_DEBIAN_RELEASE} nginx" >> /etc/apt/sources.list.d/nginx.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends nginx=${NGINX_VERSION}*
|
||||
|
||||
# copy docker entrypoints from the *real* nginx image directly
|
||||
COPY --link --from=nginx-image /docker-entrypoint.d /docker/entrypoint.d/
|
||||
COPY docker/nginx/root /
|
||||
COPY docker/nginx/Procfile .
|
||||
# Install composer dependencies
|
||||
RUN composer install --no-ansi --no-interaction --optimize-autoloader
|
||||
|
||||
STOPSIGNAL SIGQUIT
|
||||
# Switch back to www-data user
|
||||
USER www-data
|
||||
|
||||
CMD ["forego", "start", "-r"]
|
||||
# Expose port 8080 (default for serversideup/php)
|
||||
EXPOSE 8080
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
---
|
||||
services:
|
||||
migrate:
|
||||
image: "servercontainers/rsync"
|
||||
entrypoint: ""
|
||||
working_dir: /migrate
|
||||
command: 'bash -c "exit 1"'
|
||||
restart: never
|
||||
volumes:
|
||||
################################
|
||||
# Storage volume
|
||||
################################
|
||||
# OLD
|
||||
- "app-storage:/migrate/app-storage/old"
|
||||
# NEW
|
||||
- "${DOCKER_APP_HOST_STORAGE_PATH}:/migrate/app-storage/new"
|
||||
|
||||
################################
|
||||
# MySQL/DB volume
|
||||
################################
|
||||
# OLD
|
||||
- "db-data:/migrate/db-data/old"
|
||||
# NEW
|
||||
- "${DOCKER_DB_HOST_DATA_PATH}:/migrate/db-data/new"
|
||||
|
||||
################################
|
||||
# Redis volume
|
||||
################################
|
||||
# OLD
|
||||
- "redis-data:/migrate/redis-data/old"
|
||||
# NEW
|
||||
- "${DOCKER_REDIS_HOST_DATA_PATH}:/migrate/redis-data/new"
|
||||
|
||||
# Volumes from the old [docker-compose.yml] file
|
||||
# https://github.com/pixelfed/pixelfed/blob/b1ff44ca2f75c088a11576fb03b5bad2fbed4d5c/docker-compose.yml#L72-L76
|
||||
volumes:
|
||||
db-data:
|
||||
redis-data:
|
||||
app-storage:
|
||||
app-bootstrap:
|
||||
@ -1,217 +1,147 @@
|
||||
---
|
||||
###############################################################
|
||||
# Please see docker/README.md for usage information
|
||||
###############################################################
|
||||
|
||||
services:
|
||||
# HTTP/HTTPS proxy
|
||||
#
|
||||
# Sits in front of the *real* webserver and manages SSL and (optionally)
|
||||
# load-balancing between multiple web servers
|
||||
#
|
||||
# You can disable this service by setting [DOCKER_PROXY_PROFILE="disabled"]
|
||||
# in your [.env] file - the setting is near the bottom of the file.
|
||||
#
|
||||
# This also disables the [proxy-acme] service, if this is not desired, change the
|
||||
# [DOCKER_PROXY_ACME_PROFILE] setting to an empty string [""]
|
||||
#
|
||||
# See: https://github.com/nginx-proxy/nginx-proxy/tree/main/docs
|
||||
proxy:
|
||||
image: "nginxproxy/nginx-proxy:${DOCKER_PROXY_VERSION}"
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-proxy"
|
||||
## MariaDB and Redis (optional)
|
||||
db:
|
||||
image: mariadb:11
|
||||
container_name: pixelfed-db
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- ${DOCKER_PROXY_PROFILE:-}
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
DOCKER_SERVICE_NAME: "proxy"
|
||||
MARIADB_DATABASE: ${DB_DATABASE}
|
||||
MARIADB_USER: ${DB_USERNAME}
|
||||
MARIADB_PASSWORD: ${DB_PASSWORD}
|
||||
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- "${DOCKER_PROXY_HOST_DOCKER_SOCKET_PATH}:/tmp/docker.sock:ro"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/conf.d:/etc/nginx/conf.d"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/vhost.d:/etc/nginx/vhost.d"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/certs:/etc/nginx/certs"
|
||||
- "${DOCKER_ALL_HOST_DATA_ROOT_PATH}/proxy/html:/usr/share/nginx/html"
|
||||
ports:
|
||||
- "${DOCKER_PROXY_HOST_PORT_HTTP}:80"
|
||||
- "${DOCKER_PROXY_HOST_PORT_HTTPS}:443"
|
||||
- ./mariadb-11-data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: "curl --fail https://${APP_DOMAIN}/api/service/health-check"
|
||||
interval: "${DOCKER_PROXY_HEALTHCHECK_INTERVAL}"
|
||||
retries: 2
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
networks:
|
||||
- pixelfed-network
|
||||
|
||||
# Proxy companion for managing letsencrypt SSL certificates
|
||||
#
|
||||
# You can disable this service by setting [DOCKER_PROXY_ACME_PROFILE="disabled"]
|
||||
# in your [.env] file - the setting is near the bottom of the file.
|
||||
#
|
||||
# See: https://github.com/nginx-proxy/acme-companion/tree/main/docs
|
||||
proxy-acme:
|
||||
image: nginxproxy/acme-companion
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-proxy-acme"
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: pixelfed-redis
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- ${DOCKER_PROXY_ACME_PROFILE:-}
|
||||
environment:
|
||||
DEBUG: 0
|
||||
DEFAULT_EMAIL: "${DOCKER_PROXY_LETSENCRYPT_EMAIL:?error}"
|
||||
NGINX_PROXY_CONTAINER: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-proxy"
|
||||
depends_on:
|
||||
- proxy
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy-acme:/etc/acme.sh"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/certs:/etc/nginx/certs"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/conf.d:/etc/nginx/conf.d"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/vhost.d:/etc/nginx/vhost.d"
|
||||
- "${DOCKER_ALL_HOST_DATA_ROOT_PATH}/proxy/html:/usr/share/nginx/html"
|
||||
- "${DOCKER_PROXY_HOST_DOCKER_SOCKET_PATH}:/var/run/docker.sock:ro"
|
||||
- ./redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
networks:
|
||||
- pixelfed-network
|
||||
|
||||
web:
|
||||
image: "${DOCKER_APP_IMAGE}:${DOCKER_APP_TAG}"
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-web"
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- ${DOCKER_WEB_PROFILE:-}
|
||||
## Pixelfed containers - App (Web/API), Horizon Queue, Scheduled task.
|
||||
pixelfed:
|
||||
build:
|
||||
target: ${DOCKER_APP_RUNTIME}-runtime
|
||||
cache_from:
|
||||
- "type=registry,ref=${DOCKER_APP_IMAGE}-cache:${DOCKER_APP_TAG}"
|
||||
args:
|
||||
APT_PACKAGES_EXTRA: "${DOCKER_APP_APT_PACKAGES_EXTRA:-}"
|
||||
BUILD_FRONTEND: "${DOCKER_APP_BUILD_FRONTEND:-0}"
|
||||
PHP_BASE_TYPE: "${DOCKER_APP_BASE_TYPE}"
|
||||
PHP_DEBIAN_RELEASE: "${DOCKER_APP_DEBIAN_RELEASE}"
|
||||
PHP_EXTENSIONS_EXTRA: "${DOCKER_APP_PHP_EXTENSIONS_EXTRA:-}"
|
||||
PHP_PECL_EXTENSIONS_EXTRA: "${DOCKER_APP_PHP_PECL_EXTENSIONS_EXTRA:-}"
|
||||
PHP_VERSION: "${DOCKER_APP_PHP_VERSION:?error}"
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: pixelfed-app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
# Used by Pixelfed Docker init script
|
||||
DOCKER_SERVICE_NAME: "web"
|
||||
DOCKER_APP_ENTRYPOINT_DEBUG: ${DOCKER_APP_ENTRYPOINT_DEBUG:-0}
|
||||
ENTRYPOINT_SKIP_SCRIPTS: ${ENTRYPOINT_SKIP_SCRIPTS:-}
|
||||
# Used by [proxy] service
|
||||
LETSENCRYPT_HOST: "${DOCKER_PROXY_LETSENCRYPT_HOST:?error}"
|
||||
LETSENCRYPT_EMAIL: "${DOCKER_PROXY_LETSENCRYPT_EMAIL:?error}"
|
||||
LETSENCRYPT_TEST: "${DOCKER_PROXY_LETSENCRYPT_TEST:-}"
|
||||
VIRTUAL_HOST: "${APP_DOMAIN}"
|
||||
VIRTUAL_PORT: "80"
|
||||
# SSL Configuration (handled by reverse proxy)
|
||||
SSL_MODE: "off"
|
||||
|
||||
# PHP Configuration
|
||||
PHP_POST_MAX_SIZE: "500M"
|
||||
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
|
||||
PHP_OPCACHE_ENABLE: "1"
|
||||
|
||||
# Laravel Auto-run Configuration
|
||||
AUTORUN_ENABLED: "true"
|
||||
AUTORUN_LARAVEL_MIGRATION: "true"
|
||||
AUTORUN_LARAVEL_MIGRATION_ISOLATION: "true"
|
||||
AUTORUN_LARAVEL_STORAGE_LINK: "true"
|
||||
AUTORUN_LARAVEL_EVENT_CACHE: "true"
|
||||
AUTORUN_LARAVEL_ROUTE_CACHE: "true"
|
||||
AUTORUN_LARAVEL_VIEW_CACHE: "true"
|
||||
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
|
||||
|
||||
volumes:
|
||||
- "./.env:/var/www/.env"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/conf.d:/shared/proxy/conf.d"
|
||||
- "${DOCKER_APP_HOST_CACHE_PATH}:/var/www/bootstrap/cache"
|
||||
- "${DOCKER_APP_HOST_OVERRIDES_PATH}:/docker/overrides:ro"
|
||||
- "${DOCKER_APP_HOST_STORAGE_PATH}:/var/www/storage"
|
||||
labels:
|
||||
com.github.nginx-proxy.nginx-proxy.keepalive: 30
|
||||
com.github.nginx-proxy.nginx-proxy.http2.enable: true
|
||||
com.github.nginx-proxy.nginx-proxy.http3.enable: true
|
||||
ports:
|
||||
- "${DOCKER_WEB_PORT_EXTERNAL_HTTP}:80"
|
||||
- ./storage:/var/www/html/storage
|
||||
- ./bootstrap/cache:/var/www/html/bootstrap/cache
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
healthcheck:
|
||||
test: 'curl --header "Host: ${APP_DOMAIN}" --fail http://localhost/api/service/health-check'
|
||||
interval: "${DOCKER_WEB_HEALTHCHECK_INTERVAL}"
|
||||
retries: 2
|
||||
timeout: 5s
|
||||
networks:
|
||||
- pixelfed-network
|
||||
|
||||
worker:
|
||||
image: "${DOCKER_APP_IMAGE}:${DOCKER_APP_TAG}"
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-worker"
|
||||
command: gosu www-data php artisan horizon
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGTERM
|
||||
profiles:
|
||||
- ${DOCKER_WORKER_PROFILE:-}
|
||||
horizon:
|
||||
build:
|
||||
target: ${DOCKER_APP_RUNTIME}-runtime
|
||||
cache_from:
|
||||
- "type=registry,ref=${DOCKER_APP_IMAGE}-cache:${DOCKER_APP_TAG}"
|
||||
args:
|
||||
APT_PACKAGES_EXTRA: "${DOCKER_APP_APT_PACKAGES_EXTRA:-}"
|
||||
BUILD_FRONTEND: "${DOCKER_APP_BUILD_FRONTEND:-0}"
|
||||
PHP_BASE_TYPE: "${DOCKER_APP_BASE_TYPE}"
|
||||
PHP_DEBIAN_RELEASE: "${DOCKER_APP_DEBIAN_RELEASE}"
|
||||
PHP_EXTENSIONS_EXTRA: "${DOCKER_APP_PHP_EXTENSIONS_EXTRA:-}"
|
||||
PHP_PECL_EXTENSIONS_EXTRA: "${DOCKER_APP_PHP_PECL_EXTENSIONS_EXTRA:-}"
|
||||
PHP_VERSION: "${DOCKER_APP_PHP_VERSION:?error}"
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: pixelfed-horizon
|
||||
restart: unless-stopped
|
||||
command: ["php", "artisan", "horizon"]
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
# Used by Pixelfed Docker init script
|
||||
DOCKER_SERVICE_NAME: "worker"
|
||||
DOCKER_APP_ENTRYPOINT_DEBUG: ${DOCKER_APP_ENTRYPOINT_DEBUG:-0}
|
||||
ENTRYPOINT_SKIP_SCRIPTS: ${ENTRYPOINT_SKIP_SCRIPTS:-}
|
||||
# Laravel Auto-run Configuration
|
||||
AUTORUN_LARAVEL_STORAGE_LINK: "true"
|
||||
AUTORUN_LARAVEL_EVENT_CACHE: "true"
|
||||
AUTORUN_LARAVEL_ROUTE_CACHE: "true"
|
||||
AUTORUN_LARAVEL_VIEW_CACHE: "true"
|
||||
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
|
||||
PHP_POST_MAX_SIZE: "500M"
|
||||
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
|
||||
PHP_OPCACHE_ENABLE: "1"
|
||||
volumes:
|
||||
- "./.env:/var/www/.env"
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/proxy/conf.d:/shared/proxy/conf.d"
|
||||
- "${DOCKER_APP_HOST_CACHE_PATH}:/var/www/bootstrap/cache"
|
||||
- "${DOCKER_APP_HOST_OVERRIDES_PATH}:/docker/overrides:ro"
|
||||
- "${DOCKER_APP_HOST_STORAGE_PATH}:/var/www/storage"
|
||||
- ./storage:/var/www/html/storage
|
||||
- ./bootstrap/cache:/var/www/html/bootstrap/cache
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
healthcheck:
|
||||
test: gosu www-data php artisan horizon:status | grep running
|
||||
interval: "${DOCKER_WORKER_HEALTHCHECK_INTERVAL:?error}"
|
||||
test: ["CMD", "php", "artisan", "horizon:status"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 2
|
||||
retries: 3
|
||||
networks:
|
||||
- pixelfed-network
|
||||
|
||||
db:
|
||||
image: ${DOCKER_DB_IMAGE:?error}
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-db"
|
||||
command: ${DOCKER_DB_COMMAND:-}
|
||||
scheduler:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: pixelfed-scheduler
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- ${DOCKER_DB_PROFILE:-}
|
||||
command: ["php", "artisan", "schedule:work"]
|
||||
stop_signal: SIGTERM
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
TZ: "${TZ:?error}"
|
||||
# MySQL (Oracle) - "Environment Variables" at https://hub.docker.com/_/mysql
|
||||
MYSQL_ROOT_PASSWORD: "${DOCKER_DB_ROOT_PASSWORD:?error}"
|
||||
MYSQL_USER: "${DB_USERNAME:?error}"
|
||||
MYSQL_PASSWORD: "${DB_PASSWORD:?error}"
|
||||
MYSQL_DATABASE: "${DB_DATABASE:?error}"
|
||||
# MySQL (MariaDB) - "Start a mariadb server instance with user, password and database" at https://hub.docker.com/_/mariadb
|
||||
MARIADB_ROOT_PASSWORD: "${DOCKER_DB_ROOT_PASSWORD:?error}"
|
||||
MARIADB_USER: "${DB_USERNAME:?error}"
|
||||
MARIADB_PASSWORD: "${DB_PASSWORD:?error}"
|
||||
MARIADB_DATABASE: "${DB_DATABASE:?error}"
|
||||
# PostgreSQL - "Environment Variables" at https://hub.docker.com/_/postgres
|
||||
POSTGRES_USER: "${DB_USERNAME:?error}"
|
||||
POSTGRES_PASSWORD: "${DB_PASSWORD:?error}"
|
||||
POSTGRES_DB: "${DB_DATABASE:?error}"
|
||||
# Laravel Auto-run Configuration
|
||||
AUTORUN_LARAVEL_STORAGE_LINK: "true"
|
||||
AUTORUN_LARAVEL_EVENT_CACHE: "true"
|
||||
AUTORUN_LARAVEL_ROUTE_CACHE: "true"
|
||||
AUTORUN_LARAVEL_VIEW_CACHE: "true"
|
||||
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
|
||||
PHP_POST_MAX_SIZE: "500M"
|
||||
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
|
||||
PHP_OPCACHE_ENABLE: "1"
|
||||
volumes:
|
||||
- "${DOCKER_DB_HOST_DATA_PATH:?error}:${DOCKER_DB_CONTAINER_DATA_PATH:?error}"
|
||||
ports:
|
||||
- "${DOCKER_DB_HOST_PORT:?error}:${DOCKER_DB_CONTAINER_PORT:?error}"
|
||||
- ./storage:/var/www/html/storage
|
||||
- ./bootstrap/cache:/var/www/html/bootstrap/cache
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD",
|
||||
"healthcheck.sh",
|
||||
"--su-mysql",
|
||||
"--connect",
|
||||
"--innodb_initialized",
|
||||
]
|
||||
interval: "${DOCKER_DB_HEALTHCHECK_INTERVAL:?error}"
|
||||
retries: 2
|
||||
timeout: 5s
|
||||
test: ["CMD", "healthcheck-schedule"]
|
||||
start_period: 10s
|
||||
networks:
|
||||
- pixelfed-network
|
||||
|
||||
redis:
|
||||
image: redis:${DOCKER_REDIS_VERSION}
|
||||
container_name: "${DOCKER_ALL_CONTAINER_NAME_PREFIX}-redis"
|
||||
restart: unless-stopped
|
||||
command: "${DOCKER_REDIS_CONFIG_FILE:-} --requirepass '${REDIS_PASSWORD:-}'"
|
||||
profiles:
|
||||
- ${DOCKER_REDIS_PROFILE:-}
|
||||
environment:
|
||||
TZ: "${TZ:?error}"
|
||||
REDISCLI_AUTH: ${REDIS_PASSWORD:-}
|
||||
volumes:
|
||||
- "${DOCKER_ALL_HOST_CONFIG_ROOT_PATH}/redis:/etc/redis"
|
||||
- "${DOCKER_REDIS_HOST_DATA_PATH}:/data"
|
||||
ports:
|
||||
- "${DOCKER_REDIS_HOST_PORT}:6379"
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-p", "6379", "ping"]
|
||||
interval: "${DOCKER_REDIS_HEALTHCHECK_INTERVAL:?error}"
|
||||
retries: 2
|
||||
timeout: 5s
|
||||
networks:
|
||||
pixelfed-network:
|
||||
driver: bridge
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
# Pixelfed + Docker + Docker Compose
|
||||
|
||||
Please see the [Pixelfed Docs (Next)](https://jippi.github.io/docker-pixelfed/) for current documentation on Docker usage.
|
||||
|
||||
The docs can be [reviewed in the pixelfed/docs-next](https://github.com/pixelfed/docs-next/pull/1) repository.
|
||||
@ -1,8 +0,0 @@
|
||||
RemoteIPHeader X-Real-IP
|
||||
|
||||
# All private IPs as outlined in rfc1918
|
||||
#
|
||||
# See: https://datatracker.ietf.org/doc/html/rfc1918
|
||||
RemoteIPTrustedProxy 10.0.0.0/8
|
||||
RemoteIPTrustedProxy 172.16.0.0/12
|
||||
RemoteIPTrustedProxy 192.168.0.0/16
|
||||
@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare service="${PF_SERVICE:=worker}"
|
||||
declare user="${PF_USER:=www-data}"
|
||||
|
||||
exec docker compose exec \
|
||||
--user "${user}" \
|
||||
--env TERM \
|
||||
--env COLORTERM \
|
||||
"${service}" \
|
||||
php artisan "${@}"
|
||||
@ -1,126 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o errexit -o nounset -o pipefail
|
||||
|
||||
#
|
||||
# Colors
|
||||
#
|
||||
|
||||
declare -r RED="\e[31m"
|
||||
declare -r GREEN="\e[32m"
|
||||
declare -r BLUE="\e[34m"
|
||||
declare -r NO_COLOR="\e[0m"
|
||||
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
|
||||
function highlight() {
|
||||
local reset="${2:-$NO_COLOR}"
|
||||
echo "${BLUE}$1${reset}"
|
||||
}
|
||||
|
||||
function action_start() {
|
||||
echo -en "⚙️ $1: "
|
||||
}
|
||||
|
||||
function action_ok() {
|
||||
echo -e "\n\t✅ ${GREEN}${*}${NO_COLOR}\n"
|
||||
}
|
||||
|
||||
function action_error() {
|
||||
echo -e "\n\t❌ ${RED}${*}${NO_COLOR}" >&2
|
||||
}
|
||||
|
||||
function action_error_exit() {
|
||||
action_error "${*}\n\n${RED}Aborting!${NO_COLOR}"
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
#
|
||||
# Configuration
|
||||
#
|
||||
|
||||
declare -r min_docker_compose_version_arr=(2 17)
|
||||
min_docker_compose_version=$(
|
||||
IFS=.
|
||||
echo "${min_docker_compose_version[*]}"
|
||||
)
|
||||
|
||||
#
|
||||
# Help text
|
||||
#
|
||||
|
||||
DOCKER_HELP="
|
||||
|
||||
\tWe recommend installing Docker (and Compose) directly from Docker.com instead of your Operation System package registry.
|
||||
\tPlease see $(highlight "https://docs.docker.com/engine/install/")${RED} for information on how to install Docker on your system.
|
||||
|
||||
\tA convinience script is provided by Docker to automate the installation that should work on all supported platforms:
|
||||
|
||||
\t\t ${GREEN}\$${BLUE} curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
\t\t ${GREEN}\$${BLUE} sudo sh ./get-docker.sh
|
||||
${RED}
|
||||
\tPlease see $(highlight "https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script")${RED} for more information
|
||||
|
||||
\tAlternatively, you can update *JUST* the Compose plugin by following the guide here:
|
||||
\t$(highlight "https://docs.docker.com/compose/install/linux/#install-the-plugin-manually")${RED}
|
||||
|
||||
\tLearn more about Docker compose release history here:
|
||||
\t$(highlight "https://docs.docker.com/compose/release-notes/")${RED}${NO_COLOR}"
|
||||
declare -r DOCKER_HELP
|
||||
|
||||
#
|
||||
# System checks
|
||||
#
|
||||
|
||||
echo -e "👋 ${GREEN}Hello!"
|
||||
echo -e ""
|
||||
echo -e "This script will check your system for the minimum requirements outlined in the Pixelfed Docker install guide"
|
||||
echo -e "You can find the guide here ${BLUE}https://jippi.github.io/pixelfed-docs-next/pr-preview/pr-1/running-pixelfed/docker/prerequisites.html#software${GREEN}."
|
||||
echo -e "${NO_COLOR}"
|
||||
|
||||
# git installed?
|
||||
action_start "Checking if [$(highlight "git")] command is available"
|
||||
command -v git >/dev/null 2>&1 || {
|
||||
action_error_exit "Pixelfed require the 'git' command, but it's not installed"
|
||||
}
|
||||
action_ok "git is installed"
|
||||
|
||||
# docker installed?
|
||||
action_start "Checking if [$(highlight "docker")] command is available"
|
||||
command -v docker >/dev/null 2>&1 || {
|
||||
action_error_exit "Pixelfed require the 'docker' command, but it's not installed. ${DOCKER_HELP}"
|
||||
}
|
||||
action_ok "docker is installed"
|
||||
|
||||
# docker compose installed?
|
||||
action_start "Checking if [$(highlight "docker compose")] command is available"
|
||||
docker compose >/dev/null 2>&1 || {
|
||||
action_error_exit "Pixelfed require the 'docker compose' command, but it's not installed. ${DOCKER_HELP}"
|
||||
}
|
||||
action_ok "docker compose is installed"
|
||||
|
||||
# docker compose version is acceptable?
|
||||
compose_version=$(docker compose version --short)
|
||||
|
||||
declare -a compose_version_arr
|
||||
IFS="." read -r -a compose_version_arr <<<"$compose_version"
|
||||
|
||||
## major version
|
||||
action_start "Checking if [$(highlight "docker compose version")] major version (${min_docker_compose_version_arr[0]}) is acceptable"
|
||||
[[ ${compose_version_arr[0]} -eq ${min_docker_compose_version_arr[0]} ]] || {
|
||||
action_error_exit "Pixelfed require minimum Docker Compose major version ${min_docker_compose_version_arr[0]}.x.x - found ${compose_version}.${DOCKER_HELP}"
|
||||
}
|
||||
action_ok "You're using major version ${compose_version_arr[0]}"
|
||||
|
||||
## minor version
|
||||
action_start "Checking if [$(highlight "docker compose version")] minor version (${min_docker_compose_version_arr[1]}) is acceptable"
|
||||
[[ ${compose_version_arr[1]} -ge ${min_docker_compose_version_arr[1]} ]] || {
|
||||
action_error_exit "Pixelfed require minimum Docker Compose minor version ${min_docker_compose_version_arr[0]}.${min_docker_compose_version_arr[1]} - found ${compose_version}.${DOCKER_HELP}"
|
||||
}
|
||||
action_ok "You're using minor version ${compose_version_arr[1]}"
|
||||
|
||||
# Yay, everything is fine
|
||||
echo -e "🎉 ${GREEN}All checks passed, you should be ready to run Pixelfed on this server!${NO_COLOR}"
|
||||
@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o errexit -o nounset -o pipefail
|
||||
|
||||
declare project_root="${PWD}"
|
||||
declare user="${PF_USER:=www-data}"
|
||||
|
||||
if command -v git &>/dev/null; then
|
||||
project_root=$(git rev-parse --show-toplevel)
|
||||
fi
|
||||
|
||||
declare -r release="${DOTTIE_VERSION:-latest}"
|
||||
|
||||
declare -r update_check_file="/tmp/.dottie-update-check" # file to check age of since last update
|
||||
declare -i update_check_max_age=$((8 * 60 * 60)) # 8 hours between checking for dottie version
|
||||
declare -i update_check_cur_age=$((update_check_max_age + 1)) # by default the "update" event should happen
|
||||
|
||||
# default [docker run] flags
|
||||
declare -a flags=(
|
||||
--rm
|
||||
--interactive
|
||||
--tty
|
||||
--user "${user}"
|
||||
--env TERM
|
||||
--env COLORTERM
|
||||
--volume "${project_root}:/var/www"
|
||||
--workdir /var/www
|
||||
)
|
||||
|
||||
# if update file exists, find its age since last modification
|
||||
if [[ -f "${update_check_file}" ]]; then
|
||||
now=$(date +%s)
|
||||
changed=$(date -r "${update_check_file}" +%s)
|
||||
update_check_cur_age=$((now - changed))
|
||||
fi
|
||||
|
||||
# if update file is older than max allowed poll for new version of dottie
|
||||
if [[ $update_check_cur_age -gt $update_check_max_age ]]; then
|
||||
flags+=(--pull always)
|
||||
|
||||
touch "${update_check_file}"
|
||||
fi
|
||||
|
||||
# run dottie
|
||||
exec docker run "${flags[@]}" "ghcr.io/jippi/dottie:${release}" "$@"
|
||||
@ -1,2 +0,0 @@
|
||||
fpm: php-fpm
|
||||
nginx: nginx -g "daemon off;"
|
||||
@ -1,49 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
|
||||
server_name {{ getenv "APP_DOMAIN" }};
|
||||
root /var/www/public;
|
||||
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr warn;
|
||||
|
||||
index index.html index.htm index.php;
|
||||
|
||||
charset utf-8;
|
||||
client_max_body_size {{ getenv "POST_MAX_SIZE" "61M" }};
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /favicon.ico {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location = /robots.txt {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
error_page 404 /index.php;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
|
||||
include fastcgi_params;
|
||||
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
|
||||
location ~ /\.(?!well-known).* {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
# This is changed from the original "nginx" in upstream to work properly
|
||||
# with permissions within pixelfed when serving static files.
|
||||
user www-data;
|
||||
|
||||
worker_processes auto;
|
||||
|
||||
# Ensure the PID is writable
|
||||
# Lifted from: https://hub.docker.com/r/nginxinc/nginx-unprivileged
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
# Write error log to stderr (/proc/self/fd/2 -> /dev/stderr)
|
||||
error_log /proc/self/fd/2 notice;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
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"';
|
||||
|
||||
# Write error log to stdout (/proc/self/fd/1 -> /dev/stdout)
|
||||
access_log /proc/self/fd/1 main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
keepalive_timeout 65;
|
||||
gzip on;
|
||||
|
||||
# Ensure all temp paths are in a writable by "www-data" user.
|
||||
# Lifted from: https://hub.docker.com/r/nginxinc/nginx-unprivileged
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
proxy_temp_path /tmp/proxy_temp_path;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
# Ensure the Docker volumes and required files are owned by the runtime user as other scripts
|
||||
# will be writing to these
|
||||
run-as-current-user chown --verbose "${RUNTIME_UID}:${RUNTIME_GID}" "./.env"
|
||||
run-as-current-user chown --verbose "${RUNTIME_UID}:${RUNTIME_GID}" "./bootstrap/cache"
|
||||
run-as-current-user chown --verbose "${RUNTIME_UID}:${RUNTIME_GID}" "./storage"
|
||||
run-as-current-user chown --verbose --recursive "${RUNTIME_UID}:${RUNTIME_GID}" "./storage/docker"
|
||||
|
||||
# Optionally fix ownership of configured paths
|
||||
: "${DOCKER_APP_ENSURE_OWNERSHIP_PATHS:=""}"
|
||||
|
||||
declare -a ensure_ownership_paths=()
|
||||
IFS=' ' read -r -a ensure_ownership_paths <<<"${DOCKER_APP_ENSURE_OWNERSHIP_PATHS}"
|
||||
|
||||
if [[ ${#ensure_ownership_paths[@]} == 0 ]]; then
|
||||
log-info "No paths has been configured for ownership fixes via [\$DOCKER_APP_ENSURE_OWNERSHIP_PATHS]."
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for path in "${ensure_ownership_paths[@]}"; do
|
||||
log-info "Ensure ownership of [${path}] is correct"
|
||||
stream-prefix-command-output run-as-current-user chown --recursive "${RUNTIME_UID}:${RUNTIME_GID}" "${path}"
|
||||
done
|
||||
@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
# Validating dot-env files for any issues
|
||||
for file in "${dot_env_files[@]}"; do
|
||||
if ! file-exists "${file}"; then
|
||||
log-warning "Could not source file [${file}]: does not exists"
|
||||
continue
|
||||
fi
|
||||
|
||||
# We ignore 'dir' + 'file' rules since they are validate *host* paths
|
||||
# which do not (and should not) exists inside the container
|
||||
#
|
||||
# We disable fixer since its not interactive anyway
|
||||
run-as-current-user dottie validate --file "${file}" --ignore-rule dir,file --exclude-prefix APP_KEY --no-fix
|
||||
done
|
||||
@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NOTE:
|
||||
#
|
||||
# This file is *sourced* not run by the entrypoint runner
|
||||
# so any environment values set here will be accessible to all sub-processes
|
||||
# and future entrypoint.d scripts
|
||||
#
|
||||
# We also don't need to source `helpers.sh` since it's already available
|
||||
|
||||
entrypoint-set-script-name "${BASH_SOURCE[0]}"
|
||||
|
||||
load-config-files
|
||||
|
||||
: "${MAX_PHOTO_SIZE:=15000}"
|
||||
: "${MAX_ALBUM_LENGTH:=4}"
|
||||
|
||||
# We assign a 1MB buffer to the just-in-time calculated max post size to allow for fields and overhead
|
||||
: "${POST_MAX_SIZE_BUFFER:=1M}"
|
||||
log-info "POST_MAX_SIZE_BUFFER is set to [${POST_MAX_SIZE_BUFFER}]"
|
||||
buffer=$(numfmt --invalid=fail --from=auto --to=none --to-unit=K "${POST_MAX_SIZE_BUFFER}")
|
||||
log-info "POST_MAX_SIZE_BUFFER converted to KB is [${buffer}]"
|
||||
|
||||
# Automatically calculate the [post_max_size] value for [php.ini] and [nginx]
|
||||
log-info "POST_MAX_SIZE will be calculated by [({MAX_PHOTO_SIZE} * {MAX_ALBUM_LENGTH}) + {POST_MAX_SIZE_BUFFER}]"
|
||||
log-info " MAX_PHOTO_SIZE=${MAX_PHOTO_SIZE}"
|
||||
log-info " MAX_ALBUM_LENGTH=${MAX_ALBUM_LENGTH}"
|
||||
log-info " POST_MAX_SIZE_BUFFER=${buffer}"
|
||||
: "${POST_MAX_SIZE:=$(numfmt --invalid=fail --from=auto --from-unit=K --to=si $(((MAX_PHOTO_SIZE * MAX_ALBUM_LENGTH) + buffer)))}"
|
||||
log-info "POST_MAX_SIZE was calculated to [${POST_MAX_SIZE}]"
|
||||
|
||||
# NOTE: must export the value so it's available in other scripts!
|
||||
export POST_MAX_SIZE
|
||||
@ -1,56 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
# Show [git diff] of templates being rendered (will help verify output)
|
||||
: "${ENTRYPOINT_SHOW_TEMPLATE_DIFF:=1}"
|
||||
# Directory where templates can be found
|
||||
: "${ENTRYPOINT_TEMPLATE_DIR:=/docker/templates/}"
|
||||
# Root path to write template template_files to (default is '', meaning it will be written to /<path>)
|
||||
: "${ENTRYPOINT_TEMPLATE_OUTPUT_PREFIX:=}"
|
||||
|
||||
declare template_file relative_template_file_path output_file_dir
|
||||
|
||||
# load all dot-env config files
|
||||
load-and-export-config-files
|
||||
|
||||
|
||||
find "${ENTRYPOINT_TEMPLATE_DIR}" -follow -type f -print | while read -r template_file; do
|
||||
# Example: template_file=/docker/templates/usr/local/etc/php/php.ini
|
||||
|
||||
# The file path without the template dir prefix ($ENTRYPOINT_TEMPLATE_DIR)
|
||||
#
|
||||
# Example: /usr/local/etc/php/php.ini
|
||||
relative_template_file_path="${template_file#"${ENTRYPOINT_TEMPLATE_DIR}"}"
|
||||
|
||||
# Adds optional prefix to the output file path
|
||||
#
|
||||
# Example: /usr/local/etc/php/php.ini
|
||||
output_file_path="${ENTRYPOINT_TEMPLATE_OUTPUT_PREFIX}/${relative_template_file_path}"
|
||||
|
||||
# Remove the file from the path
|
||||
#
|
||||
# Example: /usr/local/etc/php
|
||||
output_file_dir=$(dirname "${output_file_path}")
|
||||
|
||||
# Ensure the output directory is writable
|
||||
if ! is-writable "${output_file_dir}"; then
|
||||
log-error-and-exit "${output_file_dir} is not writable"
|
||||
fi
|
||||
|
||||
# Create the output directory if it doesn't exists
|
||||
ensure-directory-exists "${output_file_dir}"
|
||||
|
||||
# Render the template
|
||||
log-info "Running [gomplate] on [${template_file}] --> [${output_file_path}]"
|
||||
gomplate <"${template_file}" >"${output_file_path}"
|
||||
|
||||
# Show the diff from the envsubst command
|
||||
if is-true "${ENTRYPOINT_SHOW_TEMPLATE_DIFF}"; then
|
||||
git --no-pager diff --color=always "${template_file}" "${output_file_path}" || : # ignore diff exit code
|
||||
fi
|
||||
done
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
# Copy the [storage/] skeleton files over the "real" [storage/] directory so assets are updated between versions
|
||||
run-as-runtime-user cp --force --recursive storage.skel/. ./storage/
|
||||
|
||||
# Ensure storage linkk are correctly configured
|
||||
run-as-runtime-user php artisan storage:link
|
||||
@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
load-config-files
|
||||
|
||||
# Allow automatic applying of outstanding/new migrations on startup
|
||||
: "${DOCKER_APP_RUN_ONE_TIME_SETUP_TASKS:=1}"
|
||||
|
||||
if is-false "${DOCKER_APP_RUN_ONE_TIME_SETUP_TASKS}"; then
|
||||
log-warning "Automatic run of the 'One-time setup tasks' is disabled."
|
||||
log-warning "Please set [DOCKER_APP_RUN_ONE_TIME_SETUP_TASKS=1] in your [.env] file to enable this."
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
await-database-ready
|
||||
|
||||
# Following https://docs.pixelfed.org/running-pixelfed/installation/#one-time-setup-tasks
|
||||
#
|
||||
# NOTE: Caches happens in [30-cache.sh]
|
||||
|
||||
only-once "key:generate" run-as-runtime-user php artisan key:generate
|
||||
only-once "storage:link" run-as-runtime-user php artisan storage:link
|
||||
only-once "initial:migrate" run-as-runtime-user php artisan migrate --force
|
||||
only-once "import:cities" run-as-runtime-user php artisan import:cities
|
||||
|
||||
if is-true "${ACTIVITY_PUB:-false}"; then
|
||||
only-once "instance:actor" run-as-runtime-user php artisan instance:actor
|
||||
fi
|
||||
|
||||
if is-true "${OAUTH_ENABLED:-false}"; then
|
||||
only-once "passport:keys" run-as-runtime-user php artisan passport:keys
|
||||
fi
|
||||
@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
# Allow automatic applying of outstanding/new migrations on startup
|
||||
: "${DB_APPLY_NEW_MIGRATIONS_AUTOMATICALLY:=0}"
|
||||
|
||||
# Wait for the database to be ready
|
||||
await-database-ready
|
||||
|
||||
# Run the migrate:status command and capture output
|
||||
output=$(run-as-runtime-user php artisan migrate:status || :)
|
||||
|
||||
# By default we have no new migrations
|
||||
declare -i new_migrations=0
|
||||
|
||||
# Detect if any new migrations are available by checking for "No" in the output
|
||||
echo "$output" | grep No && new_migrations=1
|
||||
|
||||
if is-false "${new_migrations}"; then
|
||||
log-info "No new migrations detected"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log-warning "New migrations available"
|
||||
|
||||
# Print the output
|
||||
echo "$output"
|
||||
|
||||
if is-false "${DB_APPLY_NEW_MIGRATIONS_AUTOMATICALLY}"; then
|
||||
log-info "Automatic applying of new database migrations is disabled"
|
||||
log-info "Please set [DB_APPLY_NEW_MIGRATIONS_AUTOMATICALLY=1] in your [.env] file to enable this."
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
run-as-runtime-user php artisan migrate --force
|
||||
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
run-as-runtime-user php artisan horizon:publish
|
||||
@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
|
||||
# shellcheck source=SCRIPTDIR/../helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
entrypoint-set-script-name "$0"
|
||||
|
||||
run-as-runtime-user php artisan config:cache
|
||||
run-as-runtime-user php artisan route:cache
|
||||
run-as-runtime-user php artisan view:cache
|
||||
@ -1,105 +0,0 @@
|
||||
#!/bin/bash
|
||||
# short curcuit the entrypoint if $ENTRYPOINT_SKIP isn't set to 0
|
||||
if [[ ${ENTRYPOINT_SKIP:=0} != 0 ]]; then
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
: "${ENTRYPOINT_ROOT:="/docker"}"
|
||||
export ENTRYPOINT_ROOT
|
||||
|
||||
# Directory where entrypoint scripts lives
|
||||
: "${ENTRYPOINT_D_ROOT:="${ENTRYPOINT_ROOT}/entrypoint.d/"}"
|
||||
export ENTRYPOINT_D_ROOT
|
||||
|
||||
: "${DOCKER_APP_HOST_OVERRIDES_PATH:="${ENTRYPOINT_ROOT}/overrides"}"
|
||||
export DOCKER_APP_HOST_OVERRIDES_PATH
|
||||
|
||||
# Space separated list of scripts the entrypoint runner should skip
|
||||
: "${ENTRYPOINT_SKIP_SCRIPTS:=""}"
|
||||
|
||||
# Load helper scripts
|
||||
#
|
||||
# shellcheck source=SCRIPTDIR/helpers.sh
|
||||
source "${ENTRYPOINT_ROOT}/helpers.sh"
|
||||
|
||||
# Set the entrypoint name for logging
|
||||
entrypoint-set-script-name "entrypoint.sh"
|
||||
|
||||
# Convert ENTRYPOINT_SKIP_SCRIPTS into a native bash array for easier lookup
|
||||
declare -a skip_scripts
|
||||
# shellcheck disable=SC2034
|
||||
IFS=' ' read -r -a skip_scripts <<< "$ENTRYPOINT_SKIP_SCRIPTS"
|
||||
|
||||
# Ensure the entrypoint root folder exists
|
||||
mkdir -p "${ENTRYPOINT_D_ROOT}"
|
||||
|
||||
# If ENTRYPOINT_D_ROOT directory is empty, warn and run the regular command
|
||||
if directory-is-empty "${ENTRYPOINT_D_ROOT}"; then
|
||||
log-warning "No files found in ${ENTRYPOINT_D_ROOT}, skipping configuration"
|
||||
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# If the overridess directory exists, then copy all files into the container
|
||||
if ! directory-is-empty "${DOCKER_APP_HOST_OVERRIDES_PATH}"; then
|
||||
log-info "Overrides directory is not empty, copying files"
|
||||
run-as-current-user cp --verbose --recursive "${DOCKER_APP_HOST_OVERRIDES_PATH}/." /
|
||||
fi
|
||||
|
||||
acquire-lock "entrypoint.sh"
|
||||
|
||||
# Start scanning for entrypoint.d files to source or run
|
||||
log-info "looking for shell scripts in [${ENTRYPOINT_D_ROOT}]"
|
||||
|
||||
find "${ENTRYPOINT_D_ROOT}" -follow -type f -print | sort -V | while read -r file; do
|
||||
# Skip the script if it's in the skip-script list
|
||||
if in-array "$(get-entrypoint-script-name "${file}")" skip_scripts; then
|
||||
log-warning "Skipping script [${file}] since it's in the skip list (\$ENTRYPOINT_SKIP_SCRIPTS)"
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
# Inspect the file extension of the file we're processing
|
||||
case "${file}" in
|
||||
*.envsh)
|
||||
if ! is-executable "${file}"; then
|
||||
# warn on shell scripts without exec bit
|
||||
log-error-and-exit "File [${file}] is not executable (please 'chmod +x' it)"
|
||||
fi
|
||||
|
||||
log-info "${section_message_color}============================================================${color_clear}"
|
||||
log-info "${section_message_color}Sourcing [${file}]${color_clear}"
|
||||
log-info "${section_message_color}============================================================${color_clear}"
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${file}"
|
||||
|
||||
# the sourced file will (should) than the log prefix, so this restores our own
|
||||
# "global" log prefix once the file is done being sourced
|
||||
entrypoint-restore-script-name
|
||||
;;
|
||||
|
||||
*.sh)
|
||||
if ! is-executable "${file}"; then
|
||||
# warn on shell scripts without exec bit
|
||||
log-error-and-exit "File [${file}] is not executable (please 'chmod +x' it)"
|
||||
fi
|
||||
|
||||
log-info "${section_message_color}============================================================${color_clear}"
|
||||
log-info "${section_message_color}Executing [${file}]${color_clear}"
|
||||
log-info "${section_message_color}============================================================${color_clear}"
|
||||
|
||||
"${file}"
|
||||
;;
|
||||
|
||||
*)
|
||||
log-warning "Ignoring unrecognized file [${file}]"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
release-lock "entrypoint.sh"
|
||||
|
||||
log-info "Configuration complete; ready for start up"
|
||||
|
||||
exec "$@"
|
||||
@ -1,592 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e -o errexit -o nounset -o pipefail
|
||||
|
||||
[[ ${DOCKER_APP_ENTRYPOINT_DEBUG:=0} == 1 ]] && set -x
|
||||
|
||||
: "${RUNTIME_UID:="33"}"
|
||||
: "${RUNTIME_GID:="33"}"
|
||||
|
||||
# Some splash of color for important messages
|
||||
declare -g error_message_color="\033[1;31m"
|
||||
declare -g warn_message_color="\033[1;33m"
|
||||
declare -g notice_message_color="\033[1;34m"
|
||||
declare -g success_message_color="\033[1;32m"
|
||||
# shellcheck disable=SC2034
|
||||
declare -g section_message_color="\033[1;35m"
|
||||
declare -g color_clear="\033[1;0m"
|
||||
|
||||
# Current and previous log prefix
|
||||
declare -g script_name=
|
||||
declare -g script_name_previous=
|
||||
declare -g log_prefix=
|
||||
|
||||
declare -Ag lock_fds=()
|
||||
|
||||
# dot-env files to source when reading config
|
||||
declare -a dot_env_files=(
|
||||
/var/www/.env
|
||||
)
|
||||
|
||||
declare -g docker_state_path
|
||||
docker_state_path="$(readlink -f ./storage/docker)"
|
||||
|
||||
declare -g docker_locks_path="${docker_state_path}/lock"
|
||||
declare -g docker_once_path="${docker_state_path}/once"
|
||||
|
||||
declare -g runtime_username
|
||||
runtime_username=$(id -un "${RUNTIME_UID}")
|
||||
|
||||
# We should already be in /var/www, but just to be explicit
|
||||
cd /var/www || log-error-and-exit "could not change to /var/www"
|
||||
|
||||
# @description Restore the log prefix to the previous value that was captured in [entrypoint-set-script-name ]
|
||||
# @arg $1 string The name (or path) of the entrypoint script being run
|
||||
function entrypoint-set-script-name()
|
||||
{
|
||||
script_name_previous="${script_name}"
|
||||
script_name="${1}"
|
||||
|
||||
log_prefix="[entrypoint / $(get-entrypoint-script-name "$1")] - "
|
||||
}
|
||||
|
||||
# @description Restore the log prefix to the previous value that was captured in [entrypoint-set-script-name ]
|
||||
function entrypoint-restore-script-name()
|
||||
{
|
||||
entrypoint-set-script-name "${script_name_previous}"
|
||||
}
|
||||
|
||||
# @description Run a command as the [runtime user]
|
||||
# @arg $@ string The command to run
|
||||
# @exitcode 0 if the command succeeeds
|
||||
# @exitcode 1 if the command fails
|
||||
function run-as-runtime-user()
|
||||
{
|
||||
run-command-as "${runtime_username}" "${@}"
|
||||
}
|
||||
|
||||
# @description Run a command as the [runtime user]
|
||||
# @arg $@ string The command to run
|
||||
# @exitcode 0 if the command succeeeds
|
||||
# @exitcode 1 if the command fails
|
||||
function run-as-current-user()
|
||||
{
|
||||
run-command-as "$(id -un)" "${@}"
|
||||
}
|
||||
|
||||
# @description Run a command as the a named user
|
||||
# @arg $1 string The user to run the command as
|
||||
# @arg $@ string The command to run
|
||||
# @exitcode 0 If the command succeeeds
|
||||
# @exitcode 1 If the command fails
|
||||
function run-command-as()
|
||||
{
|
||||
local -i exit_code
|
||||
local target_user
|
||||
|
||||
target_user=${1}
|
||||
shift
|
||||
|
||||
log-info-stderr "${notice_message_color}👷 Running [${*}] as [${target_user}]${color_clear}"
|
||||
|
||||
# disable error on exit behavior temporarily while we run the command
|
||||
set +e
|
||||
|
||||
if [[ ${target_user} != "root" ]]; then
|
||||
stream-prefix-command-output su --preserve-environment "${target_user}" --shell /bin/bash --command "${*}"
|
||||
else
|
||||
stream-prefix-command-output "${@}"
|
||||
fi
|
||||
|
||||
# capture exit code
|
||||
exit_code=$?
|
||||
|
||||
# re-enable exit code handling
|
||||
set -e
|
||||
|
||||
if [[ $exit_code != 0 ]]; then
|
||||
log-error "${error_message_color}❌ Error!${color_clear}"
|
||||
|
||||
return "$exit_code"
|
||||
fi
|
||||
|
||||
log-info-stderr "${success_message_color}✅ OK!${color_clear}"
|
||||
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
# @description Streams stdout from the command and echo it
|
||||
# with log prefixing.
|
||||
# @see stream-prefix-command-output
|
||||
function stream-stdout-handler()
|
||||
{
|
||||
while read -r line; do
|
||||
log-info "(stdout) ${line}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description Streams stderr from the command and echo it
|
||||
# with a bit of color and log prefixing.
|
||||
# @see stream-prefix-command-output
|
||||
function stream-stderr-handler()
|
||||
{
|
||||
while read -r line; do
|
||||
log-info-stderr "(${error_message_color}stderr${color_clear}) ${line}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description Steam stdout and stderr from a command with log prefix
|
||||
# and stdout/stderr prefix. If stdout or stderr is being piped/redirected
|
||||
# it will automatically fall back to non-prefixed output.
|
||||
# @arg $@ string The command to run
|
||||
function stream-prefix-command-output()
|
||||
{
|
||||
local stdout=stream-stdout-handler
|
||||
local stderr=stream-stderr-handler
|
||||
|
||||
# if stdout is being piped, print it like normal with echo
|
||||
if [ ! -t 1 ]; then
|
||||
# shellcheck disable=SC1007
|
||||
stdout= echo >&1 -ne
|
||||
fi
|
||||
|
||||
# if stderr is being piped, print it like normal with echo
|
||||
if [ ! -t 2 ]; then
|
||||
# shellcheck disable=SC1007
|
||||
stderr= echo >&2 -ne
|
||||
fi
|
||||
|
||||
"$@" > >($stdout) 2> >($stderr)
|
||||
}
|
||||
|
||||
# @description Print the given error message to stderr
|
||||
# @arg $message string A error message.
|
||||
# @stderr The error message provided with log prefix
|
||||
function log-error()
|
||||
{
|
||||
local msg
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
msg="$*"
|
||||
elif [[ ! -t 0 ]]; then
|
||||
read -r msg || log-error-and-exit "[${FUNCNAME[0]}] could not read from stdin"
|
||||
else
|
||||
log-error-and-exit "[${FUNCNAME[0]}] did not receive any input arguments and STDIN is empty"
|
||||
fi
|
||||
|
||||
echo -e "${error_message_color}${log_prefix}ERROR -${color_clear} ${msg}" >/dev/stderr
|
||||
}
|
||||
|
||||
# @description Print the given error message to stderr and exit 1
|
||||
# @arg $@ string A error message.
|
||||
# @stderr The error message provided with log prefix
|
||||
# @exitcode 1
|
||||
function log-error-and-exit()
|
||||
{
|
||||
log-error "$@"
|
||||
|
||||
show-call-stack
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
# @description Print the given warning message to stderr
|
||||
# @arg $@ string A warning message.
|
||||
# @stderr The warning message provided with log prefix
|
||||
function log-warning()
|
||||
{
|
||||
local msg
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
msg="$*"
|
||||
elif [[ ! -t 0 ]]; then
|
||||
read -r msg || log-error-and-exit "[${FUNCNAME[0]}] could not read from stdin"
|
||||
else
|
||||
log-error-and-exit "[${FUNCNAME[0]}] did not receive any input arguments and STDIN is empty"
|
||||
fi
|
||||
|
||||
echo -e "${warn_message_color}${log_prefix}WARNING -${color_clear} ${msg}" >/dev/stderr
|
||||
}
|
||||
|
||||
# @description Print the given message to stdout unless [ENTRYPOINT_QUIET_LOGS] is set
|
||||
# @arg $@ string A info message.
|
||||
# @stdout The info message provided with log prefix unless $ENTRYPOINT_QUIET_LOGS
|
||||
function log-info()
|
||||
{
|
||||
local msg
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
msg="$*"
|
||||
elif [[ ! -t 0 ]]; then
|
||||
read -r msg || log-error-and-exit "[${FUNCNAME[0]}] could not read from stdin"
|
||||
else
|
||||
log-error-and-exit "[${FUNCNAME[0]}] did not receive any input arguments and STDIN is empty"
|
||||
fi
|
||||
|
||||
if [ -z "${ENTRYPOINT_QUIET_LOGS:-}" ]; then
|
||||
echo -e "${notice_message_color}${log_prefix}${color_clear}${msg}"
|
||||
fi
|
||||
}
|
||||
|
||||
# @description Print the given message to stderr unless [ENTRYPOINT_QUIET_LOGS] is set
|
||||
# @arg $@ string A info message.
|
||||
# @stderr The info message provided with log prefix unless $ENTRYPOINT_QUIET_LOGS
|
||||
function log-info-stderr()
|
||||
{
|
||||
local msg
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
msg="$*"
|
||||
elif [[ ! -t 0 ]]; then
|
||||
read -r msg || log-error-and-exit "[${FUNCNAME[0]}] could not read from stdin"
|
||||
else
|
||||
log-error-and-exit "[${FUNCNAME[0]}] did not receive any input arguments and STDIN is empty"
|
||||
fi
|
||||
|
||||
if [ -z "${ENTRYPOINT_QUIET_LOGS:-}" ]; then
|
||||
echo -e "${notice_message_color}${log_prefix}${color_clear}${msg}" >/dev/stderr
|
||||
fi
|
||||
}
|
||||
|
||||
# @description Loads the dot-env files used by Docker
|
||||
function load-config-files() {
|
||||
local export_vars=0
|
||||
load-config-files-impl "$export_vars"
|
||||
}
|
||||
|
||||
# @description Loads the dot-env files used by Docker and exports the variables to subshells
|
||||
function load-and-export-config-files() {
|
||||
local export_vars=1
|
||||
load-config-files-impl "$export_vars"
|
||||
}
|
||||
|
||||
# @description Implementation of the [load-config-files] and [load-and-export-config-files] functions. Loads th
|
||||
# @arg $1 int Whether to export the variables or just have them available in the current shell
|
||||
function load-config-files-impl()
|
||||
{
|
||||
local export_vars=${1:-0}
|
||||
for file in "${dot_env_files[@]}"; do
|
||||
if ! file-exists "${file}"; then
|
||||
log-warning "Could not source file [${file}]: does not exists"
|
||||
continue
|
||||
fi
|
||||
|
||||
log-info "Sourcing ${file}"
|
||||
if ((export_vars)); then set -o allexport; fi
|
||||
# shellcheck disable=SC1090
|
||||
source "${file}"
|
||||
if ((export_vars)); then set +o allexport; fi
|
||||
done
|
||||
}
|
||||
|
||||
# @description Checks if $needle exists in $haystack
|
||||
# @arg $1 string The needle (value) to search for
|
||||
# @arg $2 array The haystack (array) to search in
|
||||
# @exitcode 0 If $needle was found in $haystack
|
||||
# @exitcode 1 If $needle was *NOT* found in $haystack
|
||||
function in-array()
|
||||
{
|
||||
local -r needle="\<${1}\>"
|
||||
local -nr haystack=$2
|
||||
|
||||
[[ ${haystack[*]} =~ $needle ]]
|
||||
}
|
||||
|
||||
# @description Checks if $1 has executable bit set or not
|
||||
# @arg $1 string The path to check
|
||||
# @exitcode 0 If $1 has executable bit
|
||||
# @exitcode 1 If $1 does *NOT* have executable bit
|
||||
function is-executable()
|
||||
{
|
||||
[[ -x "$1" ]]
|
||||
}
|
||||
|
||||
# @description Checks if $1 is writable or not
|
||||
# @arg $1 string The path to check
|
||||
# @exitcode 0 If $1 is writable
|
||||
# @exitcode 1 If $1 is *NOT* writable
|
||||
function is-writable()
|
||||
{
|
||||
[[ -w "$1" ]]
|
||||
}
|
||||
|
||||
# @description Checks if $1 exists (directory or file)
|
||||
# @arg $1 string The path to check
|
||||
# @exitcode 0 If $1 exists
|
||||
# @exitcode 1 If $1 does *NOT* exists
|
||||
function path-exists()
|
||||
{
|
||||
[[ -e "$1" ]]
|
||||
}
|
||||
|
||||
# @description Checks if $1 exists (file only)
|
||||
# @arg $1 string The path to check
|
||||
# @exitcode 0 If $1 exists
|
||||
# @exitcode 1 If $1 does *NOT* exists
|
||||
function file-exists()
|
||||
{
|
||||
[[ -f "$1" ]]
|
||||
}
|
||||
|
||||
# @description Checks if $1 contains any files or not
|
||||
# @arg $1 string The path to check
|
||||
# @exitcode 0 If $1 contains files
|
||||
# @exitcode 1 If $1 does *NOT* contain files
|
||||
function directory-is-empty()
|
||||
{
|
||||
! path-exists "${1}" || [[ -z "$(ls -A "${1}")" ]]
|
||||
}
|
||||
|
||||
# @description Ensures a directory exists (via mkdir)
|
||||
# @arg $1 string The path to create
|
||||
# @exitcode 0 If $1 If the path exists *or* was created
|
||||
# @exitcode 1 If $1 If the path does *NOT* exists and could *NOT* be created
|
||||
function ensure-directory-exists()
|
||||
{
|
||||
stream-prefix-command-output mkdir -pv "$@"
|
||||
}
|
||||
|
||||
# @description Find the relative path for a entrypoint script by removing the ENTRYPOINT_D_ROOT prefix
|
||||
# @arg $1 string The path to manipulate
|
||||
# @stdout The relative path to the entrypoint script
|
||||
function get-entrypoint-script-name()
|
||||
{
|
||||
echo "${1#"$ENTRYPOINT_D_ROOT"}"
|
||||
}
|
||||
|
||||
# @description Ensure a command is only run once (via a 'lock' file) in the storage directory.
|
||||
# The 'lock' is only written if the passed in command ($2) successfully ran.
|
||||
# @arg $1 string The name of the lock file
|
||||
# @arg $@ string The command to run
|
||||
function only-once()
|
||||
{
|
||||
local name="${1:-$script_name}"
|
||||
local file="${docker_once_path}/${name}"
|
||||
shift
|
||||
|
||||
if [[ -e "${file}" ]]; then
|
||||
log-info "Command [${*}] has already run once before (remove file [${file}] to run it again)"
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
ensure-directory-exists "$(dirname "${file}")"
|
||||
|
||||
if ! "$@"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
stream-prefix-command-output touch "${file}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# @description Best effort file lock to ensure *something* is not running in multiple containers.
|
||||
# The script uses "trap" to clean up after itself if the script crashes
|
||||
# @arg $1 string The lock identifier
|
||||
function acquire-lock()
|
||||
{
|
||||
local name="${1:-$script_name}"
|
||||
local file="${docker_locks_path}/${name}"
|
||||
local lock_fd
|
||||
|
||||
ensure-directory-exists "$(dirname "${file}")"
|
||||
|
||||
exec {lock_fd}>"$file"
|
||||
|
||||
log-info "🔑 Trying to acquire lock: ${file}: "
|
||||
while ! ([[ -v lock_fds[$name] ]] || flock -n -x "$lock_fd"); do
|
||||
log-info "🔒 Waiting on lock ${file}"
|
||||
|
||||
staggered-sleep
|
||||
done
|
||||
|
||||
[[ -v lock_fds[$name] ]] || lock_fds[$name]=$lock_fd
|
||||
|
||||
log-info "🔐 Lock acquired [${file}]"
|
||||
|
||||
on-trap "release-lock ${name}" EXIT INT QUIT TERM
|
||||
}
|
||||
|
||||
# @description Release a lock aquired by [acquire-lock]
|
||||
# @arg $1 string The lock identifier
|
||||
function release-lock()
|
||||
{
|
||||
local name="${1:-$script_name}"
|
||||
local file="${docker_locks_path}/${name}"
|
||||
|
||||
log-info "🔓 Releasing lock [${file}]"
|
||||
|
||||
[[ -v lock_fds[$name] ]] || return
|
||||
|
||||
# shellcheck disable=SC1083,SC2086
|
||||
flock --unlock ${lock_fds[$name]}
|
||||
unset 'lock_fds[$name]'
|
||||
}
|
||||
|
||||
# @description Helper function to append multiple actions onto
|
||||
# the bash [trap] logic
|
||||
# @arg $1 string The command to run
|
||||
# @arg $@ string The list of trap signals to register
|
||||
function on-trap()
|
||||
{
|
||||
local trap_add_cmd=$1
|
||||
shift || log-error-and-exit "${FUNCNAME[0]} usage error"
|
||||
|
||||
for trap_add_name in "$@"; do
|
||||
trap -- "$(
|
||||
# helper fn to get existing trap command from output
|
||||
# of trap -p
|
||||
#
|
||||
# shellcheck disable=SC2317
|
||||
extract_trap_cmd()
|
||||
{
|
||||
printf '%s\n' "${3:-}"
|
||||
}
|
||||
# print existing trap command with newline
|
||||
eval "extract_trap_cmd $(trap -p "${trap_add_name}")"
|
||||
# print the new trap command
|
||||
printf '%s\n' "${trap_add_cmd}"
|
||||
)" "${trap_add_name}" \
|
||||
|| log-error-and-exit "unable to add to trap ${trap_add_name}"
|
||||
done
|
||||
}
|
||||
|
||||
# Set the trace attribute for the above function.
|
||||
#
|
||||
# This is required to modify DEBUG or RETURN traps because functions don't
|
||||
# inherit them unless the trace attribute is set
|
||||
declare -f -t on-trap
|
||||
|
||||
# @description Waits for the database to be healthy and responsive
|
||||
function await-database-ready()
|
||||
{
|
||||
log-info "❓ Waiting for database to be ready"
|
||||
|
||||
load-config-files
|
||||
|
||||
case "${DB_CONNECTION:-}" in
|
||||
mysql)
|
||||
# shellcheck disable=SC2154
|
||||
while ! echo "SELECT 1" | mysql --user="${DB_USERNAME}" --password="${DB_PASSWORD}" --host="${DB_HOST}" --port="${DOCKER_DB_HOST_PORT}" "${DB_DATABASE}" --silent >/dev/null; do
|
||||
staggered-sleep
|
||||
done
|
||||
;;
|
||||
|
||||
pgsql)
|
||||
# shellcheck disable=SC2154
|
||||
while ! echo "SELECT 1" | PGPASSWORD="${DB_PASSWORD}" psql --user="${DB_USERNAME}" --host="${DB_HOST}" --port="${DOCKER_DB_HOST_PORT}" "${DB_DATABASE}" >/dev/null; do
|
||||
staggered-sleep
|
||||
done
|
||||
;;
|
||||
|
||||
sqlsrv)
|
||||
log-warning "Don't know how to check if SQLServer is *truely* ready or not - so will just check if we're able to connect to it"
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
while ! timeout 1 bash -c "cat < /dev/null > /dev/tcp/${DB_HOST}/${DB_PORT}"; do
|
||||
staggered-sleep
|
||||
done
|
||||
;;
|
||||
|
||||
sqlite)
|
||||
log-info "${success_message_color}sqlite is always ready${color_clear}"
|
||||
;;
|
||||
|
||||
*)
|
||||
log-error-and-exit "Unknown database type: [${DB_CONNECTION:-}]"
|
||||
;;
|
||||
esac
|
||||
|
||||
log-info "${success_message_color}✅ Successfully connected to database${color_clear}"
|
||||
}
|
||||
|
||||
# @description sleeps between 1 and 3 seconds to ensure a bit of randomness
|
||||
# in multiple scripts/containers doing work almost at the same time.
|
||||
function staggered-sleep()
|
||||
{
|
||||
sleep "$(get-random-number-between 1 3)"
|
||||
}
|
||||
|
||||
# @description Helper function to get a random number between $1 and $2
|
||||
# @arg $1 int Minimum number in the range (inclusive)
|
||||
# @arg $2 int Maximum number in the range (inclusive)
|
||||
function get-random-number-between()
|
||||
{
|
||||
local -i from=${1:-1}
|
||||
local -i to="${2:-10}"
|
||||
|
||||
shuf -i "${from}-${to}" -n 1
|
||||
}
|
||||
|
||||
# @description Helper function to show the bask call stack when something
|
||||
# goes wrong. Is super useful when needing to debug an issue
|
||||
function show-call-stack()
|
||||
{
|
||||
local stack_size=${#FUNCNAME[@]}
|
||||
local func
|
||||
local lineno
|
||||
local src
|
||||
|
||||
# to avoid noise we start with 1 to skip the get_stack function
|
||||
for ((i = 1; i < stack_size; i++)); do
|
||||
func="${FUNCNAME[$i]}"
|
||||
[ -z "$func" ] && func="MAIN"
|
||||
|
||||
lineno="${BASH_LINENO[$((i - 1))]}"
|
||||
src="${BASH_SOURCE[$i]}"
|
||||
[ -z "$src" ] && src="non_file_source"
|
||||
|
||||
log-error " at: ${func} ${src}:${lineno}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description Helper function see if $1 could be considered truthy
|
||||
# returns [0] if input is truthy, otherwise [1]
|
||||
# @arg $1 string The string to evaluate
|
||||
# @see as-boolean
|
||||
function is-true()
|
||||
{
|
||||
as-boolean "${1:-}" && return 0
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# @description Helper function see if $1 could be considered falsey
|
||||
# returns [0] if input is falsey, otherwise [1]
|
||||
# @arg $1 string The string to evaluate
|
||||
# @see as-boolean
|
||||
function is-false()
|
||||
{
|
||||
as-boolean "${1:-}" && return 1
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# @description Helper function see if $1 could be truethy or falsey.
|
||||
# since this is a bash context, returning 0 is true and 1 is false
|
||||
# so it works with [if is-false $input; then .... fi]
|
||||
#
|
||||
# This is a bit confusing, *especially* in a PHP world where [1] would be truthy and
|
||||
# [0] would be falsely as return values
|
||||
# @arg $1 string The string to evaluate
|
||||
function as-boolean()
|
||||
{
|
||||
local input="${1:-}"
|
||||
local var="${input,,}" # convert input to lower-case
|
||||
|
||||
case "$var" in
|
||||
1 | true)
|
||||
return 0
|
||||
;;
|
||||
|
||||
0 | false)
|
||||
return 1
|
||||
;;
|
||||
|
||||
*)
|
||||
log-warning "[as-boolean] variable [${var}] could not be detected as true or false, returning [1] (false) as default"
|
||||
|
||||
return 1
|
||||
;;
|
||||
|
||||
esac
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex -o errexit -o nounset -o pipefail
|
||||
|
||||
# Ensure we keep apt cache around in a Docker environment
|
||||
rm -f /etc/apt/apt.conf.d/docker-clean
|
||||
echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
|
||||
|
||||
# Don't install recommended packages by default
|
||||
echo 'APT::Install-Recommends "false";' >> /etc/apt/apt.conf
|
||||
|
||||
# Don't install suggested packages by default
|
||||
echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf
|
||||
|
||||
declare -a packages=()
|
||||
|
||||
# Standard packages
|
||||
packages+=(
|
||||
apt-utils
|
||||
bzip2
|
||||
ca-certificates
|
||||
curl
|
||||
git
|
||||
gnupg1
|
||||
gosu
|
||||
locales
|
||||
locales-all
|
||||
moreutils
|
||||
nano
|
||||
procps
|
||||
software-properties-common
|
||||
unzip
|
||||
wget
|
||||
zip
|
||||
)
|
||||
|
||||
# Image Optimization
|
||||
packages+=(
|
||||
gifsicle
|
||||
jpegoptim
|
||||
optipng
|
||||
pngquant
|
||||
)
|
||||
|
||||
# Video Processing
|
||||
packages+=(
|
||||
ffmpeg
|
||||
)
|
||||
|
||||
# Database
|
||||
packages+=(
|
||||
mariadb-client
|
||||
postgresql-client
|
||||
)
|
||||
|
||||
readarray -d ' ' -t -O "${#packages[@]}" packages < <(echo -n "${APT_PACKAGES_EXTRA:-}")
|
||||
|
||||
apt-get update
|
||||
apt-get upgrade -y
|
||||
apt-get install -y "${packages[@]}"
|
||||
|
||||
locale-gen
|
||||
update-locale
|
||||
@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex -o errexit -o nounset -o pipefail
|
||||
|
||||
declare -a pecl_extensions=()
|
||||
|
||||
readarray -d ' ' -t pecl_extensions < <(echo -n "${PHP_PECL_EXTENSIONS:-}")
|
||||
readarray -d ' ' -t -O "${#pecl_extensions[@]}" pecl_extensions < <(echo -n "${PHP_PECL_EXTENSIONS_EXTRA:-}")
|
||||
|
||||
declare -a php_extensions=()
|
||||
readarray -d ' ' -t php_extensions < <(echo -n "${PHP_EXTENSIONS:-}")
|
||||
readarray -d ' ' -t -O "${#php_extensions[@]}" php_extensions < <(echo -n "${PHP_EXTENSIONS_EXTRA:-}")
|
||||
readarray -d ' ' -t -O "${#php_extensions[@]}" php_extensions < <(echo -n "${PHP_EXTENSIONS_DATABASE:-}")
|
||||
|
||||
# Optional script folks can copy into their image to do any [docker-php-ext-configure] work before the [docker-php-ext-install]
|
||||
# this can also overwirte the [gd] configure above by simply running it again
|
||||
declare -r custom_pre_configure_script=""
|
||||
if [[ -e "${custom_pre_configure_script}" ]]; then
|
||||
if [ ! -x "${custom_pre_configure_script}" ]; then
|
||||
echo >&2 "ERROR: found ${custom_pre_configure_script} but its not executable - please [chmod +x] the file!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${custom_pre_configure_script}"
|
||||
fi
|
||||
|
||||
# PECL + PHP extensions
|
||||
IPE_KEEP_SYSPKG_CACHE=1 install-php-extensions "${pecl_extensions[@]}" "${php_extensions[@]}"
|
||||
@ -1,16 +0,0 @@
|
||||
###########################################################
|
||||
# DO NOT CHANGE
|
||||
###########################################################
|
||||
# This file is generated by the Pixelfed Docker setup, and
|
||||
# will be rewritten on every container start
|
||||
#
|
||||
# You can put any [.conf] file in this directory
|
||||
# (docker-compose-state/config/proxy/conf.d) and it will
|
||||
# be loaded by nginx on startup.
|
||||
#
|
||||
# Run [docker compose exec proxy bash -c 'nginx -t && nginx -s reload']
|
||||
# to test your config and reload the proxy
|
||||
#
|
||||
# See: https://github.com/nginx-proxy/nginx-proxy/blob/main/docs/README.md#custom-nginx-configuration
|
||||
|
||||
client_max_body_size {{ getenv "POST_MAX_SIZE" "61M" }};
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare service="${PF_SERVICE:=worker}"
|
||||
declare user="${PF_USER:=www-data}"
|
||||
|
||||
declare -a command=("bash")
|
||||
|
||||
if [[ $# -ge 1 ]]; then
|
||||
command=("$@")
|
||||
fi
|
||||
|
||||
exec docker compose exec \
|
||||
--user "${user}" \
|
||||
--env TERM \
|
||||
--env COLORTERM \
|
||||
"${service}" \
|
||||
"${command[@]}"
|
||||
@ -1,123 +0,0 @@
|
||||
# See: https://github.com/goss-org/goss/blob/master/docs/manual.md#goss-manual
|
||||
|
||||
package:
|
||||
curl: { installed: true }
|
||||
ffmpeg: { installed: true }
|
||||
gifsicle: { installed: true }
|
||||
gosu: { installed: true }
|
||||
jpegoptim: { installed: true }
|
||||
locales-all: { installed: true }
|
||||
locales: { installed: true }
|
||||
mariadb-client: { installed: true }
|
||||
nano: { installed: true }
|
||||
optipng: { installed: true }
|
||||
pngquant: { installed: true }
|
||||
postgresql-client: { installed: true }
|
||||
unzip: { installed: true }
|
||||
wget: { installed: true }
|
||||
zip: { installed: true }
|
||||
|
||||
user:
|
||||
www-data:
|
||||
exists: true
|
||||
uid: 33
|
||||
gid: 33
|
||||
groups:
|
||||
- www-data
|
||||
home: /var/www
|
||||
shell: /usr/sbin/nologin
|
||||
|
||||
command:
|
||||
php-version:
|
||||
exit-status: 0
|
||||
exec: 'php -v'
|
||||
stdout:
|
||||
- PHP {{ .Env.EXPECTED_PHP_VERSION }}
|
||||
stderr: []
|
||||
|
||||
php-extensions:
|
||||
exit-status: 0
|
||||
exec: 'php -m'
|
||||
stdout:
|
||||
- bcmath
|
||||
- Core
|
||||
- ctype
|
||||
- curl
|
||||
- date
|
||||
- dom
|
||||
- exif
|
||||
- fileinfo
|
||||
- filter
|
||||
- gd
|
||||
- hash
|
||||
- iconv
|
||||
- imagick
|
||||
- intl
|
||||
- json
|
||||
- libxml
|
||||
- mbstring
|
||||
- mysqlnd
|
||||
- openssl
|
||||
- pcntl
|
||||
- pcre
|
||||
- PDO
|
||||
- pdo_mysql
|
||||
- pdo_pgsql
|
||||
- pdo_sqlite
|
||||
- Phar
|
||||
- posix
|
||||
- readline
|
||||
- redis
|
||||
- Reflection
|
||||
- session
|
||||
- SimpleXML
|
||||
- sodium
|
||||
- SPL
|
||||
- sqlite3
|
||||
- standard
|
||||
- tokenizer
|
||||
- xml
|
||||
- xmlreader
|
||||
- xmlwriter
|
||||
- zip
|
||||
- zlib
|
||||
stderr: []
|
||||
|
||||
forego-version:
|
||||
exit-status: 0
|
||||
exec: 'forego version'
|
||||
stdout:
|
||||
- dev
|
||||
stderr: []
|
||||
|
||||
gomplate-version:
|
||||
exit-status: 0
|
||||
exec: 'gomplate -v'
|
||||
stdout:
|
||||
- gomplate version
|
||||
stderr: []
|
||||
|
||||
gosu-version:
|
||||
exit-status: 0
|
||||
exec: 'gosu -v'
|
||||
stdout:
|
||||
- '1.12'
|
||||
stderr: []
|
||||
|
||||
{{ if eq .Env.PHP_BASE_TYPE "nginx" }}
|
||||
nginx-version:
|
||||
exit-status: 0
|
||||
exec: 'nginx -v'
|
||||
stdout: []
|
||||
stderr:
|
||||
- 'nginx version: nginx'
|
||||
{{ end }}
|
||||
|
||||
{{ if eq .Env.PHP_BASE_TYPE "apache" }}
|
||||
apache-version:
|
||||
exit-status: 0
|
||||
exec: 'apachectl -v'
|
||||
stdout:
|
||||
- 'Server version: Apache/'
|
||||
stderr: []
|
||||
{{ end }}
|
||||
Loading…
Reference in New Issue