Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ RUN apt-get update \
COPY . /opt/server-setup

RUN chmod +x \
/opt/server-setup/scripts/*.sh \
/opt/server-setup/tests/*.sh \
/opt/server-setup/benchmarks/*.sh \
&& mkdir -p \
Expand Down Expand Up @@ -100,6 +99,6 @@ EXPOSE 22 80 443 4000 4001 4002 4003

STOPSIGNAL SIGRTMIN+3

ENTRYPOINT ["/opt/server-setup/scripts/sandbox-entrypoint.sh"]
ENTRYPOINT ["/usr/bin/env", "python3", "/opt/server-setup/scripts/sandbox_entrypoint.py"]

CMD ["/sbin/init"]
8 changes: 4 additions & 4 deletions INSTALLING-AND-TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Run only the status webapp tests:
Run the self-check wrapper:

```bash
./scripts/run-self-checks.sh
python3 ./scripts/run_self_checks.py
```

## Docker sandbox
Expand Down Expand Up @@ -69,9 +69,9 @@ cd /opt/server-setup
Useful sandbox commands:

```bash
./scripts/prepare-server.sh --email admin@example.com --skip-docker
./scripts/deploy-repo.sh --repo-url /srv/apps/simple-site --dest /srv/apps/simple-site --email admin@example.com --skip-github-hook
./scripts/manage-services.sh
python3 ./scripts/prepare_server.py --email admin@example.com --skip-docker
python3 ./scripts/deploy_repo.py --repo-url /srv/apps/simple-site --dest /srv/apps/simple-site --email admin@example.com --skip-github-hook
python3 ./scripts/manage_services.py
```

## Examples
Expand Down
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ The committed [`deploy/registry.example.json`](deploy/registry.example.json) fil
## Prepare the server

```bash
sudo ./scripts/prepare-server.sh \
sudo python3 ./scripts/prepare_server.py \
--email ops@example.com \
--skip-docker \
--with-status-webapp
```

What it does:
- installs baseline packages and developer tools
- optionally applies SSH/UFW/fail2ban hardening
- optionally applies unattended-upgrades/UFW/fail2ban hardening
- installs the webhook receiver service
- stores `DEFAULT_TLS_EMAIL` in `/etc/default/site-automation`
- optionally installs the status webapp

`prepare_server.py` leaves SSH untouched by default. If you explicitly want it to manage `sshd`, add `--with-ssh-hardening`.

The Next.js status webapp is the supported dashboard for this repository.

If you want to use its admin controls:
Expand All @@ -41,14 +43,14 @@ If you want to use its admin controls:
## Deploy a repository

```bash
sudo ./scripts/deploy-repo.sh \
sudo python3 ./scripts/deploy_repo.py \
--repo-url git@github.com:your-org/your-app.git
```

Optional:

```bash
sudo ./scripts/deploy-repo.sh \
sudo python3 ./scripts/deploy_repo.py \
--repo-url git@github.com:your-org/your-app.git \
--dest /srv/apps/your-app \
--branch main \
Expand Down Expand Up @@ -129,25 +131,25 @@ Legacy top-level shorthand like `build`, `command`, `port`, `www_redirect`, and
Show managed services:

```bash
./scripts/manage-services.sh
python3 ./scripts/manage_services.py
```

Restart one app service:

```bash
sudo ./scripts/manage-services.sh restart --app your-app
sudo python3 ./scripts/manage_services.py restart --app your-app
```

Stop managed services:

```bash
sudo ./scripts/shutdown-server.sh
sudo python3 ./scripts/shutdown_server.py
```

Preview purge:

```bash
sudo ./scripts/shutdown-server.sh --purge --dry-run
sudo python3 ./scripts/shutdown_server.py --purge --dry-run
```

## Legacy Migration
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/discover-sites-benchmark.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ mkdir -p "$tmp/apps/server-setup-bench"
"domain": "bench.local",
"build_output": ".",
"deploy_hooks": {
"build": "./scripts/run-self-checks.sh"
"build": "python3 ./scripts/run_self_checks.py"
},
"runtime": {
"mode": "static"
Expand Down
4 changes: 2 additions & 2 deletions examples/repositories/simple-site/public/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ <h1>What This Repo Is For</h1>
</p>
<ol>
<li>The seeding script turns this folder into a standalone git repo under <code>/srv/apps/simple-site</code>.</li>
<li><code>deploy-repo.sh</code> validates its <code>server.conf</code> and writes the generated registry entry.</li>
<li><code>deploy-repo.sh</code> publishes it through Nginx and configures webhook redeploys.</li>
<li><code>deploy_repo.py</code> validates its <code>server.conf</code> and writes the generated registry entry.</li>
<li><code>deploy_repo.py</code> publishes it through Nginx and configures webhook redeploys.</li>
</ol>
<p><a href="/">Back to the home page</a></p>
</main>
Expand Down
18 changes: 16 additions & 2 deletions monitor/webapp/app/api/actions/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { NextResponse } from "next/server";

import { requestHasAdminAccess } from "@/lib/auth";
import { runDashboardAction, type DashboardActionRequest } from "@/lib/control";
import {
readEditableConfig,
runDashboardAction,
type DashboardActionRequest,
} from "@/lib/control";

export const dynamic = "force-dynamic";
export const revalidate = 0;
Expand Down Expand Up @@ -38,6 +42,15 @@ function parseActionRequest(body: unknown): DashboardActionRequest {
throw new Error("This action requires a non-empty siteName.");
}
return { action: record.action, siteName: record.siteName.trim() };
case "add-site":
return {
action: "add-site",
repoUrl: typeof record.repoUrl === "string" ? record.repoUrl : "",
branch: typeof record.branch === "string" ? record.branch : "",
checkoutPath: typeof record.checkoutPath === "string" ? record.checkoutPath : "",
email: typeof record.email === "string" ? record.email : "",
skipGithubHook: record.skipGithubHook === true,
};
default:
throw new Error("Unsupported action.");
}
Expand All @@ -52,7 +65,8 @@ export async function POST(request: Request) {
const body = parseActionRequest(await request.json());

const response = await runDashboardAction(body);
return NextResponse.json(response, {
const config = await readEditableConfig();
return NextResponse.json({ ...response, config }, {
headers: {
"cache-control": "no-store",
},
Expand Down
17 changes: 17 additions & 0 deletions monitor/webapp/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ main {
.button-grid,
.token-form,
.token-field,
.toggle-field,
.action-result,
.site-actions,
.deploy-panel,
Expand Down Expand Up @@ -360,6 +361,22 @@ main {
font: inherit;
}

.toggle-field {
grid-auto-flow: column;
grid-auto-columns: max-content 1fr;
align-items: center;
}

.toggle-field input {
width: 18px;
height: 18px;
accent-color: #78e08f;
}

.toggle-field span {
color: var(--text);
}

.token-field input,
.config-editor {
width: 100%;
Expand Down
2 changes: 2 additions & 0 deletions monitor/webapp/components/dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ test("dashboard renders important issues and setup details", () => {

assert.match(markup, /What needs attention/);
assert.match(markup, /Config and recovery controls/);
assert.match(markup, /Add website/);
assert.match(markup, /Push to Main/);
assert.match(markup, /Retry deploy/);
assert.match(markup, /The repository must already include a valid root `server\.conf`\./);
assert.match(markup, /Automation: Apps watcher/);
assert.match(markup, /Bootstrap and operations signals/);
assert.match(markup, /api\.service \(failed\)/);
Expand Down
Loading
Loading