Fork from Hypha project, customise for Site.js provisioning

parent f66cd6eb
Pipeline #851 failed with stages
# Deployment 1
# Site.js Provisioning Spike
## cloud-init
Launches a server running Ubuntu 18.04LTS with Node latest LTS with the simply-insecure.js server on port 80 using multipass. Also sets up systemd service to run it automatically on subsequent restarts. Service/node runs as unprivileged account _indie_.
Creates a [cloud-init](https://cloud-init.io/) script to launch a server running Ubuntu 18.04LTS (local testing implemented via multipass) with Node latest LTS with Site.js running on port 433. Creates and unprivileged sudoer account _me_.
### Usage
......@@ -23,46 +21,6 @@ Launches a server running Ubuntu 18.04LTS with Node latest LTS with the simply-i
* List servers (and find out their IP address): `multipass ls`
* SSH into server: `ssh indie@<IP ADDRESS>`
* Within server, view cloud-init log: `cat /var/log/cloud-init-output.log`
* Within server, show PM2 processes: `pm2 ls`
* Within server, monitor PM2 processes: `pm2 monit`
* Within server (after restart), show systemd service: `systemctl | grep pm2`
See [blog post](https://ar.al/2019/01/05/hypha-spike-deployment-1/#cloud-init) for more details.
## Simply insecure
A simple, insecure web server. Used by the cloud-init spike.
## Simple TLS
### Usage
1. Create keys using [mkcert](https://github.com/FiloSottile/mkcert):
```bash
# If you haven’t used mkcert before, you must first create
# and install your local Certificate Authority (CA):
mkcert -install
# Generate your keys for localhost:
mkcert localhost
```
This will create the `localhost.pem` and `localhost-key.pem` files used by the Simple TLS spike.
(Note: for the certificate to be accepted without warning, you must restart your browser after running `mkcert -install`.)
1. Give Node.js permission to bind to ports < 1024 (i.e., 80 and 443) without being root:
```bash
sudo setcap 'cap_net_bind_service=+ep' $(which node)
```
3. Run the app:
```bash
node simple-tls.js
```
* Within server, use Site.js command-line app. e.g., `site logs`, `site status`, etc. See `site help` for the full list of commands.
4. Visit _https://localhost_
The work here dates back to my very spike for the Hypha project. See this [blog post](https://ar.al/2019/01/05/hypha-spike-deployment-1/#cloud-init) for more details.
#!/usr/bin/env node
////////////////////////////////////////////////////////////////////////////////
//
// Create cloud-init.yaml from cloud-init.template.yaml.
//
////////////////////////////////////////////////////////////////////////////////
const os = require('os')
const fs = require('fs')
const path = require('path')
const account = process.env.USERNAME
let sshKey
try {
sshKey = fs.readFileSync(path.join(os.homedir(), '.ssh', 'id_rsa.pub'), 'utf-8')
} catch (error) {
console.error('\nError: could not load SSH key (expected it in ~/.ssh/id_rsa.pub).\n\n', error)
process.exit(1)
}
console.log('\nCreating cloud-init.yaml with the following details:\n')
console.log(`Account: ${account}\n`)
console.log(`SSH key: ${sshKey}\n`)
// Read the template.
let template
try {
template = fs.readFileSync('./cloud-init.template.yaml', 'utf-8')
} catch (error) {
console.error('\nError: Could not read the template.\n\n', error)
process.exit(1)
}
// Carry out template substitution.
const cloudInitYaml = template.replace(/\{ACCOUNT\}/g, account).replace(/\{SSH_KEY\}/, sshKey)
// Save the cloud-init.yaml file.
try {
fs.writeFileSync('./cloud-init.yaml', cloudInitYaml)
} catch (error) {
console.error('\nError: Could not write cloud-init.yaml file.\n\n', error)
process.exit(1)
}
// Exit silently on success.
#cloud-config
################################################################################
#
# This script is for Ubuntu-like systems and relies on the apt package manager.
#
# Please do not use this file directly. It is meant to be used as a template to
# generate the final cloud-init.yaml file.
#
# Template variables:
#
# {ACCOUNT}: the account to create on the remote server.
#
################################################################################
# Set up non-root sudo account.
users:
- name: {ACCOUNT}
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh-authorized-keys: {SSH_KEY}
# apt update and upgrade
package_update: true
package_upgrade: true
# Install the following packages.
packages:
# Used to download the Site.js installation script.
- wget
# For setcap, in the runcmd section:
- libcap2-bin
#
# These commands will run only on the first boot.
# Note: they run as root by default. To run a command as the {ACCOUNT} account,
# ===== surround it with su -c "…" - {ACCOUNT}
#
runcmd:
# Environment variables
- export HOME=/home/{ACCOUNT}
# Install Site.js
- wget -qO- https://sitejs.org/install | bash
# Make the site folder
- mkdir ~/site
# Start the server, making sure sync is supported.
- site enable ~/site --sync
#cloud-config
################################################################################
# cloud-config
#
# This script is for Ubuntu-like systems and relies on the apt package manager.
#
# Please do not use this file directly. It is meant to be used as a template to
# generate the final cloud-init.yaml file.
#
# Template variables:
#
# aral: the account to create on the remote server.
#
################################################################################
# Set up non-root sudo account.
users:
- name: indie
- name: aral
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh-authorized-keys:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDgGMIFr4UWMpUHpe3e0bNqSqmagYf3SKKVRepGUeThY2g4o560lQpQPuzTM+1uGqkB9zsQzUF3QU54syW69Vw9IHPicACn/gNC1y7869wU/GLVRKTQ0gP8/jw4UEUg0OdXUfP57NrlJg5iCimu2xLhk4OyYiRv0OBNR0OCPm1OSwJv3Y2x/ykp/25AO+Vqy/ZJfmprWqb8e7K8Or2Nw+hVJOqk2UE8lz2qQnoN2V/Mn3guDhWVfeiSDkssJHSPF2QY8jKkGS1d0AHlqYIO4gfl1IBTXAwh530B03sSc9RQr8XTcPp+zSlAiXabDMe2nK3SHoC3NuVqoZQFfouCcNt2qdyZlkJZL24PCckfZYOc4CepgM1ksje8CCheiCtFTQ3zFThd1GEJypyPZ381dmeDxnT5ZvBBJqvxMKqwwuS0+UUDHlNofra79YzKXltfxylLneCCuJqzN7m327YJ1sbz3Xkgrk02A9uZlJBDHDtxKoIhx3PYmAGudASSAcbpXY6Bdn01VdyBmuefSluIEwkGsisN4X8mOSpcag9aUgKOxLvtvHnMZURxMj43c+i6kJ0MGlH0hNDQaw3GQWpw3Ndj9k3KSkspo23QkVlV6FhfAHdZoLLTx2iQEa/5ezSZSZhq1eISxV+tpimQyVj13iJkdFQ8CZdnxY2GJzKp7E77lw== aral+pop@ind.ie
ssh-authorized-keys: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDgGMIFr4UWMpUHpe3e0bNqSqmagYf3SKKVRepGUeThY2g4o560lQpQPuzTM+1uGqkB9zsQzUF3QU54syW69Vw9IHPicACn/gNC1y7869wU/GLVRKTQ0gP8/jw4UEUg0OdXUfP57NrlJg5iCimu2xLhk4OyYiRv0OBNR0OCPm1OSwJv3Y2x/ykp/25AO+Vqy/ZJfmprWqb8e7K8Or2Nw+hVJOqk2UE8lz2qQnoN2V/Mn3guDhWVfeiSDkssJHSPF2QY8jKkGS1d0AHlqYIO4gfl1IBTXAwh530B03sSc9RQr8XTcPp+zSlAiXabDMe2nK3SHoC3NuVqoZQFfouCcNt2qdyZlkJZL24PCckfZYOc4CepgM1ksje8CCheiCtFTQ3zFThd1GEJypyPZ381dmeDxnT5ZvBBJqvxMKqwwuS0+UUDHlNofra79YzKXltfxylLneCCuJqzN7m327YJ1sbz3Xkgrk02A9uZlJBDHDtxKoIhx3PYmAGudASSAcbpXY6Bdn01VdyBmuefSluIEwkGsisN4X8mOSpcag9aUgKOxLvtvHnMZURxMj43c+i6kJ0MGlH0hNDQaw3GQWpw3Ndj9k3KSkspo23QkVlV6FhfAHdZoLLTx2iQEa/5ezSZSZhq1eISxV+tpimQyVj13iJkdFQ8CZdnxY2GJzKp7E77lw== aral+pop@ind.ie
# apt update and upgrade
package_update: true
......@@ -15,42 +27,25 @@ package_upgrade: true
# Install the following packages.
packages:
- git
- curl
# Used to download the Site.js installation script.
- wget
# For setcap, in the runcmd section:
- libcap2-bin
#
# These commands will run only on the first boot.
# Note: they run as root by default.
# Note: they run as root by default. To run a command as the aral account,
# ===== surround it with su -c "…" - aral
#
runcmd:
# Environment variables
- export HOME=/home/indie
# Install Node.js from the NodeSource repositories.
- curl -sL https://deb.nodesource.com/setup_10.x | bash
- apt install -y nodejs
# Enable node to bind to ports < 1024 (which we will need with the
# script we are going to run)
- setcap 'cap_net_bind_service=+ep' $(which node)
# Setup npm to not use /usr/lib/node_modules so we can
# do an npm install -g from a regular unprivileged account.
# See: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally
- su -c "mkdir ~/.npm-global" - indie
- su -c "npm config set prefix '~/.npm-global'" - indie
- su -c "echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.profile" - indie
- su -c "source ~/.profile" - indie
# Clone this repository (how meta!)
- su -c "git clone https://source.ind.ie/hypha/spikes/deployment-1.git ~/server" - indie
# Install the PM2 Node Process manager, make it create a systemd service,
# and run the simple-tls.js script.
- su -c "npm install pm2 -g" - indie
- env PATH=$PATH:/usr/bin ~/.npm-global/bin/pm2 startup systemd -u indie --hp /home/indie
# The previous command was run as root and thus created some PM2 files as root. We must
# reset their permissions down to the indie account.
- chown -R indie:indie /home/indie
# Actually start the service (and have it added to the startup service by PM2).
- su -c "pm2 start ~/server/simply-insecure.js" - indie
- export HOME=/home/aral
# Install Site.js
- wget -qO- https://sitejs.org/install | bash
# Make the site folder
- mkdir ~/site
# Start the server, making sure sync is supported.
- site enable ~/site --sync
multipass launch --name hypha --cloud-init cloud-init.yaml
#!/bin/sh
account=$(whoami)
echo '\nCreating Site.js server instance for testing using multipass…\n'
echo " > Creating cloud-init.yaml using local account ${account}…"
node cloud-init.js $account
echo " > Creating and launching instance…"
multipass launch --name site --cloud-init cloud-init.yaml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to your site!</title>
<style>body { background-color: white; font-family: sans-serif; padding: 1em;} hr { border: none; border-top: 1px solid black; }</style>
</head>
<body>
<div id='main'>
<h1>Welcome to your personal web site 💖</h1>
<hr>
<h2>To edit this page:</h2>
<ol>
<li id='ssh'><script>const hostname = document.location.hostname; if (hostname === 'localhost') { document.getElementById('ssh').innerHTML=`<pre>ssh ${document.location.hostname}</pre>\n`; }</script></li>
<li><pre>$EDITOR ~/site</pre></li>
</ol>
<hr>
<p><small>This is a <a href='https://ar.al/2019/03/04/small-technology/'>Small Tech</a> personal web site served via <a href='https://source.ind.ie/hypha/tools/https-server'>HTTPS Server</a>. Made with love by <a href='https://ind.ie'>Ind.ie</a> in the Emerald Isle.</small></p>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>Welcome to your site!</title><style>body{background-color: white; font-family: sans-serif; padding: 1em;}hr{border: none; border-top: 1px solid black;}</style></head><body><div id='main'><h1>Welcome to your personal web site 💖</h1><hr><h2>To edit this page:</h2><ol><li id='ssh'><script>const hostname=document.location.hostname; if (hostname==='localhost'){document.getElementById('ssh').innerHTML=`<pre>ssh ${document.location.hostname}</pre>\n`;}</script></li><li><pre>$EDITOR ~/site</pre></li></ol><hr><p><small>This is a <a href='https://ar.al/2019/03/04/small-technology/'>Small Tech</a> personal web site served via <a href='https://source.ind.ie/hypha/tools/https-server'>HTTPS Server</a>. Made with love by <a href='https://ind.ie'>Ind.ie</a> in the Emerald Isle.</small></p></div></body></html>
\ No newline at end of file
const fs= require('fs')
const https = require('https')
const options = {
key: fs.readFileSync('localhost-key.pem'),
cert: fs.readFileSync('localhost.pem')
}
https.createServer(options, (req, res) => {
res.end('Hypha v0.0 (secure)')
}).listen(443, () => {
console.log('Listening on port 443.')
})
const fs= require('fs')
const http = require('http')
http.createServer((req, res) => {
res.end('Hypha v0.0 (insecure)')
}).listen(80, () => {
console.log('Listening on port 80.')
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment