Add invoiceninja
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# IN application vars
|
||||||
|
APP_URL=http://invoiceninja.domr.ovh
|
||||||
|
APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
|
||||||
|
APP_ENV=production
|
||||||
|
APP_DEBUG=true
|
||||||
|
REQUIRE_HTTPS=false
|
||||||
|
PHANTOMJS_PDF_GENERATION=false
|
||||||
|
PDF_GENERATOR=snappdf
|
||||||
|
TRUSTED_PROXIES='*'
|
||||||
|
|
||||||
|
|
||||||
|
CACHE_DRIVER=redis
|
||||||
|
QUEUE_CONNECTION=redis
|
||||||
|
SESSION_DRIVER=redis
|
||||||
|
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
FILESYSTEM_DISK=debian_docker
|
||||||
|
|
||||||
|
# DB connection
|
||||||
|
DB_HOST=mysql
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=ninja
|
||||||
|
DB_USERNAME=ninja
|
||||||
|
DB_PASSWORD=ninja
|
||||||
|
DB_ROOT_PASSWORD=80DKugiSxJb5Sr
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
|
||||||
|
# Create initial user
|
||||||
|
# Default to these values if empty
|
||||||
|
IN_USER_EMAIL=admin@domroese.eu
|
||||||
|
IN_PASSWORD=zLI6XKwwXiWhSu
|
||||||
|
# IN_USER_EMAIL=
|
||||||
|
# IN_PASSWORD=
|
||||||
|
|
||||||
|
# Mail options
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_HOST=smtp.mailtrap.io
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS='soenke@domroese.eu'
|
||||||
|
MAIL_FROM_NAME='Sönke Domröse - InvoiceNinja'
|
||||||
|
|
||||||
|
# MySQL
|
||||||
|
MYSQL_ROOT_PASSWORD=80DKugiSxJb5Sr
|
||||||
|
MYSQL_USER=ninja
|
||||||
|
MYSQL_PASSWORD=ninja
|
||||||
|
MYSQL_DATABASE=ninja
|
||||||
|
|
||||||
|
# GoCardless/Nordigen API key for banking integration
|
||||||
|
NORDIGEN_SECRET_ID=
|
||||||
|
NORDIGEN_SECRET_KEY=
|
||||||
|
|
||||||
|
IS_DOCKER=true
|
||||||
|
SCOUT_DRIVER=null
|
||||||
|
#SNAPPDF_CHROMIUM_PATH=/usr/bin/google-chrome-stable
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
invoiceninja.domr.ovh,
|
||||||
|
invoiceninja.home.domroese.eu {
|
||||||
|
tls soenke@domroese.eu
|
||||||
|
reverse_proxy 192.168.1.65:8012
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
ARG PHP=8.4
|
||||||
|
|
||||||
|
FROM php:${PHP}-fpm AS prepare-app
|
||||||
|
|
||||||
|
ARG URL=https://github.com/invoiceninja/invoiceninja/releases/latest/download/invoiceninja.tar.gz
|
||||||
|
|
||||||
|
ADD ${URL} /tmp/invoiceninja.tar.gz
|
||||||
|
|
||||||
|
RUN tar -xzf /tmp/invoiceninja.tar.gz -C /var/www/html \
|
||||||
|
&& ln -s /var/www/html/resources/views/react/index.blade.php /var/www/html/public/index.html \
|
||||||
|
&& php artisan storage:link \
|
||||||
|
# Workaround for application updates
|
||||||
|
&& mv /var/www/html/public /tmp/public
|
||||||
|
|
||||||
|
# ==================
|
||||||
|
# InvoiceNinja image
|
||||||
|
# ==================
|
||||||
|
FROM php:${PHP}-fpm
|
||||||
|
|
||||||
|
# PHP modules
|
||||||
|
ARG php_require="bcmath gd mbstring pdo_mysql zip"
|
||||||
|
ARG php_suggest="exif imagick intl pcntl saxon soap"
|
||||||
|
ARG php_extra="opcache"
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libfcgi-bin \
|
||||||
|
mariadb-client \
|
||||||
|
gpg \
|
||||||
|
rsync \
|
||||||
|
supervisor \
|
||||||
|
# Unicode support for PDF
|
||||||
|
fonts-noto-cjk-extra \
|
||||||
|
fonts-wqy-microhei \
|
||||||
|
fonts-wqy-zenhei \
|
||||||
|
xfonts-wqy \
|
||||||
|
# Install google-chrome-stable(amd64)/chromium(arm64)
|
||||||
|
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
|
||||||
|
mkdir -p /etc/apt/keyrings \
|
||||||
|
&& curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | \
|
||||||
|
gpg --dearmor -o /etc/apt/keyrings/google.gpg \
|
||||||
|
&& echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google.gpg] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends google-chrome-stable; \
|
||||||
|
elif [ "$(dpkg --print-architecture)" = "arm64" ]; then \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
chromium; \
|
||||||
|
fi \
|
||||||
|
# Create config directory for chromium/google-chrome-stable
|
||||||
|
&& mkdir /var/www/.config \
|
||||||
|
&& chown www-data:www-data /var/www/.config \
|
||||||
|
# Cleanup
|
||||||
|
&& apt-get purge -y gpg \
|
||||||
|
&& apt-get autoremove -y \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
COPY --from=ghcr.io/mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
|
||||||
|
|
||||||
|
RUN install-php-extensions \
|
||||||
|
${php_require} \
|
||||||
|
${php_suggest} \
|
||||||
|
${php_extra}
|
||||||
|
|
||||||
|
# Configure PHP
|
||||||
|
RUN ln -s "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||||
|
|
||||||
|
COPY php/php.ini /usr/local/etc/php/conf.d/invoiceninja.ini
|
||||||
|
|
||||||
|
COPY php/php-fpm.conf /usr/local/etc/php-fpm.d/invoiceninja.conf
|
||||||
|
|
||||||
|
# Workaround: Disable SSL for mariadb-client for compatibility with MySQL
|
||||||
|
RUN echo "skip-ssl = true" >> /etc/mysql/mariadb.conf.d/50-client.cnf
|
||||||
|
|
||||||
|
# Setup supervisor
|
||||||
|
COPY supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# Setup InvoiceNinja
|
||||||
|
COPY --from=prepare-app --chown=www-data:www-data /var/www/html /var/www/html
|
||||||
|
COPY --from=prepare-app --chown=www-data:www-data /tmp/public /tmp/public
|
||||||
|
|
||||||
|
# Add initialization script
|
||||||
|
COPY --chmod=0755 scripts/init.sh /usr/local/bin/init.sh
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --start-period=100s \
|
||||||
|
CMD REMOTE_ADDR=127.0.0.1 REQUEST_URI=/health REQUEST_METHOD=GET SCRIPT_FILENAME=/var/www/html/public/index.php cgi-fcgi -bind -connect 127.0.0.1:9000 | grep '{"status":"ok","message":"API is healthy"}'
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/init.sh"]
|
||||||
|
CMD ["supervisord", "-c", "/etc/supervisor/supervisord.conf"]
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: debian
|
||||||
|
image: invoiceninja/invoiceninja-debian:${TAG:-latest}
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
# - ./php/php.ini:/usr/local/etc/php/conf.d/invoiceninja.ini:ro
|
||||||
|
# - ./php/php-fpm.conf:/usr/local/etc/php-fpm.d/invoiceninja.conf:ro
|
||||||
|
# - ./supervisor/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf:ro
|
||||||
|
- /home/soenke/docker-data/invoiceninja/app_public:/var/www/html/public
|
||||||
|
- /home/soenke/docker-data/invoiceninja/app_storage:/var/www/html/storage
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8012:80"
|
||||||
|
volumes:
|
||||||
|
- /home/soenke/docker-data/invoiceninja/nginx:/etc/nginx/conf.d:ro
|
||||||
|
- /home/soenke/docker-data/invoiceninja/app_public:/var/www/html/public:ro
|
||||||
|
- /home/soenke/docker-data/invoiceninja/app_storage:/var/www/html/storage:ro
|
||||||
|
depends_on:
|
||||||
|
app:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:8
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_DATABASE: ${DB_DATABASE}
|
||||||
|
MYSQL_USER: ${DB_USERNAME}
|
||||||
|
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- /home/soenke/docker-data/invoiceninja/mysql_data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD",
|
||||||
|
"mysqladmin",
|
||||||
|
"ping",
|
||||||
|
"-h",
|
||||||
|
"localhost",
|
||||||
|
"-u${MYSQL_USER}",
|
||||||
|
"-p${MYSQL_PASSWORD}",
|
||||||
|
]
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /home/soenke/docker-data/invoiceninja/redis_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# https://nginx.org/en/docs/http/ngx_http_core_module.html
|
||||||
|
client_max_body_size 10M;
|
||||||
|
client_body_buffer_size 10M;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
# https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html
|
||||||
|
fastcgi_buffers 32 16K;
|
||||||
|
|
||||||
|
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||||
|
gzip on;
|
||||||
|
gzip_comp_level 2;
|
||||||
|
gzip_min_length 1M;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_types *;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# https://laravel.com/docs/master/deployment#nginx
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
server_name _;
|
||||||
|
root /var/www/html/public;
|
||||||
|
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
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_pass app:9000;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.(?!well-known).* {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pm.max_children = 10
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[core]
|
||||||
|
; https://www.php.net/manual/en/ini.core.php
|
||||||
|
post_max_size=10M
|
||||||
|
upload_max_filesize=10M
|
||||||
|
memory_limit=512M
|
||||||
|
|
||||||
|
[opcache]
|
||||||
|
; https://www.php.net/manual/en/opcache.installation.php#opcache.installation.recommended
|
||||||
|
opcache.enable_cli=1
|
||||||
|
|
||||||
|
[jit]
|
||||||
|
; https://wiki.php.net/rfc/jit_config_defaults
|
||||||
|
opcache.jit=tracing
|
||||||
|
opcache.jit_buffer_size=64M
|
||||||
|
|
||||||
|
[extra]
|
||||||
|
; http://symfony.com/doc/current/performance.html
|
||||||
|
opcache.memory_consumption=256
|
||||||
|
opcache.max_accelerated_files=20000
|
||||||
|
opcache.preload=/var/www/html/preload.php
|
||||||
|
opcache.preload_user=www-data
|
||||||
|
opcache.validate_timestamps=0
|
||||||
|
realpath_cache_size = 4096K
|
||||||
|
realpath_cache_ttl = 600
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/sh -eu
|
||||||
|
|
||||||
|
# Set PDF generation browser path based on architecture
|
||||||
|
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
|
||||||
|
export SNAPPDF_CHROMIUM_PATH=/usr/bin/google-chrome-stable
|
||||||
|
elif [ "$(dpkg --print-architecture)" = "arm64" ]; then
|
||||||
|
export SNAPPDF_CHROMIUM_PATH=/usr/bin/chromium
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$*" = 'supervisord -c /etc/supervisor/supervisord.conf' ]; then
|
||||||
|
|
||||||
|
# Check for required folders and create if needed
|
||||||
|
[ -d /var/www/html/public ] || mkdir -p /var/www/html/public
|
||||||
|
[ -d /var/www/html/storage/app/public ] || mkdir -p /var/www/html/storage/app/public
|
||||||
|
[ -d /var/www/html/storage/framework/sessions ] || mkdir -p /var/www/html/storage/framework/sessions
|
||||||
|
[ -d /var/www/html/storage/framework/views ] || mkdir -p /var/www/html/storage/framework/views
|
||||||
|
[ -d /var/www/html/storage/framework/cache ] || mkdir -p /var/www/html/storage/framework/cache
|
||||||
|
|
||||||
|
# Workaround for application updates
|
||||||
|
if [ "$(ls -A /tmp/public)" ]; then
|
||||||
|
echo "Updating public folder..."
|
||||||
|
rm -rf /var/www/html/public/.htaccess \
|
||||||
|
/var/www/html/public/.well-known \
|
||||||
|
/var/www/html/public/*
|
||||||
|
cp -r /tmp/public/* \
|
||||||
|
/tmp/public/.htaccess \
|
||||||
|
/tmp/public/.well-known \
|
||||||
|
/var/www/html/public/ &&
|
||||||
|
rm -rf /tmp/public/.htaccess \
|
||||||
|
/tmp/public/.well-known \
|
||||||
|
/tmp/public/*
|
||||||
|
|
||||||
|
fi
|
||||||
|
echo "Public Folder is up to date"
|
||||||
|
|
||||||
|
# Ensure owner, file and directory permissions are correct
|
||||||
|
chown -R www-data:www-data \
|
||||||
|
/var/www/html/public \
|
||||||
|
/var/www/html/storage
|
||||||
|
find /var/www/html/public \
|
||||||
|
/var/www/html/storage \
|
||||||
|
-type f -exec chmod 644 {} \;
|
||||||
|
find /var/www/html/public \
|
||||||
|
/var/www/html/storage \
|
||||||
|
-type d -exec chmod 755 {} \;
|
||||||
|
|
||||||
|
# Clear and cache config in production
|
||||||
|
if [ "$APP_ENV" = "production" ]; then
|
||||||
|
runuser -u www-data -- php artisan migrate --force
|
||||||
|
runuser -u www-data -- php artisan cache:clear # Clear after the migration
|
||||||
|
runuser -u www-data -- php artisan ninja:design-update
|
||||||
|
runuser -u www-data -- php artisan optimize
|
||||||
|
|
||||||
|
# If first IN run, it needs to be initialized
|
||||||
|
if [ "$(runuser -u www-data -- php artisan tinker --execute='echo Schema::hasTable("accounts") && !App\Models\Account::all()->first();')" = "1" ]; then
|
||||||
|
echo "Running initialization..."
|
||||||
|
|
||||||
|
runuser -u www-data -- php artisan db:seed --force
|
||||||
|
|
||||||
|
if [ -n "${IN_USER_EMAIL}" ] && [ -n "${IN_PASSWORD}" ]; then
|
||||||
|
runuser -u www-data -- php artisan ninja:create-account --email "${IN_USER_EMAIL}" --password "${IN_PASSWORD}"
|
||||||
|
else
|
||||||
|
echo "Initialization failed - Set IN_USER_EMAIL and IN_PASSWORD in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
echo "Production setup completed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting supervisord..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
command=/usr/local/sbin/php-fpm -F
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=5
|
||||||
|
stdout_logfile=/dev/fd/1
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:queue-worker]
|
||||||
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --max-time=3600 --verbose
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
user=www-data
|
||||||
|
numprocs=2
|
||||||
|
environment=HOME="/var/www"
|
||||||
|
stdout_logfile=/dev/fd/1
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
redirect_stderr=true
|
||||||
|
stopwaitsecs=3600
|
||||||
|
|
||||||
|
[program:scheduler]
|
||||||
|
command=php /var/www/html/artisan schedule:work --verbose
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
user=www-data
|
||||||
|
stdout_logfile=/dev/fd/1
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
redirect_stderr=true
|
||||||
Reference in New Issue
Block a user