commit 7409ce6d274b39af436099e96d00c3172e649590
parent 85ae0487045645646fb547fb19e307320b162543
Author: Damian Myrda <damian@prime8.dev>
Date: Sun, 8 Feb 2026 14:11:03 -0600
feat: interactive cloud-config generator, fix sitemap
Diffstat:
7 files changed, 176 insertions(+), 86 deletions(-)
diff --git a/astro.config.mjs b/astro.config.mjs
@@ -1,16 +0,0 @@
-import { defineConfig } from "astro/config";
-import bun from "astro-bun-adapter";
-
-export default defineConfig({
- output: "server",
- site: "https://prime8.dev",
- adapter: bun(),
- server: {
- host: true,
- },
- image: {
- service: {
- entrypoint: "astro/assets/services/noop",
- },
- },
-});
diff --git a/astro.config.ts b/astro.config.ts
@@ -0,0 +1,18 @@
+import { defineConfig } from "astro/config";
+import bun from "astro-bun-adapter";
+import { SITE_URL } from "./src/constants/website";
+
+export default defineConfig({
+ output: "server",
+ site: SITE_URL,
+ trailingSlash: "never",
+ adapter: bun(),
+ server: {
+ host: true,
+ },
+ image: {
+ service: {
+ entrypoint: "astro/assets/services/noop",
+ },
+ },
+});
diff --git a/cloud_config.yml b/cloud_config.yml
@@ -1,67 +0,0 @@
-users:
- - name: damian
- groups: users, admin
- sudo: ALL=(ALL) NOPASSWD:ALL
- shell: /bin/bash
- ssh_authorized_keys:
- - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbhuxFr7zO5fcvLMP8dt1SQAQ1uEw0rJCeFI7o5JFULA4w1dB9yc9FotnVwxRroXpBHxmH7jTFsuCXjHj5CQFDnDb0Vq6iVrtj4WEWBg4N+juA347pmKPLVnyEofpjIHHFSj4b4U/ozk/xEfekNrAxrjhMYcREXQsMI168MNupCEqrqWAyDygokKTicwEX0YNCX2ig5Obs9dUj/nbaWL9/kWgOejuAzQd9guncC0r6Oc8yce+FHjqFpd6tApCLF1IN0KNBfj2k24WEU9JuovwwZ+mbFvKTeZF0O9aXlvuVlrKIS6yfn6Srh22GQJMEhcDMypO8t3AnsKli6vM6J7iUWJuksLf9fOty2ZfJghMOlUHYVcAaXPn2ESReNjSJfHtNOsvIlXsXMznFnTK2WL0115aF0th9Ivxn+t/9onOj6iQALgIYiRSM9tg7zKu1+vglZmU1CKsdzXGGP5P/UVeQFkxjUsYEjEebInfbIl6I246HpLLQIwkqGm/21Ge5hLAEiKYtasoFyRqcc1pWhwj96TMw096pWGrZg89CO8P0U9INhWfHbogT4c07reZpZuSH745thufYQ0CtgJQOlCTQdyilHyZL3d6yDoITNycqMIklnNPRDB9Po5tdD6qzDg7p//OurYx3d5FkhMby6H8/B/79E0+ASh3so5TRP6hiOw==
-
-package_update: true
-package_upgrade: true
-
-packages:
- - fail2ban
- - ufw
- - curl
- - ca-certificates
- - systemd-timesyncd
-
-ssh_pwauth: false
-write_files:
- - path: /etc/ssh/sshd_config.d/ssh-hardening.conf
- content: |
- Port 2222
- PermitRootLogin no
- PasswordAuthentication no
- KbdInteractiveAuthentication no
- ChallengeResponseAuthentication no
- MaxAuthTries 3
- AllowTcpForwarding no
- X11Forwarding no
- AllowAgentForwarding no
- AuthorizedKeysFile .ssh/authorized_keys
- AllowUsers damian
-
-runcmd:
- # Time sync
- - systemctl enable systemd-timesyncd
- - systemctl start systemd-timesyncd || true
-
- # Fail2ban
- - printf "[sshd]\nenabled = true\nport = 2222\nbanaction = iptables-multiport\nmaxretry = 3\nbantime = 3600\nfindtime = 600\n" > /etc/fail2ban/jail.local
- - systemctl enable fail2ban
- - systemctl restart fail2ban || true
-
- # Firewall
- - ufw allow 2222/tcp # SSH (Admin)
- - ufw allow 22/tcp # SSH (GitLab)
- - ufw allow 80/tcp # HTTP
- - ufw allow 443/tcp # HTTPS
- - ufw allow 3000/tcp # Dokploy UI
- - ufw allow 25/tcp # SMTP
- - ufw allow 465/tcp # SMTPS
- - ufw allow 587/tcp # Submission
- - ufw allow 993/tcp # IMAPS
- - ufw --force enable
-
- # Reload SSH to apply hardening
- - systemctl restart sshd || systemctl restart ssh || true
-
- # Dokploy
- - curl -sSL https://dokploy.com/install.sh | sh
-
- # Add damian to docker group
- - usermod -aG docker damian || true
-
- # Finish
- - reboot
diff --git a/generate_cloud_config.sh b/generate_cloud_config.sh
@@ -0,0 +1,153 @@
+#!/bin/bash
+set -e
+
+read -p "Enter your name: " USERNAME
+read -p "Enter your SSH public key: " SSH_KEY
+echo
+read -p "Enter your hostname: " HOSTNAME
+read -p "Enter your domain: " DOMAIN
+echo
+read -p "Enter your email address: " EMAIL_ADDRESS
+read -s -p "Enter your email password: " EMAIL_PASSWORD
+echo
+
+cat <<EOF
+#cloud-config
+
+users:
+ - name: $USERNAME
+ groups: users, admin, docker
+ sudo: ALL=(ALL) NOPASSWD:ALL
+ shell: /bin/bash
+ ssh_authorized_keys:
+ - $SSH_KEY
+
+package_update: true
+package_upgrade: true
+packages:
+ - fail2ban
+ - ufw
+ - curl
+ - ca-certificates
+ - systemd-timesyncd
+ - unattended-upgrades
+ - apt-listchanges
+ - needrestart
+ - msmtp
+ - bsd-mailx
+
+ssh_pwauth: false
+
+write_files:
+ - path: /etc/ssh/sshd_config.d/ssh-hardening.conf
+ content: |
+ Port 2222
+ PermitRootLogin no
+ PasswordAuthentication no
+ KbdInteractiveAuthentication no
+ ChallengeResponseAuthentication no
+ MaxAuthTries 3
+ AllowTcpForwarding no
+ X11Forwarding no
+ AllowAgentForwarding no
+ AuthorizedKeysFile .ssh/authorized_keys
+ AllowGroups users
+
+ - path: /etc/apt/apt.conf.d/50unattended-upgrades
+ content: |
+ Unattended-Upgrade::Allowed-Origins {
+ "\${distro_id}:\${distro_codename}-security";
+ };
+
+ Unattended-Upgrade::Package-Blacklist {};
+
+ Unattended-Upgrade::Mail "$EMAIL_ADDRESS";
+ Unattended-Upgrade::Sender "server-updates <$EMAIL_ADDRESS>";
+ Unattended-Upgrade::MailReport "on-change";
+ Unattended-Upgrade::MailOnlyOnError "true";
+
+ Unattended-Upgrade::Automatic-Reboot "true";
+ Unattended-Upgrade::Automatic-RebootTime "00:00";
+ Unattended-Upgrade::Automatic-RebootWithUsers "false";
+
+ - path: /etc/apt/apt.conf.d/20auto-upgrades
+ content: |
+ APT::Periodic::Update-Package-Lists "1";
+ APT::Periodic::Unattended-Upgrade "1";
+ APT::Periodic::AutocleanInterval "7";
+
+ # WARNING: Email password stored in plaintext here (root-only, 0600). Use secrets manager in production.
+ - path: /root/.msmtprc
+ permissions: "0600"
+ owner: root:root
+ content: |
+ account default
+ host smtp.fastmail.com
+ port 465
+ from $EMAIL_ADDRESS
+ user $EMAIL_ADDRESS
+ password $EMAIL_PASSWORD
+ auth on
+ tls on
+ tls_starttls off
+ tls_certcheck on
+ logfile /var/log/msmtp/msmtp.log
+
+ - path: /etc/logrotate.d/msmtp
+ content: |
+ /var/log/msmtp/msmtp.log {
+ daily
+ rotate 7
+ compress
+ delaycompress
+ missingok
+ notifempty
+ create 0600 root root
+ }
+
+ - path: /etc/mailname
+ content: $DOMAIN
+
+ - path: /etc/hostname
+ content: $HOSTNAME
+
+runcmd:
+ - hostnamectl set-hostname $HOSTNAME || true
+
+ - timedatectl set-timezone America/Los_Angeles || true
+ - systemctl enable --now systemd-timesyncd
+
+ - |
+ printf "[sshd]\nenabled = true\nport = 2222\nbanaction = iptables-multiport\nmaxretry = 3\nbantime = 3600\nfindtime = 600\n" > /etc/fail2ban/jail.local
+ - systemctl enable --now fail2ban
+
+ - ufw default deny incoming
+ - ufw default allow outgoing
+ - ufw allow 2222/tcp comment "SSH hardened port"
+ - ufw allow 22/tcp comment "SSH GitLab"
+ - ufw allow 80/tcp comment "HTTP - Traefik"
+ - ufw allow 443/tcp comment "HTTPS - Traefik"
+ - ufw allow 3000/tcp comment "Dokploy UI - temporary, close after setup"
+ - ufw --force enable
+
+ - systemctl restart sshd || systemctl restart ssh || true
+
+ - ln -sf /root/.msmtprc /etc/msmtprc || true
+ - grep -q "mta=/usr/bin/msmtp" /etc/mail.rc || echo "set mta=/usr/bin/msmtp" >> /etc/mail.rc
+ - echo "Automatic security updates enabled. Emails sent to $EMAIL_ADDRESS on changes. Reboots at 00:00 PT if needed." > /etc/motd.d/99-security-updates
+ - echo "Server first boot for $HOSTNAME" | mail -s "Server Setup Test" $EMAIL_ADDRESS || true
+
+ - |
+ fallocate -l 4G /swapfile || true
+ chmod 600 /swapfile || true
+ mkswap /swapfile || true
+ swapon /swapfile || true
+ echo "/swapfile none swap sw 0 0" >> /etc/fstab || true
+
+ - curl -fsSL https://get.docker.com | sh
+ - usermod -aG docker $USERNAME || true
+
+ - curl -sSL https://dokploy.com/install.sh | sh
+
+ - reboot
+EOF
diff --git a/src/constants/website.ts b/src/constants/website.ts
@@ -1,3 +1,3 @@
-export const SITE_DOMAIN = "prime8.dev";
+export const SITE_DOMAIN = "www.prime8.dev";
export const SITE_URL = `https://${SITE_DOMAIN}`;
diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro
@@ -4,6 +4,7 @@ import Article from "../../layouts/components/Article.astro";
import { blogs } from "../../blogs";
import schemas from "../../schemas/index";
+import { SITE_URL } from "../../constants/website";
const blog = blogs.find((blog) => blog.id === Astro.params.slug);
if (!blog) {
@@ -22,7 +23,7 @@ const { getSchemaForBlog, getBreadcrumbSchema } = schemas.blog;
title={`${blog.title} | Damian Myrda`}
description={blog.description}
type="article"
- url={`https://prime8.dev/blog/${blog.id}`}
+ url={`${SITE_URL}/blog/${blog.id}`}
publishedTime={blog.date}
modifiedTime={blog.modifiedDate || blog.date}
keywords={keywords}
diff --git a/src/pages/sitemap.xml.ts b/src/pages/sitemap.xml.ts
@@ -2,6 +2,7 @@ import type { APIRoute } from "astro";
import { fetchGitMetadataForProject } from "../external/git";
import { experience, projects } from "../config";
import { blogs } from "../blogs";
+import { SITE_URL } from "../constants/website";
export const GET: APIRoute = async () => {
const now = new Date().toISOString().split("T")[0];
@@ -58,7 +59,7 @@ export const GET: APIRoute = async () => {
${allPages
.map(
(page) => ` <url>
- <loc>${URL}${page.url}</loc>
+ <loc>${SITE_URL}${page.url}</loc>
<lastmod>${page.lastmod || now}</lastmod>
<changefreq>${page.changefreq}</changefreq>
<priority>${page.priority}</priority>