<%= p.name %> <% var isLaravel = p.runtime === 'laravel'; %> <%= isLaravel ? 'fpm' : 'pm2' %>: <%= pm2State %> <% if (isLaravel) { %>Laravel · PHP <%= info.PHP_VERSION || '?' %><% } %> <% if (isLaravel && (info.QUEUE_WORKER || 'off') === 'on') { %> queue: <%= queueState %> <% } %> <% if (history.length) { %> <%= h.depLabel(history[0].status) %> <% } %>

<% if (msg) { %>
<%= msg %>
<% } %> <% if (err) { %>
<%= err %>
<% } %>
<% if (snapshotMtimeMs) { %> <% if (primaryDomain) { %><% } %> Homepage snapshot of <%= p.name %> <% if (primaryDomain) { %><% } %>
snapshot of current deployment · <%= h.relTimeMs(snapshotMtimeMs) %>
<% } else if (primaryDomain) { %>
snapshot pending — reload shortly
<% } else { %>
No domain configured — snapshot unavailable.
<% } %>

Overview

Repository
<%= p.repo_url %>
Branch
loading branches…
Auto-deploy
<%= p.auto_deploy ? 'on — pushes to ' + p.branch + ' deploy' : 'off — manual deploys only' %>
Domains
<% const domains = String(info.DOMAINS || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean); %> <% if (domains.length) { %> <% domains.forEach(function (d, i) { %><%= i ? ', ' : '' %><%= d %><% }) %> <% } else { %>—<% } %>
Port
<%= info.PORT || '—' %>
Cache
<% if (isLaravel) { %> off — Varnish is not available for Laravel apps (the edge strips cookies; sessions/CSRF would break) <% } else { %>
<%= (info.CACHE || 'off') === 'on' ? 'on (Varnish)' : 'off (direct)' %>
<% } %>
Noindex
<%= (info.NOINDEX || 'off') === 'on' ? 'on (blocked)' : 'off (indexable)' %>
<% if (isLaravel) { %>
Runtime
PHP-FPM pool paas-<%= p.name %> · health <%= info.HEALTH_PATH || '/up' %>
<% } else { %>
Start command
<%= info.START_CMD || '—' %>
<% } %>
Build command
Output dir
<%= p.output_dir %>
Last deployed
<% if (lastLive && lastLive.finished_at) { %> <%= h.relTime(lastLive.finished_at) %> <% } else { %>never<% } %>
Node.js
Multi-label
<%= p.multi_label ? 'on — label helpers active' : 'off' %>
Group
Created
<%= h.fmtTime(p.created_at) %>

Access

<% const isEnabled = String(info.ENABLED || 'on') !== 'off'; %> <% const baUser = String(info.BASIC_AUTH_USER || '').trim(); %>
<%= isEnabled ? 'active' : 'deactivated (503)' %>
onsubmit="return confirm('Deactivate this project? All domains answer 503 until re-enabled.')"<% } %>>
<%= baUser ? 'protected (user: ' + baUser + ')' : 'public' %> <% if (baUser) { %>
<% } %>
browser login in front of ALL domains — share credentials to give private access
<% if ((info.CACHE || 'off') === 'on') { %>

Cache

HIT rate today: <% const tc = trafficStats.today.hit + trafficStats.today.miss; %> <%= tc ? Math.round(100 * trafficStats.today.hit / tc) + '%' : '—' %> · 30 days: <%= trafficStats.hitRate30 !== null ? trafficStats.hitRate30 + '%' : '—' %>
<% } %>
>

Actions

Runtime logs
<% if (isLaravel) { %>

Laravel

Migrate on deploy
<%= (info.MIGRATE || 'on') === 'on' ? 'on — migrate --force runs after the health-gate; a failing migration fails the deploy (schema changes are not rolled back)' : 'off — run migrations yourself' %>
Scheduler
<%= (info.SCHEDULER || 'off') === 'on' ? 'on — schedule:run every minute (log: storage/logs/scheduler.log)' : 'off' %>
Queue worker
<%= (info.QUEUE_WORKER || 'off') === 'on' ? 'on — PM2 process ' + p.name + '-queue (' + (queueState || 'absent') + '); deploys send queue:restart' : 'off' %>
<%= info.QUEUE_CMD || 'php artisan queue:work --sleep=3 --tries=3 --max-time=3600' %>
FPM max children
concurrent PHP workers for this app (ondemand pool, ~40–80 MB each)
Releases: the whole built checkout; storage/ and .env are shared across releases; config/route/view/event:cache are built per release, then the release is health-gated through the real PHP-FPM pool before current flips. No PHP-FPM reload per deploy (opcache is keyed per release path).
<% } %> <% if (capabilities && capabilities.db) { %>

Database — MariaDB on this server, loopback only

<% if (dbInfo) { %>
Database
<%= dbInfo.database %> <% if (!dbInfo.managed) { %>(external — not provisioned here)<% } %>
Host
<%= dbInfo.host %>:<%= dbInfo.port %>
User
<%= dbInfo.username %>
Password
••••••••••••
URL
mysql://<%= dbInfo.username %>:••••@<%= dbInfo.host %>:<%= dbInfo.port %>/<%= dbInfo.database %>
From your workstation: ssh -L 3306:127.0.0.1:3306 deploy@<this server>, then connect any client to localhost:3306 with these credentials. Nightly dumps in /srv/paas/backups/db (last 7 kept).
<% if (dbInfo.managed) { %>
<% } %>
<% } else { %>

No database yet. Creates <%= p.name.replace(/-/g, '_') %> with a dedicated user and writes DB_CONNECTION/DB_HOST/DB_PORT/DB_DATABASE/DB_USERNAME/DB_PASSWORD<%= isLaravel ? '' : ' and DATABASE_URL' %> into the environment.

<% } %>
<% } %>

Domains

<% const sysDomain = String(info.SYSTEM_DOMAIN || '').trim(); %> <% const customDomains = String(info.DOMAINS || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean); %> <% const redirDomains = String(info.REDIRECT_DOMAINS || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean); %> <% const allServing = customDomains.concat(sysDomain ? [sysDomain] : []); %> <% const declaredMain = String(info.MAIN_DOMAIN || '').trim(); %> <% const mainDomain = allServing.indexOf(declaredMain) >= 0 ? declaredMain : allServing[0]; %> <% allServing.forEach(function (d) { %> <% const isSys = d === sysDomain; %> <% }) %> <% redirDomains.forEach(function (d) { %> <% }) %>
DomainTypeMain
<%= d %> <%= isSys ? 'system · noindex' : 'domain' %>
onchange="this.form.submit()" title="make <%= d %> the main domain">
<% if (isSys) { %> always available, cannot be removed <% } else { %>
<% } %>
<%= d %> 308 → <%= primaryDomain %>
re-attempts certificate issuance for domains whose DNS was fixed after creation
Point DNS at 188.40.238.163 before adding — certificates are issued automatically.
<% if (customDomains.length) { %>

Domain rules

Restrict a specific domain to only serve certain paths (everything else 404s on that host) and/or keep it out of search results — useful for a secondary marketing/campaign domain that should only expose a handful of landing pages instead of the whole site.
enforced in Caddy before the cache, same as geo-blocking · one rule per domain, any number of paths
<% } %>

Geo-blocking

<%= (info.GEO_EXEMPT_GOOGLE || 'on') !== 'off' ? "Exempt Google's AdsBot/Googlebot IP ranges from these rules" : "Google's AdsBot/Googlebot are subject to these rules like any other visitor" %>
Select countries…
rules apply in front of the cache; internal checks and warming are never blocked

Traffic — last 30 days

<% if (traffic.some(function (t) { return t.requests > 0; })) { %>
<%= traffic[0].day %><%= traffic[traffic.length - 1].day %>
served from cache (Varnish)served by server (app/static)
<%= h.fmtBytes(trafficStats.today.bytes) %> · <%= h.fmtInt(trafficStats.today.requests) %> req
today
<%= h.fmtBytes(trafficStats.yesterday.bytes) %> · <%= h.fmtInt(trafficStats.yesterday.requests) %> req
yesterday
<%= h.fmtBytes(trafficStats.bytes7) %> · <%= h.fmtInt(trafficStats.req7) %> req
7 days
<%= h.fmtBytes(trafficStats.bytes30) %> · <%= h.fmtInt(trafficStats.req30) %> req
30 days
<% if (trafficStats.hitRate30 !== null) { %>
<%= trafficStats.hitRate30 %>%
cache hit (30 d)
<% } %> <% if (trafficStats.cacheShare30 !== null) { %>
<%= h.fmtBytes(trafficStats.cacheBytes30) %> · <%= trafficStats.cacheShare30 %>%
from cache (30 d)
<% } %>

Monthly totals

<% months.forEach(function (m) { %> <% const mc = m.hit + m.miss; const msplit = (m.bytes_cache || 0) + (m.bytes_origin || 0); %>
<% if (msplit) { %>
<% } %>
<%= m.month.slice(2) %><%= m.final ? '' : ' *' %>
<%= h.fmtBytes(m.bytes) %>
<%= h.fmtInt(m.requests) %> req
<% }) %>
* running month — archived automatically once the month completes<%= monthsAll.length > months.length ? ' · chart shows the last 24 months' : '' %>
<% if (monthsAll.length > 1) { %>
all months <% monthsAll.slice().reverse().forEach(function (m) { %> <% const ms = (m.bytes_cache || 0) + (m.bytes_origin || 0); %> <% }) %>
MonthRequestsBandwidthCacheServerHITMISS5xx
<%= m.month %><%= h.fmtInt(m.requests) %><%= h.fmtBytes(m.bytes) %><%= ms ? h.fmtBytes(m.bytes_cache) : '—' %><%= ms ? h.fmtBytes(m.bytes_origin) : '—' %><%= h.fmtInt(m.hit) %><%= h.fmtInt(m.miss) %><%= h.fmtInt(m.s5xx) %><%= m.final ? 'archived' : 'running' %>
<% } %>
daily table <% traffic.slice().reverse().forEach(function (t) { %><% if (t.requests) { %> <% const ts = (t.bytes_cache || 0) + (t.bytes_origin || 0); %> <% } %><% }) %>
DayRequestsBandwidthCacheServerHITMISS2xx4xx5xx
<%= t.day %><%= h.fmtInt(t.requests) %><%= h.fmtBytes(t.bytes) %><%= ts ? h.fmtBytes(t.bytes_cache) : '—' %><%= ts ? h.fmtBytes(t.bytes_origin) : '—' %><%= h.fmtInt(t.hit) %><%= h.fmtInt(t.miss) %><%= h.fmtInt(t.s2xx) %><%= h.fmtInt(t.s4xx) %><%= h.fmtInt(t.s5xx) %>
<% } else { %>
No traffic data yet — collection runs every 5 minutes; first numbers appear shortly after the next visits.
<% } %>

Repository

<% if (p.git_account_id && p.repo_full) { %>
<%= gitAccount ? gitAccount.provider + ' · ' + gitAccount.label : 'account removed' %> <%= p.repo_full %> <% if (gitAccount) { %>
<% } %>
Re-checks (and re-adds if missing) the read-only deploy key and the push webhook on the repository.
<% } else if (p.repo_url) { %>
<%= p.repo_url %>
Manual repository — add the webhook and deploy key below to the repository yourself.
<% } else { %>
No repository connected yet — this project currently deploys from ZIP uploads only.
<% } %>
Connect / change repository
Connect accounts under Git accounts to browse repositories. With an account selected, the deploy key and push webhook are set up automatically.
Only used when no account is selected above.

Webhook

<%= webhookUrl %>

Deploy key

Add this public key to the repository (read-only deploy key) if it is private.
<% if (deployKey) { %>
<%= deployKey %>
<% } else { %>
No deploy key found at the configured path.
<% } %>

Environment variables

<% if (p.multi_label) { %>
Label preset — fills NUXT_SITE=<%= p.name %>, a fresh purge secret and this app's domain;
<% } %>
<% if (isLaravel) { %>
Written to <%= envPath %> (the release's .env symlinks to it). Laravel reads it through its config cache — after saving, use "Restart app" (rebuilds the cache) or deploy. env() outside config/ returns null under a cached config, as usual.
<% } else { %>
Written to <%= envPath %>. Takes effect on the next deploy — or use "Restart app". NUXT_SITE is baked at BUILD time — a label change always needs a deploy.
<% } %>

Deployments

<% if (!history.length) { %>
No deployments yet.
<% } else { %> <% for (const d of history) { %> <% } %>
#StatusSourceCommitStartedDuration
#<%= d.id %> <%= h.depLabel(d.status) %> <% if (d.step && d.status === 'failed') { %>
<%= d.step %>
<% } %>
<%= d.source %> <%= h.shortSha(d.commit_sha) %> <% if (d.commit_msg) { %>
<%= d.commit_msg %>
<% } %>
<%= h.fmtTime(d.started_at) %> <%= h.duration(d.started_at, d.finished_at) %> log
<% if (historyHasMore) { %>
<% } %> <% } %>