Files
gaussian-wellworks/Implementation Runbook.md
2026-04-30 14:53:51 -05:00

19 KiB
Raw Blame History

Runbook: Self-hosted Pilot

Gaussian Wellworks

1. Runbook Objective

This runbook provides a step-by-step procedure to deploy a secure, self-hosted pilot environment in DigitalOcean within five business days, including infrastructure provisioning, domain and DNS configuration, email platform integration, containerized Nextcloud deployment, and secure HTTPS access via reverse proxy. The objective is to deliver a fully functional, production-ready pilot system that supports internal collaboration and client file ingestion workflows, with validated end-to-end functionality (upload, access, delivery), clear administrative controls, and a scalable foundation for future expansion or migration.

2. Critical Dependencies

2.1 Business Domain Ownership

2.2 Administrative Access

2.3 Decision Checklist

3. Detailed Implementation Runbook

3.1 Create Digital Ocean Account

Objective

Provision a cloud account capable of hosting the pilot environment:

  • Account created and secured
  • Billing configured
  • Team/ownership clarified
  • Ready to provision Droplet (Task 3.3)

Architectural Context

This account will own:

  • Droplet (server)
  • Backups/snapshots
  • Networking (firewall, IP)
  • Future scaling resources

Step 1 - Register Account

Go to:

https://cloud.digitalocean.com/registrations/new

1.1 Enter account details

Email address (prefer client-owned)
Password (strong, unique)

1.2 Verify email

Check inbox
Click verification link

Step 2 - Secure the Account (Highly Recommended)

2.1 Enable Two-Factor Authentication (2FA)

Navigate to:

Settings → Security → Two-Factor Authentication

Enable using: Authenticator app (recommended)

2.2 Store recovery codes

✔ Save securely (password manager)

Step 3 - Add Billing Method

Navigate to:

Billing → Payment Methods

3.1 Add payment method

3.2 Confirm billing active

Step 4 - Create/Confirm Team Context

DigitalOcean uses teams/projects.

Navigate:

Projects → Default Project

4.1 Rename project (recommended) GaussianWellworks-Pilot

4.2 Assign resources later Droplets will be attached here.

Step 5 - Configure Default Settings

5.1 Enable backups (account-level awareness) While backups are enabled per droplet, confirm understanding:

✔ Backups cost ~20% of droplet price ✔ Enable during droplet creation

5.2 (Optional) Enable monitoring Settings → Monitoring → Enable

Not required for pilot, but useful later.

Validation Checklist

  • [✔] Account created
  • [✔] Email verified
  • [✔] 2FA enabled
  • [✔] Billing method added
  • [✔] Project created/renamed
  • [✔] Dashboard accessible
  • [✔] Able to initiate droplet creation

3.2 Create SSH Key Pair (Windows 11)

Objective

Create an SSH key pair on a Windows 11 workstation and upload the public key to DigitalOcean so it can be attached when provisioning the Ubuntu droplet.

DigitalOcean recommends SSH keys over passwords for Droplet access, and uploaded team keys can be selected during Droplet creation.

Generate key

</> Powershell

ssh-keygen -t ed25519 -C "admin@company.com"

Accept default path:

C:\Users\<user>\.ssh\id_ed25519

Copy public key

</> Powershell

Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard

Upload to DigitalOcean

  • Settings → Security → SSH Keys → Add
  • Name: admin-windows11

Validation Checklist

  • [✔] Key visible in DigitalOcean

3.3 Provision Droplet

Objective

Provision a production-ready virtual server (Droplet) in DigitalOcean that will host:

  • Nextcloud (Docker-based)
  • Reverse proxy (Nginx)
  • Supporting services

This step establishes the core infrastructure node for the entire pilot.

Create Dropet

  1. Login to DigitalOcean
  2. Click Create
  3. Select Droplets

Droplet Configuration

Image: Ubuntu 22.04 LTS
Plan: Premium Intel
Size: 2 vCPU / 8GB RAM
Region: closest to users
Auth: SSH key
Backups: Enabled
Hostname: gw-drive-01

Test SSH

ssh root@<IP>

Validation Checklist

  • [✔] SSH login works
  • [✔] IP recorded

3.4 Initial Server Configuration

Objective

Harden the freshly provisioned Ubuntu server and establish a secure administrative baseline before any application deployment.

At the end of this task, the system will:

  • Allow SSH access only via key-based authentication
  • Use a non-root administrative user
  • Be fully patched and up to date
  • Be ready for firewall and application installation

Create admin user

</> Bash

adduser adminuser
usermod -aG sudo adminuser

Copy SSH key

</> Bash

rsync --archive --chown=adminuser:adminuser ~/.ssh /home/adminuser

Disable root login

</> Bash

sudo tee /etc/ssh/sshd_config > /dev/null << 'EOF'
PermitRootLogin no
PasswordAuthentication no
EOF
</> Bash

sudo systemctl restart ssh

Test login

</> Powershell

ssh adminuser@<IP>

Update system

</> Bash

sudo apt update
sudo apt upgrade -y
sudo apt autoremove -y

Validation [✔] adminuser login works [✔] root login blocked [✔] system updated

3.5 Configure Firewall

Objective

Establish a baseline network security posture so that:

  • Only required ports are exposed
  • All other inbound traffic is blocked
  • SSH access remains available
  • The system is prepared for web access (Nextcloud + HTTPS)

DigitalOcean Firewall

Allow:

22 (SSH) → your IP
80 (HTTP) → all
443 (HTTPS) → all

Attach to droplet.

UFW

</> Bash

sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Validation

</> Bash 

sudo ufw status

3.6 Configure DNS

Objective

Create a public DNS record so that:

drive.company.com → your Droplet public IP

This enables:

  • Browser access to Nextcloud (Day 3)
  • SSL certificate issuance (Lets Encrypt)
  • A stable, user-friendly endpoint

Create A record

Host: drive
Value: <DROPLET_IP>
TTL: 300

Validate

</> Powershell

nslookup drive.company.com

Note ⚠ DNS propagation required before SSL

3.7 Install Docker

Objective

Prepare the server to run containerized services by installing:

  • Docker Engine (container runtime)
  • Docker Compose (multi-container orchestration)

Required Dependencies

</> Bash
sudo apt install ca-certificates curl gnupg -y
sudo mkdir -p /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
</> Bash
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker

</> Bash
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y

Enable Docker

</> Bash
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker adminuser

Reconnect SSH.

Test

</> Bash

docker run hello-world

3.10 Deploy Nextcloud

Objective

Deploy a production-capable Nextcloud stack using Docker Compose, including:

  • Nextcloud application container
  • MariaDB database container
  • Redis (for performance + file locking)
  • Persistent storage volumes

Create directory

</> Bash

mkdir -p ~/apps/nextcloud
cd ~/apps/nextcloud

Create .env

</> Bash
sudo tee .env > /dev/null << 'EOF'
MYSQL_ROOT_PASSWORD=StrongRootPassword
MYSQL_PASSWORD=StrongDBPassword
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud

NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=StrongAdminPassword

MYSQL_HOST=db
REDIS_HOST=redis
NEXTCLOUD_TRUSTED_DOMAINS=<IP>
EOF

Create docker-compose

</> Bash
sudo tee docker-compose.yml > /dev/null << 'EOF'
version: '3.9'

services:
  db:
    image: mariadb:10.6
    restart: always
    env_file:
      - .env
    volumes:
      - db_data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    restart: always

  app:
    image: nextcloud:apache
    restart: always
    ports:
      - "8080:80"
    env_file:
      - .env
    depends_on:
      - db
      - redis
    volumes:
      - nextcloud_data:/var/www/html

volumes:
  db_data:
  nextcloud_data:
EOF

Start

</> Bash

docker compose up -d

Validate

http://<IP>:8080

3.11 Validate Internal Access

Objective

Confirm that the deployed Nextcloud instance is:

  • Reachable over the network (via Droplet IP)
  • Functionally operational (login, file operations)
  • Persisting data correctly
  • Stable prior to exposing externally

This is a hard validation gate—do not proceed until this passes.

Test:

  • Login
  • Upload file
  • Create folder
  • Restart containers
  • Data persists

3.12 Install Nginx

Objective

Install and validate Nginx as the web server that will act as a reverse proxy in front of Nextcloud.

At the end of this step:

  • Nginx is installed and running
  • Port 80 (HTTP) is actively serving traffic
  • Server is ready for reverse proxy configuration (Task 3.13)
</> Bash
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx

Test:

http://<IP> → nginx welcome page

3.13 Configure HTTP Reverse Proxy (Staging Only)

Objective

Bind your domain to the application by configuring Nginx to proxy:

drive.company.com → Nginx (port 80) → Nextcloud (port 8080)

At the end of this step:

  • Nginx reverse proxy configuration staged
  • HTTP server block created for drive.company.com
  • Nginx config syntax validates
  • Nginx reloads successfully
  • ⚠ Browser access may redirect to HTTPS and show 404 until SSL/HTTPS configuration is completed
</> Bash

sudo tee /etc/nginx/sites-available/nextcloud > /dev/null << 'EOF'
server {
    listen 80;
    server_name drive.company.com;

    location / {
        proxy_pass http://127.0.0.1:8080;

        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 http;
    }
}
EOF

Enable:

</> Bash

sudo ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Important

  • ⚠ This step is NOT fully usable yet
  • ⚠ HTTPS may redirect and show 404 (expected)

3.14 Install SSL (Certbot)

Objective

Obtain and install a valid SSL certificate so that:

https://drive.company.com

is:

  • Trusted (no browser warnings)
  • Encrypted (HTTPS)
  • Routed through Nginx to Nextcloud
</> Bash

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d drive.company.com

Validate

  • ✔ Certificate issued
  • ✔ HTTPS reachable
  • ⚠ May still show 404 (expected)

3.15 Finalize HTTPS Reverse Proxy

Objective

Complete the system by:

  • Wiring HTTPS (port 443) to Nextcloud
  • Enforcing HTTP → HTTPS redirect
  • Applying required Nextcloud proxy settings
  • Performing end-to-end validation

At completion:

Replace config

</> Bash

sudo tee /etc/nginx/sites-available/nextcloud > /dev/null << 'EOF'
server {
    listen 80;
    server_name drive.company.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name drive.company.com;

    ssl_certificate /etc/letsencrypt/live/drive.company.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/drive.company.com/privkey.pem;

    client_max_body_size 10G;

    location / {
        proxy_pass http://127.0.0.1:8080;

        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 https;
    }
}
EOF

Reload

</> Bash

sudo nginx -t
sudo systemctl reload nginx

Fix Nextcloud

</> Bash

docker exec -u www-data nextcloud-app php occ config:system:set trusted_domains 1 --value="drive.company.com"
docker exec -u www-data nextcloud-app php occ config:system:set overwrite.cli.url --value="https://drive.company.com"
docker exec -u www-data nextcloud-app php occ config:system:set overwriteprotocol --value="https"

Final Validation

https://drive.company.com

  • ✔ Login works
  • ✔ Upload works
  • ✔ Download works
  • ✔ No warnings
  • ✔ HTTPS padlock present

Cleanup

</> Bash

sudo ufw delete allow 8080/tcp

Final Outcome

  • ✔ Secure Nextcloud deployment
  • ✔ HTTPS reverse proxy functional
  • ✔ Docker-based architecture
  • ✔ Ready for users and workflows

3.16 Create Email Provider Account (Fastmail)

Objective

Establish a business-grade email platform using Fastmail so that:

  • domain-based email (user@company.com)
  • reliable outbound mail (for Nextcloud notifications later)
  • foundation for SPF/DKIM/DMARC

Architectural Context

Email is not hosted on your droplet. Your infrastructure will later integrate with it for:

  • Nextcloud notifications
  • User accounts
  • Client communication

Prerequisites

  • Domain ownership confirmed
  • Access to DNS registrar
  • Decision: Fastmail selected (per runbook)

Step 1 - Create Fastmail Account

Go to: https://www.fastmail.com

1.1 Sign up

  • Click Sign Up
  • Choose a plan (Standard is sufficient for pilot)
  • Enter:
    Name
    Email (temporary Fastmail domain)
    Password
    

1.2 Complete account creation

You will land in the Fastmail admin interface.

Step 2 - Add Your Domain

2.1 Navigate to Domains

In Fastmail:

Settings → Domains → Add Domain

2.2 Enter your domain

company.com

Click:

Add Domain

Step 3 - Verify Domain Ownership

Fastmail will present a TXT verification record.

3.1 Copy TXT record

Example:

Type: TXT
Name: @
Value: fm-domain-verification=abc123xyz

3.2 Add to DNS (Registrar)

In your DNS provider (e.g., GoDaddy or Cloudflare):

Add:

Type: TXT
Host: @
Value: fm-domain-verification=abc123xyz
TTL: 300

3.3 Wait for propagation

~515 minutes typical, but may be as much as 24 hours

3.4 Verify in Fastmail

Click:

Verify Domain

Expected Result

  • Domain verified successfully

Step 4 - Set Domain as Default

In Fastmail:

Settings → Domains → company.com → Set as default

This ensures:

Step 5 - Create Initial Admin Mailbox

5.1 Navigate to Users

Settings → Users → Add User

5.2 Create admin user

Example:

Username: admin
Email: admin@company.com
Password: (strong password)

5.3 Save

Expected Result

  • Mailbox created
  • Can send/receive (after DNS setup in 3.8)

Step 6 - Basic Access Test (Pre-DNS)

Login via:

https://app.fastmail.com

Expected

  • Inbox accessible
  • Account functional (even before MX setup)
  • Email is NOT functional yet

Validation Checklist

  • [✔] Fastmail account created
  • [✔] Domain added to Fastmail
  • [✔] TXT verification record created
  • [✔] Domain verified
  • [✔] Default domain set
  • [✔] Admin mailbox created
  • [✔] Able to login to Fastmail

3.17 Configure Email DNS

Objective

Make your domain fully capable of sending and receiving email by configuring DNS records required by Fastmail:

  • Incoming mail routing (MX)
  • Authorized senders (SPF)
  • Cryptographic signing (DKIM)
  • Policy & reporting (DMARC)

Changing MX records WILL impact live email.

If the client currently uses another provider:

  • Schedule a cutover window
  • Lower TTL beforehand (if possible)
  • Expect brief delivery delays during propagation

Prerequisites

  • Domain added & verified in Fastmail (Task 3.7)
  • Access to DNS registrar
  • Admin mailbox created

Step 1 - Gather Fastmail DNS Records

In Fastmail:

Settings → Domains → company.com → DNS Settings

Fastmail will provide all required records. Use those exact values if they differ from below.

Step 2 - Configure MX Records (Mail Routing)

2.1 Remove Existing MX Records

⚠️ Only do this at cutover time.

2.2 Add Fastmail MX Records

Type: MX
Host: @
Priority: 10
Value: in1-smtp.messagingengine.com

Type: MX
Host: @
Priority: 20
Value: in2-smtp.messagingengine.com

Step 3 - Configure SPF (Sender Authorization)

3.1 Add SPF record

Type: TXT
Host: @
Value: v=spf1 include:spf.messagingengine.com ~all
TTL: 300

Notes

  • Only ONE SPF record per domain
  • Merge with existing SPF if present

Step 4 - Configure DKIM (Email Signing)

4.1 Get DKIM from Fastmail

In Fastmail DNS settings, copy the DKIM record.

Example:

Type: CNAME
Host: fm1._domainkey
Value: fm1.company.com.dkim.fmhosted.com

Type: CNAME
Host: fm2._domainkey
Value: fm2.company.com.dkim.fmhosted.com

Type: CNAME
Host: fm3._domainkey
Value: fm3.company.com.dkim.fmhosted.com
4.2 Add all DKIM records

These enable:

  • Email authenticity verification
  • Better deliverability

Step 5 - Configure DMARC (Policy & Reporting)

5.1 Add DMARC record

Type: TXT
Host: _dmarc
Value: v=DMARC1; p=none; rua=mailto:admin@company.com
TTL: 300

Explanation

  • p=none → monitor only (safe for pilot)
  • rua= → aggregate reports sent to admin mailbox

Future Hardening Later you can move to:

  • p=quarantine → soft enforcement
  • p=reject → full enforcement

Step 6 - Verify DNS Propagation

6.1 Check MX nslookup -type=MX company.com

Expected:

in1-smtp.messagingengine.com in2-smtp.messagingengine.com 6.2 Check SPF nslookup -type=TXT company.com 6.3 Check DKIM nslookup -type=CNAME fm1._domainkey.company.com 6.4 Check DMARC nslookup -type=TXT _dmarc.company.com

Step 7 - Functional Email Test 7.1 Send inbound test

From Gmail/Outlook:

Send email to: admin@company.com

Expected:

  • Email received in Fastmail inbox

7.2 Send outbound test

From Fastmail:

Send email to external address

Expected:

  • Email delivered
  • Not marked as spam

Step 8 - Validate Deliverability (Recommended)

Use:

  • mail-tester.com
  • mxtoolbox.com

Expected

  • SPF pass
  • DKIM pass
  • DMARC pass
  • Low spam score

Step 9 - Propagation Expectations

  • MX: 530 minutes typical
  • SPF: immediate to 1 hour
  • DKIM: 1560 minutes
  • DMARC: 1560 minutes

Worst case: Up to 24 hours

Validation Checklist

  • [✔] MX records updated
  • [✔] SPF record present
  • [✔] DKIM records configured (all 3)
  • [✔] DMARC record created
  • [✔] DNS resolves correctly
  • [✔] Email received externally
  • [✔] Email sent externally
  • [✔] Deliverability validated