Работа над контейнером docker

Изменения в конфигах nginx
Добавил привязку сервисов к 1 адресу
This commit is contained in:
brusnitsyn
2026-07-28 11:46:07 +09:00
parent 5fed7f51a8
commit e1579c7b4e
14 changed files with 265 additions and 114 deletions

View File

@@ -62,6 +62,11 @@ RUN composer install \
COPY . .
ENV BROADCAST_CONNECTION=log \
PUSHER_APP_ID=local \
PUSHER_APP_KEY=local \
PUSHER_APP_SECRET=local
RUN composer dump-autoload --optimize
RUN chown -R application:application /var/www/html && \
@@ -142,6 +147,10 @@ COPY docker/openssl.cnf /etc/ssl/openssl.cnf
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/app.conf /etc/nginx/conf.d/default.conf
COPY docker/supervisord.conf /etc/supervisor/supervisord.conf
COPY docker/entrypoint.sh /entrypoint.sh
COPY docker/php-fpm-pool.conf /usr/local/etc/php-fpm.d/www.conf
RUN rm -f /etc/nginx/conf.d/10-docker.conf
WORKDIR /var/www/html
@@ -149,7 +158,13 @@ COPY --chown=application:application --from=php-build /var/www/html .
COPY --chown=application:application --from=node-build /var/www/html/public/build ./public/build
RUN chown -R application:application /var/www/html && \
chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache && \
chmod +x /entrypoint.sh
ENV BROADCAST_CONNECTION=log \
PUSHER_APP_ID=local \
PUSHER_APP_KEY=local \
PUSHER_APP_SECRET=local
RUN php artisan storage:link
@@ -158,4 +173,5 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
EXPOSE 80
CMD ["supervisord", "-c", "/etc/supervisor.d/supervisord.conf"]
ENTRYPOINT ["/entrypoint.sh"]
#CMD ["supervisord", "-c", "/etc/supervisor.d/supervisord.conf"]

View File

@@ -11,6 +11,7 @@ return Application::configure(basePath: dirname(__DIR__))
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {

11
config/vue.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
return [
'sentry' => [
'id' => env('SENTRY_VUE_ID'),
'dsn' => env('SENTRY_VUE_DSN'),
],
'time' => [
'url' => env('TIME_EVENT_SOURCE_URL')
]
];

View File

@@ -1,7 +1,7 @@
services:
#PHP Service
app:
image: registry.brusoff.su/aokb-onboard:2026.06-dev
image: registry.brusoff.su/aokb-onboard:2026.07.8-dev
build: .
container_name: aokb_onboard_app
restart: unless-stopped
@@ -18,13 +18,13 @@ services:
- ./.env:/var/www/html/.env
- ./docker/php.ini:/usr/local/etc/php/conf.d/app.ini
- ./docker/blocked_ips.map:/etc/nginx/blocked_ips.map
- ./storage/logs:/var/www/storage/logs
- ./logs:/var/www/html/storage/logs
networks:
- aokb-onboard-network
#Queue Worker
queue:
image: registry.brusoff.su/aokb-onboard:2026.06-dev
image: registry.brusoff.su/aokb-onboard:2026.07.8-dev
build: .
container_name: aokb_onboard_queue
restart: unless-stopped
@@ -40,13 +40,13 @@ services:
volumes:
- ./.env:/var/www/html/.env
- ./docker/php.ini:/usr/local/etc/php/conf.d/app.ini
- ./storage/logs:/var/www/storage/logs
# - ./logs/queue.log:/var/www/html/storage/logs/laravel.log
networks:
- aokb-onboard-network
#Scheduler (одиночный — планировщик Laravel)
scheduler:
image: registry.brusoff.su/aokb-onboard:2026.06-dev
image: registry.brusoff.su/aokb-onboard:2026.07.8-dev
build: .
container_name: aokb_onboard_scheduler
restart: unless-stopped
@@ -62,7 +62,29 @@ services:
volumes:
- ./.env:/var/www/html/.env
- ./docker/php.ini:/usr/local/etc/php/conf.d/app.ini
- ./storage/logs:/var/www/storage/logs
# - ./logs/scheduler.log:/var/www/html/storage/logs/laravel.log
networks:
- aokb-onboard-network
#Reverb (WebSocket-сервер для broadcasting)
reverb:
image: registry.brusoff.su/aokb-onboard:2026.07.8-dev
build: .
container_name: aokb_onboard_reverb
restart: unless-stopped
working_dir: /var/www/html
command: php artisan reverb:start --host=0.0.0.0 --port=8080
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- QUEUE_CONNECTION=redis
depends_on:
- redis
- app
volumes:
- ./.env:/var/www/html/.env
- ./docker/php.ini:/usr/local/etc/php/conf.d/app.ini
- ./logs:/var/www/html/storage/logs
networks:
- aokb-onboard-network

View File

@@ -8,7 +8,7 @@ server {
listen 80;
server_name _;
root /var/www/public;
root /var/www/html/public;
index index.php index.html;
# ========== ОСНОВНЫЕ НАСТРОЙКИ БЕЗОПАСНОСТИ ==========
@@ -35,8 +35,8 @@ server {
location ~ \.php$ {
# Дефолтные лимиты для всех PHP запросов
limit_req zone=req_limit_per_ip burst=30 delay=15;
limit_conn conn_limit_per_ip 30;
limit_req zone=req_limit_per_ip burst=100 delay=15;
limit_conn conn_limit_per_ip 60;
try_files $uri =404;
@@ -60,6 +60,43 @@ server {
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# ========== REVERB (WEBSOCKET) ==========
# Клиент бьёт в /app/{key} (WS), серверный broadcast — в /apps/{id}/... (REST).
# Оба идут на тот же домен/порт, что и само приложение.
location /app/ {
proxy_pass http://reverb:8080;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 60s;
}
location /apps/ {
proxy_pass http://reverb:8080;
proxy_http_version 1.1;
proxy_set_header Host $http_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;
}
# ========== Sentry ==========
location /sentry/ {
proxy_pass http://10.32.0.213:50/;
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;
}
# ========== ОСНОВНОЙ LOCATION ==========
location / {

16
docker/entrypoint.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
set -e
# Исправляем владельца и права на storage (включая логи) при каждом запуске
if [ -d /var/www/html/storage ]; then
mkdir -p /var/www/html/storage/logs/supervisor /var/www/html/storage/logs/nginx
chown -R application:application /var/www/html/storage
chmod -R 775 /var/www/html/storage
fi
# Если переданы аргументы выполняем их, иначе запускаем supervisord
if [ $# -eq 0 ]; then
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
else
exec "$@"
fi

View File

@@ -1,3 +1,4 @@
user application application;
worker_processes auto;
worker_rlimit_nofile 65535;
@@ -13,7 +14,13 @@ events {
http {
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=50r/s;
# Для проксирования WebSocket (Reverb) через тот же домен/порт.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
@@ -43,8 +50,8 @@ http {
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss
application/atom+xml image/svg+xml;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
access_log /var/www/html/storage/logs/nginx/access.log;
error_log /var/www/html/storage/logs/nginx/error.log;
limit_req_status 429;
limit_conn_status 429;

13
docker/php-fpm-pool.conf Normal file
View File

@@ -0,0 +1,13 @@
[www]
user = application
group = application
listen = 9000
; или listen = /var/run/php/php8.3-fpm.sock
listen.owner = application
listen.group = application
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

View File

@@ -1,6 +1,6 @@
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisor.log
logfile=/var/www/html/storage/logs/supervisor/supervisor.log
logfile_maxbytes=50MB
logfile_backups=3
@@ -9,8 +9,8 @@ command=/usr/local/sbin/php-fpm -F
autostart=true
autorestart=true
priority=5
stdout_logfile=/var/log/supervisor/php-fpm.log
stderr_logfile=/var/log/supervisor/php-fpm_err.log
stdout_logfile=/var/www/html/storage/logs/supervisor/php-fpm.log
stderr_logfile=/var/www/html/storage/logs/supervisor/php-fpm_err.log
logfile_maxbytes=50MB
logfile_backups=3
@@ -19,7 +19,5 @@ command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
priority=10
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx_err.log
logfile_maxbytes=50MB
logfile_backups=3

151
package-lock.json generated
View File

@@ -8,7 +8,7 @@
"@arco-design/color": "^0.4.0",
"@floating-ui/vue": "^2.0.1",
"@inertiajs/vue3": "^2.3.4",
"@sentry/vue": "^10.43.0",
"@sentry/vue": "^10.68.0",
"@vitejs/plugin-vue": "^6.0.2",
"@vue-flow/core": "^1.48.1",
"@vueuse/core": "^14.1.0",
@@ -1018,96 +1018,111 @@
"win32"
]
},
"node_modules/@sentry-internal/browser-utils": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.43.0.tgz",
"integrity": "sha512-8zYTnzhAPvNkVH1Irs62wl0J/c+0QcJ62TonKnzpSFUUD3V5qz8YDZbjIDGfxy+1EB9fO0sxtddKCzwTHF/MbQ==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.43.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.43.0.tgz",
"integrity": "sha512-YoXuwluP6eOcQxTeTtaWb090++MrLyWOVsUTejzUQQ6LFL13Jwt+bDPF1kvBugMq4a7OHw/UNKQfd6//rZMn2g==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.43.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.43.0.tgz",
"integrity": "sha512-khCXlGrlH1IU7P5zCEAJFestMeH97zDVCekj8OsNNDtN/1BmCJ46k6Xi0EqAUzdJgrOLJeLdoYdgtiIjovZ8Sg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.43.0",
"@sentry/core": "10.43.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.43.0.tgz",
"integrity": "sha512-ZIw1UNKOFXo1LbPCJPMAx9xv7D8TMZQusLDUgb6BsPQJj0igAuwd7KRGTkjjgnrwBp2O/sxcQFRhQhknWk7QPg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/replay": "10.43.0",
"@sentry/core": "10.43.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/browser": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.43.0.tgz",
"integrity": "sha512-2V3I3sXi3SMeiZpKixd9ztokSgK27cmvsD9J5oyOyjhGLTW/6QKCwHbKnluMgQMXq20nixQk5zN4wRjRUma3sg==",
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.68.0.tgz",
"integrity": "sha512-8xVgk7oG2lajXnbXF6a7H1xMZ/U6icqSldHGzQu1+bajfrK8Gan9ULG/Xsj1VM1LlNeK6/7znDJ3u1jgvIwznw==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.43.0",
"@sentry-internal/feedback": "10.43.0",
"@sentry-internal/replay": "10.43.0",
"@sentry-internal/replay-canvas": "10.43.0",
"@sentry/core": "10.43.0"
"@sentry/browser-utils": "10.68.0",
"@sentry/conventions": "^0.16.0",
"@sentry/core": "10.68.0",
"@sentry/feedback": "10.68.0",
"@sentry/replay": "10.68.0",
"@sentry/replay-canvas": "10.68.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/browser-utils": {
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/browser-utils/-/browser-utils-10.68.0.tgz",
"integrity": "sha512-be8VtdjCngKc77cstJeV+gO15iH+blyXpBDk8yOehmtX4BkFO33mfTMNCWVR2LA0oOxjIHWRAhf77fIUEhzxPg==",
"license": "MIT",
"dependencies": {
"@sentry/conventions": "^0.16.0",
"@sentry/core": "10.68.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/conventions": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@sentry/conventions/-/conventions-0.16.0.tgz",
"integrity": "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@sentry/core": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.43.0.tgz",
"integrity": "sha512-l0SszQAPiQGWl/ferw8GP3ALyHXiGiRKJaOvNmhGO+PrTQyZTZ6OYyPnGijAFRg58dE1V3RCH/zw5d2xSUIiNg==",
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.68.0.tgz",
"integrity": "sha512-5Amhx8ltVz7vb1bRGyf3c4J69/iHW8R/H+SJxTRILHlsSOBrnVVc/IQEYDC6PTRdRdZ3x2u7RVjxZi2Mhe525g==",
"license": "MIT",
"dependencies": {
"@sentry/conventions": "^0.16.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/feedback": {
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/feedback/-/feedback-10.68.0.tgz",
"integrity": "sha512-XbdcXiBnpC3vgw46eHOPeD/ZQ+XzluP75ubdUcaPDW02hCh2nsdXiwjZ2DBImbpvIpTbJgjHf/sIlHWvcZJ2Mg==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.68.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/replay": {
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-10.68.0.tgz",
"integrity": "sha512-ZoG2n16vbkx4GWSCnLIqUUN9xlUmccQFbQ2US2rhruQeHTUnHl/ukr8NHOQXZaEbwKyMkX9bEMwfmZHJm+wSTQ==",
"license": "MIT",
"dependencies": {
"@sentry/browser-utils": "10.68.0",
"@sentry/core": "10.68.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/replay-canvas": {
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/replay-canvas/-/replay-canvas-10.68.0.tgz",
"integrity": "sha512-HusYcr+He+ohnUDHunYrc5St6vdDnBXpUAndnT5ReyUMVSCiWKfY3paXowU/0787HwYfxdcpZgwC5u79+XbEIg==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.68.0",
"@sentry/replay": "10.68.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/vue": {
"version": "10.43.0",
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.43.0.tgz",
"integrity": "sha512-PYBJVHfd7JwnQv92sTnsfLVNwVEKY2wQzXt9aux6QNcKh4g3pyK68PoEBrcCSEHpUb7zs3lJedk3+aeX+kN7fw==",
"version": "10.68.0",
"resolved": "https://registry.npmjs.org/@sentry/vue/-/vue-10.68.0.tgz",
"integrity": "sha512-d8hqDHN+hRDBZx9YmVklVOPw12bGPlO0xFxVNHjJP3OxSkECoOy/eL2ucjR4O7hTyZnYcQdWMZWRo6siTCYZ5g==",
"license": "MIT",
"dependencies": {
"@sentry/browser": "10.43.0",
"@sentry/core": "10.43.0"
"@sentry/browser": "10.68.0",
"@sentry/conventions": "^0.16.0",
"@sentry/core": "10.68.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@tanstack/vue-router": "^1.64.0",
"pinia": "2.x || 3.x",
"pinia": "2.x || 3.x || 4.x",
"vue": "2.x || 3.x"
},
"peerDependenciesMeta": {

View File

@@ -21,7 +21,7 @@
"@arco-design/color": "^0.4.0",
"@floating-ui/vue": "^2.0.1",
"@inertiajs/vue3": "^2.3.4",
"@sentry/vue": "^10.43.0",
"@sentry/vue": "^10.68.0",
"@vitejs/plugin-vue": "^6.0.2",
"@vue-flow/core": "^1.48.1",
"@vueuse/core": "^14.1.0",

View File

@@ -1,5 +1,5 @@
import { createApp, h } from 'vue'
import { createInertiaApp, router } from '@inertiajs/vue3'
import {createInertiaApp, router, usePage} from '@inertiajs/vue3'
import {createPinia} from "pinia";
import {setupNaiveDiscreteApi} from "./Plugins/NaiveUI.js";
import * as Sentry from "@sentry/vue";
@@ -8,9 +8,12 @@ import './bootstrap';
import '../css/app.css';
import {NConfigProvider, NDialogProvider, NMessageProvider, ruRU, dateRuRU, darkTheme} from "naive-ui";
import { ZiggyVue } from 'ziggy-js';
import {browserTracingIntegration} from "@sentry/vue";
router.on('start', () => {
router.on('start', (event) => {
startGlobalLoading()
Sentry.setTag('route', event.detail.visit?.component || 'unknown');
Sentry.setTag('url', window.location.href);
})
router.on('finish', () => {
@@ -21,8 +24,11 @@ router.on('invalid', () => {
stopGlobalLoading()
})
router.on('exception', () => {
router.on('exception', (event) => {
stopGlobalLoading()
if (event.error) {
Sentry.captureException(event.error);
}
})
const themeOverrides = {
@@ -41,6 +47,16 @@ const themeOverrides = {
},
}
// Получаем ключ и ID из мета-тегов
const keyMeta = document.querySelector('meta[name="sentry-key"]');
const idMeta = document.querySelector('meta[name="sentry-id"]');
const sentryKey = keyMeta ? keyMeta.getAttribute('content') : '';
const sentryId = idMeta ? idMeta.getAttribute('content') : '';
const dsn = sentryKey && sentryId
? `${window.location.protocol}//${sentryKey}@${window.location.host}/sentry/${sentryId}`
: ''
createInertiaApp({
id: 'onboard',
resolve: name => {
@@ -71,21 +87,21 @@ createInertiaApp({
setupNaiveDiscreteApi(vueApp)
// Sentry.init({
// vueApp,
// dsn: import.meta.env.VITE_SENTRY_DNS,
// // Setting this option to true will send default PII data to Sentry.
// // For example, automatic IP address collection on events
// sendDefaultPii: true,
// integrations: [
// Sentry.replayIntegration()
// ],
// // Session Replay
// replaysSessionSampleRate: 0, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
// replaysOnErrorSampleRate: 0.5, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.,
// // Logs
// enableLogs: true
// });
Sentry.init({
vueApp,
dsn: dsn,
// Setting this option to true will send default PII data to Sentry.
// For example, automatic IP address collection on events
sendDefaultPii: true,
integrations: [
Sentry.replayIntegration(),
],
// Session Replay
replaysSessionSampleRate: 0, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 0.5, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.,
// Logs
enableLogs: true
});
vueApp.mount(el)
},

View File

@@ -12,10 +12,10 @@ const MAX_REVERB_FAILS = 3;
window.Echo = new Echo({
broadcaster: 'reverb',
key: window.reverb.key,
wsHost: window.reverb.host,
wsPort: window.reverb.port ?? 8080,
wssPort: window.reverb.port ?? 8080,
forceTLS: (window.reverb.scheme ?? 'http') === 'https',
wsHost: window.location.hostname,
wsPort: window.location.port,
wssPort: window.location.port,
forceTLS: window.location.protocol === 'https:',
enabledTransports: ['ws', 'wss'],
withCredentials: true,
});

View File

@@ -3,15 +3,14 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="sentry-key" content="{{ config('vue.sentry.dsn') }}">
<meta name="sentry-id" content="{{ config('vue.sentry.id') }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<script>
window.reverb = {
key: "{{ env('REVERB_APP_KEY') }}",
host: "{{ env('REVERB_APP_HOST') }}",
port: "{{ env('REVERB_APP_PORT') }}",
scheme: "{{ env('REVERB_APP_SCHEME') }}",
key: "{{ config('reverb.apps.apps.0.key') }}",
}
</script>