For my very first blog post here, I’m going to cover how to install and set up a blog on a VPS
(or to be more precise; a system with a static IP address
!).
The server we’ll be using for this is OpenBSD
because quite frankly; it’s extremely simple to set up servers on and has the added benefit of actually being secure by default. Don’t get me wrong… I’m also a sysadmin for production Linux-based web servers, but OpenBSD takes the stress out of life by keeping it simple.
Please note: Any AI assistance in my blog post was kept to the absolute minimal, with its use pretty much limited to finding the regular expressions for grep/sed commands (which I suck at) and learning how to visually organise markdown. AI isn’t quite up to the standard of writing a blog post as fantastical as mines, yet! ;)
For my next blog post, I’ll show you how to host from home on your own hardware and get around the whole dynamic IP address thing.
Enjoy the post!
Prerequisites
- A cheap virtual private server (VPS) such as one from Linode or Vultr
- Brand new, unconfigured OpenBSD installation
- Your domain’s A records pointing to the IP of your VPS server (@ and www)
The Plan
The following steps will take you all the way to having your very own public blog and with https.
I have written this blog for brand new OpenBSD users. As long as you know how to open a terminal on your Windows, Linux or Mac system and you know how to type: ssh root@your-ip-or-hostname.com
then you should be able to get an OpenBSD blog up and running in a few minutes if you are in a rush (eg if you were to skip my written text and head to the bottom for the script!) or 20-30 mins if you are wanting to take your time and go through it all.
Along the way, I am going to show you some nifty little tricks for debugging things which I had to use myself when building this server, such as checking for listening ports, seeing which processes were running on which ports, running the httpd (the web server) under daemon mode and other randomness which was crucial for me to write a blog post for you guys which just worked.
Some of you may wonder why I used Relayd as a reverse proxy for the HTTPD server when I could have just skipped that and had HTTPD server listen on port 443 and port 80. You’re right - I didn’t need to. But the truth is, I just wanted to because I really like the way Relayd handles https certs and I wanted to show others how to use the reverse proxy features.
Here are the steps we’ll be following:
-
Initial system maintenance
- Use syspatch to update the server
- Setting your hostname
- Setting the server variables
- Configure the correct time for your region
- Change the SSHD port to reduce password attacks
- Create a new non-root user, add them to the ‘wheel’ group and configure
doas
-
Create a Barebones HTTPD Web Server
- Create directory layout with correct permissions
- Generate the httpd config
- Testing the httpd web server
- Diagnosing httpd issues
-
Build a TLS Reverse Proxy with Relayd
- Generate the relayd config
- Testing the relayd config
- Diagnosing relayd issues
-
It’s TLS Time with Let’s Encrypt!
- Generate acme-client.conf and request certificates
- Testing the new TLS certs with relayd and httpd
- Set up a crontab for automated cert generation
- Automated certificate renewal
-
Setting Up a Hugo Blog
- Create the hugo site directory
- Create a new hugo site
- Configuring git and installing the PaperMod theme
- Updating the PaperMod theme
- Configure hugo.toml
- Structure of the hugo directory
- Lets write about.md
- Build and push to the web directory
- Skeleton post
- Front matter
- Create a post
- Build and publish
- Building another blog post with cover image
Extra: Easy Setup Script
How to Follow this Guide
I have tried to make this post as useful as possible by sneakily trying to teach a little bit of scripting and debugging.
All code between the following lines can be safely copied and pasted into your terminal in one big chunk:
###### COPYPASTASTART ######
###### COPYPASTAEND ######
If you see a code block which doesn’t have the ###### COPYPASTASTART ######
, it simply means it might be easier to paste in each line of code at a time so you can easily read the output of the commands - but you can still copy/paste whole blocks and it should work regardless if you’re in a rush for a nice new blog.
There is also a full KSH script at the end of this blog post if you prefer.
Initial System Maintenance
1. Use syspatch
to Update the Server
Ensure your system is up to date and install the necessary packages with the following commands:
syspatch
pkg_add nano git hugo
Explanation:
syspatch
: Updates the system with the latest patches and security fixes.pkg_add
: Installs the following packages:nano
: A text editor.git
: A version control system for tracking changes in your codebase.hugo
: A static site generator for building websites quickly.
Note: If you’re asked which version of Hugo you want, choose the extended version.
2. Setting Your Hostname
To add your hostname (e.g., tatties.scot
) to the /etc/myname
file, execute the following command:
###### COPYPASTASTART ######
{
echo 'A root domain name is like tatties.scot, i.e., without the www part.'
# Loop until a valid input is entered
while true; do
read -r "hostname_choice?What is your root hostname?: "
if [ -n "$hostname_choice" ]; then
break
fi
done
echo "$hostname_choice" > /etc/myname
hostname -s "$hostname_choice"
}
###### COPYPASTAEND ######
All of the following code will use this hostname you have just set.
3. Setting the Server Variables
These are the variables we are going to use for the server. Change them if you want, or just keep it simple and copy/paste as seen.
If you’re not following this entire guide in one sitting, you may need to come back and copy/paste these again or your variables might be empty - you will know they are empty when all the commands stop working! I have made these variables a bit smart, so it shouldn’t change the WEBSERVERport
or the SSHport
if they’re already set up.
###### COPYPASTASTART ######
HOSTname="$(hostname)"
HOST_name=$(echo "${HOSTname}" | sed 's/\./_/g')
SUBHOSTname="www.${HOSTname}"
SUB_HOST_name="www_${HOST_name}"
HTTPD_CHROOT="/var/www/htdocs"
REL_WEBSITE_DIR="${HOSTname}"
REL_WEBSITE_DIR_PUBLIC="${REL_WEBSITE_DIR}/public"
REL_ACME_CHALLENGE_DIR="${REL_WEBSITE_DIR}/acme"
ABS_ACME_CHALLENGE_DIR="${HTTPD_CHROOT}/${REL_WEBSITE_DIR}/acme"
ABS_WEBSITE_DIR="${HTTPD_CHROOT}/${REL_WEBSITE_DIR}"
ABS_WEBSITE_DIR_PUBLIC="${ABS_WEBSITE_DIR}/public"
ABS_WEBSITE_DIR_LOGS="${ABS_WEBSITE_DIR}/logs"
HUGO_DIR="${ABS_WEBSITE_DIR}/hugo"
# If httpd.conf already contains a port number, use that. Otherwise, generate a random port number.
WEBSERVERport=$(grep -m 1 -o '127\.0\.0\.1 port [0-9]*' /etc/httpd.conf | awk '{print $3}')
if [ -z "$WEBSERVERport" ]; then
WEBSERVERport=$((RANDOM % (65535 - 1000 + 1) + 1000))
fi
# If sshd_config already contains the default port number, generate a random port number. Otherwise, use same port from sshd_config.
SSHport=$(grep -m 1 -o '#Port 22' /etc/ssh/sshd_config)
if [ -z "$SSHport" ]; then
SSHport=$(grep -m 1 -o 'Port [0-9]*' /etc/ssh/sshd_config | awk '{print $2}')
else
SSHport=$((RANDOM % (65535 - 1000 + 1) + 1000))
fi
###### COPYPASTAEND ######
4. Configure the Correct Time for Your Region
To ensure your log files display the correct time, follow these steps:
-
List the Available Time Zones and Symlink to Yours:
ls /usr/share/zoneinfo/Europe/
-
Update the
/etc/localtime
file:Glasgow isn’t in the zoneinfo directory, so pick London or create a symlink:
ln -s /usr/share/zoneinfo/Europe/London /usr/share/zoneinfo/Europe/Glesga ln -sf "/usr/share/zoneinfo/Europe/Glesga" /etc/localtime
5. Change SSHD port to reduce password attacks
###### COPYPASTASTART ######
{
sed -i "s/^\(#\)\{0,1\}\(Port \)[0-9]*/\2${SSHport}/" /etc/ssh/sshd_config
print "Your new SSH port number is: $SSHport"
print "In future, you can connect with: ssh -p $SSHport $(whoami)@$(hostname)"
}
###### COPYPASTAEND ######
When you’re ready, you can run rcctl -df restart sshd
before logging back in on your new ssh port.
An example of the effectiveness of changing the default SSH port from 22:
# doas tail -n 30 /var/log/authlog
May 6 20:34:39 image sshd[50696]: Invalid user hadoop from 170.64.187.255 port 50890
May 6 20:34:40 image sshd[50696]: Failed password for invalid user hadoop from 170.64.187.255 port 50890 ssh2
May 6 20:34:40 image sshd[50696]: Connection closed by invalid user hadoop 170.64.187.255 port 50890 [preauth]
May 6 20:34:52 image sshd[15427]: Invalid user bigdata from 170.64.187.255 port 47118
May 6 20:34:52 image sshd[15427]: Failed password for invalid user bigdata from 170.64.187.255 port 47118 ssh2
May 6 20:34:52 image sshd[15427]: Connection closed by invalid user bigdata 170.64.187.255 port 47118 [preauth]
May 6 20:35:02 image sshd[96148]: Invalid user flink from 170.64.187.255 port 43344
May 6 20:35:03 image sshd[96148]: Failed password for invalid user flink from 170.64.187.255 port 43344 ssh2
May 6 20:35:03 image sshd[96148]: Connection closed by invalid user flink 170.64.187.255 port 43344 [preauth]
May 6 20:35:14 image sshd[70459]: Invalid user tomcat from 170.64.187.255 port 39580
May 6 20:35:14 image sshd[70459]: Failed password for invalid user tomcat from 170.64.187.255 port 39580 ssh2
May 6 20:35:15 image sshd[70459]: Connection closed by invalid user tomcat 170.64.187.255 port 39580 [preauth]
May 6 20:35:27 image sshd[10843]: Invalid user app from 170.64.187.255 port 35810
May 6 20:35:29 image sshd[10843]: Failed password for invalid user app from 170.64.187.255 port 35810 ssh2
May 6 20:35:29 image sshd[10843]: Connection closed by invalid user app 170.64.187.255 port 35810 [preauth]
May 6 20:35:39 image sshd[97733]: Failed password for www from 170.64.187.255 port 60118 ssh2
May 6 20:35:41 image sshd[97733]: Connection closed by authenticating user www 170.64.187.255 port 60118 [preauth]
May 6 20:35:48 image sshd[78349]: Invalid user mahan from 170.64.187.255 port 56500
May 6 20:35:48 image sshd[78349]: Failed password for invalid user mahan from 170.64.187.255 port 56500 ssh2
May 6 20:35:48 image sshd[78349]: Connection closed by invalid user mahan 170.64.187.255 port 56500 [preauth]
May 6 20:35:57 image sshd[75]: Failed password for root from 170.64.187.255 port 52622 ssh2
May 6 20:35:57 image sshd[75]: Connection closed by authenticating user root 170.64.187.255 port 52622 [preauth]
May 6 20:43:26 image sshd[57025]: Received signal 15; terminating.
May 6 20:43:27 image sshd[59058]: Server listening on 0.0.0.0 port 17556.
May 6 20:43:27 image sshd[59058]: Server listening on :: port 17556.
May 6 20:43:52 image sshd[47664]: Received disconnect from XXX.XXX.XXX.69 port 65380:11: disconnected by user
May 6 20:43:52 image sshd[47664]: Disconnected from user root XXX.XXX.XXX.69 port 65430
May 6 20:44:26 image sshd[56497]: Accepted password for root from XXX.XXX.XXX.69 port 63568 ssh2
18 hours later and you can see how quiet my SSH server is… These connections are just me logging in.
May 6 20:43:26 image sshd[57025]: Received signal 15; terminating.
May 6 20:43:27 image sshd[59058]: Server listening on 0.0.0.0 port 17556.
May 6 20:43:27 image sshd[59058]: Server listening on :: port 17556.
May 6 20:43:52 image sshd[47664]: Received disconnect from XXX.XXX.XXX.69 port 65380:11: disconnected by user
May 6 20:43:52 image sshd[47664]: Disconnected from user root XXX.XXX.XXX.69 port 65380
May 6 20:44:26 image sshd[56497]: Accepted password for root from XXX.XXX.XXX.69 port 63568 ssh2
May 7 15:48:20 image sshd[25576]: Accepted password for root from XXX.XXX.XXX.69 port 54435 ssh2
Get it up yae bots!
7. Create a New Non-Root User, Add Them to the wheel
Group and Configure doas
After you have created your blog, you will be able to log in with a brand new user you are about to create:
###### COPYPASTASTART ######
{
while true; do
read -r "USERname?Enter your username: "
if [ -n "$USERname" ]; then
break
fi
done
# Prompt for PASSword
while true; do
read -r "PASSword?Enter your password: "
if [ -n "$PASSword" ]; then
break
fi
done
# Let's create the new user
useradd -m -s /bin/ksh -p $(encrypt ${PASSword}) ${USERname}
# Modify new user to the 'wheel' group
usermod -G wheel $USERname
# Update /etc/doas.conf
echo "permit persist keepenv :wheel" >> /etc/doas.conf
echo "permit nopass :wheel as www" >> /etc/doas.conf
}
###### COPYPASTAEND ######
Create a Barebones HTTPD Server
We’ll be placing your web directory inside here: /var/www/htdocs/
, so it should look something like /var/www/htdocs/tatties.scot
.
1. Create Directory Layout with Correct Permissions
As our HTTPD server runs under the www
user, we’ll create the following directory structure and permissions.
###### COPYPASTASTART ######
install -d -m 750 -o www -g www ${ABS_WEBSITE_DIR}/public
install -d -m 750 -o www -g www ${ABS_WEBSITE_DIR}/logs
install -d -m 750 -o www -g www ${ABS_ACME_CHALLENGE_DIR}/logs
###### COPYPASTAEND ######
2. Generate the HTTPD Config
Let’s write the /etc/httpd.conf
with a super simple config. Notice that there is no TLS
mentioned in this config, because HTTPD
won’t be responsible for the HTTPS connection we’ll soon have, Relayd
will.
###### COPYPASTASTART ######
httpd_conf=$(cat <<EOF
chroot "${HTTPD_CHROOT}"
logdir "${ABS_WEBSITE_DIR_LOGS}"
# If a connection comes in without a matching hostname, drop and block it
server "default" {
listen on 127.0.0.1 port ${WEBSERVERport}
block drop
}
server "${HOSTname}" {
alias www.${HOSTname}
listen on 127.0.0.1 port ${WEBSERVERport}
root "${REL_WEBSITE_DIR_PUBLIC}/"
directory index index.html
gzip-static
# Give Letsencrypt access to http://${HOSTname}/.well-known/acme-challenge/*
location "/.well-known/acme-challenge/*" {
root "${REL_ACME_CHALLENGE_DIR}/"
request strip 2
}
}
EOF
)
print "$httpd_conf" > /etc/httpd.conf
###### COPYPASTAEND ######
Notice that we are listening on 127.0.0.1
(meaning it’s not directly available to anyone but the system itself) and on a random port.
For all connections which come into our HTTPD
server which match "default"
(i.e. any connection where the host header
does not match the exact server hostnames, e.g. server "tatties.scot"
), we block and drop it.
For Let’s Encrypt, we drop them into the /var/www/htdocs/$(hostname)/acme
which is where OpenBSD’s acme-client
will be able to do its song and dance with Let’s Encrypt to get us our certs.
3. Testing the HTTPD Web Server
We’ll write a txt file to our public web directory with the word 'IMUP!'
, then we’ll enable and fire up the HTTPD web server and give it a try with curl to see if it’s working.
###### COPYPASTASTART ######
doas -u www echo "IMUP!" > ${ABS_WEBSITE_DIR_PUBLIC}/status.txt
if httpd -n; then
rcctl -df enable httpd
rcctl set httpd flags "-f /etc/httpd.conf"
rcctl stop httpd && rcctl -df start httpd && sleep 3
curl -s -H "Host: ${HOSTname}" http://127.0.0.1:${WEBSERVERport}/status.txt
else
echo "Something went wrong!"
fi
###### COPYPASTAEND ######
You should see IMUP!
if the web server is up!
Notice the curl command with the flag -H "Host: ${HOSTname}"
, i.e. -H "Host: tatties.scot"
?
The reason for that is because we are making a connection to our local machine 127.0.0.1
on the random port that HTTPD
server is running on. But like I was last saying, if the hostname doesn’t match any server block, it will simply block and drop it. So I am having to use a little curl
trick to pass along the actual hostname I am trying to access while at the same time using a loopback IP Address within my curl command. That way -H "Host: tatties.scot"
matches the correct server "tatties.scot"
server block within my /etc/httpd.conf
instead of dropping my connection.
4. Diagnosing HTTPD Issues
If you experienced any issues with the previous command, the following may help you figure out why:
# Look for the running httpd processes:
ps aux | grep httpd
# Run HTTPD in the foreground to try spot problems that -n missed:
rcctl -df stop httpd
httpd -d -f /etc/httpd.conf
# Ensure HTTPD is listening on the correct port:
netstat -an | grep 127.0.0.1.${WEBSERVERport}
# Ensure it is HTTPD running on that port:
fstat | grep ':80'
# Kill HTTPD and start over:
pkill httpd
Now we have finished setting up the HTTPD Web Server, we will move on to make it publicly accessible using Relayd
.
Build a TLS Reverse Proxy with Relayd
Relayd in OpenBSD is a load balancer and application-layer gateway that distributes traffic across multiple servers, performs health checks, and supports TLS termination. It enhances service reliability, performance, and security by ensuring traffic is directed only to healthy servers and managing secure connections.
We will be using Relayd for it for it’s TLS termination and reverse proxying capabilities.
1. Generate the Relayd Config
The following will configure a reverse proxy to allow port 80/443
connections coming in from the outside to be proxied to the HTTPD
web server.
###### COPYPASTASTART ######
relayd_conf=$(cat <<EOF
table <${HOST_name}> { 127.0.0.1 }
table <${SUB_HOST_name}> { 127.0.0.1 }
http protocol "http" {
match request header append "FORWARDED_FOR" value "\$REMOTE_ADDR"
match request header set "FORWARDED_PROTO" value "\$REQUEST_SCHEME"
match request header set "HTTP_HOST" value "\$HOST"
match request header append "REMOTE_ADDR" value "\$REMOTE_ADDR"
match request header set "DOCUMENT_URI" value "\$DOCUMENT_URI"
match request header set "QUERY_STRING" value "\$QUERY_STRING"
match request header set "QUERY_STRING_ENC" value "\$QUERY_STRING_ENC"
match request header set "REMOTE_PORT" value "\$REMOTE_PORT"
match request header set "REMOTE_USER" value "\$REMOTE_USER"
match request header set "SERVER_ADDR" value "\$SERVER_ADDR"
match request header set "SERVER_PORT" value "\$SERVER_PORT"
match request header set "SERVER_NAME" value "\$SERVER_NAME"
match request header set "REQUEST_SCHEME" value "\$REQUEST_SCHEME"
match request header set "REQUEST_URI" value "\$REQUEST_URI"
match request header "Host" value "${HOSTname}" forward to <${HOST_name}>
match request header "Host" value "${SUBHOSTname}" forward to <${SUB_HOST_name}>
}
#£http protocol "https" {
#£ match request header append "FORWARDED_FOR" value "\$REMOTE_ADDR"
#£ match request header set "FORWARDED_PROTO" value "\$REQUEST_SCHEME"
#£ match request header set "HTTP_HOST" value "\$HOST"
#£ match request header append "REMOTE_ADDR" value "\$REMOTE_ADDR"
#£ match request header set "DOCUMENT_URI" value "\$DOCUMENT_URI"
#£ match request header set "QUERY_STRING" value "\$QUERY_STRING"
#£ match request header set "QUERY_STRING_ENC" value "\$QUERY_STRING_ENC"
#£ match request header set "REMOTE_PORT" value "\$REMOTE_PORT"
#£ match request header set "REMOTE_USER" value "\$REMOTE_USER"
#£ match request header set "SERVER_ADDR" value "\$SERVER_ADDR"
#£ match request header set "SERVER_PORT" value "\$SERVER_PORT"
#£ match request header set "SERVER_NAME" value "\$SERVER_NAME"
#£ match request header set "REQUEST_SCHEME" value "\$REQUEST_SCHEME"
#£ match request header set "REQUEST_URI" value "\$REQUEST_URI"
#£
#£ tls keypair "${HOSTname}"
#£ match request header "Host" value "${HOSTname}" forward to <${HOST_name}>
#£ match request header "Host" value "${SUBHOSTname}" forward to <${SUB_HOST_name}>
#£}
relay "${HOST_name}_http_relay" {
listen on 0.0.0.0 port 80
protocol "http"
forward to <${HOST_name}> port ${WEBSERVERport}
forward to <${SUB_HOST_name}> port ${WEBSERVERport}
}
#£relay "${HOST_name}_https_relay" {
#£ listen on 0.0.0.0 port 443 tls
#£ protocol "https"
#£ forward to <${HOST_name}> port ${WEBSERVERport}
#£ forward to <${SUB_HOST_name}> port ${WEBSERVERport}
#£}
EOF
)
print "$relayd_conf" > /etc/relayd.conf
###### COPYPASTAEND ######
If you are wondering what all those #£
are, those are just comments which will be removed as soon as we have our TLS certs in from Letsencrypt. If we don’t comment those lines out, relayd will error because we haven’t got them yet!
2. Testing the Relayd Config
We’ll check the relayd.conf for any errors before enabling the service and restarting it.
###### COPYPASTSTART ######
relayd -n && rcctl -df enable relayd httpd
rcctl -df stop relayd httpd && rcctl -df start relayd httpd && sleep 3
curl http://${HOSTname}/status.txt
###### COPYPASTAEND ######
You should see 'IMUP!'
which confirms that connections coming in are being proxied to the HTTPD web server running on our custom port.
3. Diagnosing Relayd Issues
# Try running curl more verbose:
curl -v https://${HOSTname}/status.txt
# You could also check if Relayd is really up and listening on port 80:
fstat | grep ':80'
# You will see Relayd and HTTPD listening on ports with this one:
netstat -Aan | grep LISTEN
# If all else fails:
reboot
It’s TLS Time with Let’s Encrypt!
The biggest change Edward Snowden brought to the world was the mass adoption of https. These days without https, your site will utterly tank for SEO, so let’s get that dealt with.
1. Generate acme-client.conf and Request Certificates
###### COPYPASTASTART ######
cat << EOF > /etc/acme-client.conf
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
authority letsencrypt-staging {
api url "https://acme-staging-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-staging-privkey.pem"
}
# We will point to our own conf
include "/etc/acme-client.d/${HOST_name}.conf"
EOF
mkdir -p /etc/acme-client.d
cat << EOF > /etc/acme-client.d/${HOST_name}.conf
domain ${HOSTname} {
alternative names { www.${HOSTname} }
domain key "/etc/ssl/private/${HOSTname}:443.key"
domain full chain certificate "/etc/ssl/${HOSTname}:443.crt"
challengedir "${ABS_ACME_CHALLENGE_DIR}"
sign with letsencrypt
}
EOF
acme-client -vv "${HOSTname}"
###### COPYPASTAEND ######
Assuming you had no errors and Letsencrypt went swimmingly, we will need to remove the #£
’s from the relayd.conf and restart it to make use of our new TLS certs.
2. Testing Our New TLS Certs with Relayd and HTTPD
###### COPYPASTASTART ######
# Remove all mentions of '#£' from /etc/relayd.conf
sed -i 's/^#£//' /etc/relayd.conf
relayd -n && rcctl -df restart relayd && sleep 3
curl https://${HOSTname}/status.txt
###### COPYPASTAEND ######
The last curl command should have given you a reply of IMUP!
3. Diagnosing Relayd Issues
Here’s how you can diagnose any issue with Relayd:
# Check if Relayd is listening on port 443 (and 80 whilst we're at it):
netstat -an | grep 'LISTEN' | grep -e '*.80' -e '*.443'
# Try running relayd in the foreground to see what's happening:
relayd -d
# Try running curl more verbose:
curl -v https://${HOSTname}/status.txt
# Check HTTPD is up and listening on the correct port:
fstat | grep -e '127.0.0.1:${WEBSERVERport}'
You shouldn’t have had any errors in the last command, try this if you have:
rcctl -df restart httpd relayd
.
4. Automated Certificate Renewal
Now we know your acme-client can successfully retrieve certs with Let’s Encrypt, we will want to automate the process for renewing these certs before the 90 day expiry period. We’ll go for once a day at 1am.
(crontab -l 2>/dev/null; echo "0 1 * * * acme-client ${HOSTname}") | crontab -
Setting Up a Hugo Blog
Now that we have our web server and reverse proxy configured, it’s time to set up a Hugo blog to serve some content. Hugo is a fast and flexible static site generator that allows us to create a blog with minimal effort.
1. Create the Hugo Site Directory
###### COPYPASTASTART ######
umask 002
if [ ! -d "${HUGO_DIR}" ]; then
install -d -m 755 -o www -g www ${HUGO_DIR}
fi
###### COPYPASTAEND ######
2. Create a New Hugo Site
We’ll now create the Hugo directory within our site directory, but not in the public directory. This will use the standard TOML
formatting.
###### COPYPASTASTART ######
cd "${HUGO_DIR}"
doas -u www hugo new site .
###### COPYPASTAEND ######
YAML
instead of TOML
:
If you wish to use YAML
instead, you’ll slightly adjust the following command with a --format yaml
like so:
###### COPYPASTASTART ######
cd "${HUGO_DIR}"
doas -u www hugo new site . --format yaml
###### COPYPASTAEND ######
3. Configuring GIT and Installing the PaperMod Theme
We’ll be adding the PaperMod theme as a submodule… This is the ‘recommended way’ do do things.
###### COPYPASTASTART ######
cd "${HUGO_DIR}"
doas -u www git init
doas -u www git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
doas -u www git submodule update --init --recursive
###### COPYPASTAEND ######
4. Updating the PaperMod Theme
When you want to update the PaperMod theme to the latest version.
###### COPYPASTASTART ######
cd "${HUGO_DIR}"
doas -u www git submodule update --init --recursive
###### COPYPASTAEND ######
5. Configure the hugo.toml
file
This file is super important as it contains the site settings. There are a LOT of settings to configure for a real nice custom blog, but we’ll only be showing the basics. When you are ready to delve deeper, check out the PaperMod features here.
hugo.toml We’ll set the basics here such as your base url, activate the PaperMod theme and add a little menu.
###### COPYPASTASTART ######
doas -u www tee hugo.toml > /dev/null <<EOF
baseURL = "https://${HOSTname}/"
languageCode = "en-us"
title = "My Blog"
theme = "PaperMod"
[params]
description = "This is my brand new blog"
author = "John Doe"
[[menu.main]]
identifier = "home"
name = "Home"
url = "/"
weight = 1
[[menu.main]]
identifier = "about"
name = "About"
url = "/about/"
weight = 2
EOF
###### COPYPASTAEND ######
hugo.yaml (Only if you chose to go with YAML
formatting)
###### COPYPASTASTART ######
doas -u www tee hugo.yaml > /dev/null <<EOF
baseURL: "https://${HOSTname}/"
languageCode: "en-us"
title: "My Blog"
theme: "PaperMod"
params:
description: "This is my brand new blog"
author: "John Doe"
menu:
main:
- identifier: "home"
name: "Home"
url: "/"
weight: 1
- identifier: "about"
name: "About"
url: "/about/"
weight: 2
EOF
###### COPYPASTAEND ######
6. Structure of the Hugo Directory
layouts/ Themes come with their own ’layouts’ directory, these html layouts. If we want to customise our layouts then we can change the layouts within the theme’s directory or we can copy the layouts to our own empty ’layouts’ directory from the root of the Hugo directory and edit it from there.
The advantage of copying the layouts to our own empty layouts directory is we can update our theme without overwriting our custom layouts we’ve created. Think of it like child themes you may be used to in the Wordpress world.
static/ All static assets like images
content/ This is where all our actual content goes, such as our written blog posts.
We’ll create a layouts directory and then copy all the layouts from the theme into it. The means if we want to customise our layouts that they won’t be written over when we next update the theme. But, you could just skip this step and only copy in the layout files you actually want to customise instead of pulling everything in.
###### COPYPASTASTART ######
doas -u www mkdir -p ${HUGO_DIR}/layouts
doas -u www cp -R ${HUGO_DIR}themes/PaperMod/layouts/* layouts/
###### COPYPASTAEND ######
7. Lets Write about.md
###### COPYPASTASTART ######
doas -u www tee content/about.md > /dev/null <<EOF
---
title: "About"
date: $(date +"%Y-%m-%dT%H:%M:%S%z")
---
I'm John Doe, an OpenBSD enthusiast and developer. I created this blog to share tutorials and insights about OpenBSD.
Feel free to explore the blog and learn more about OpenBSD!
EOF
###### COPYPASTAEND ######
8. Build and Push to the Web Directory
We need to tell Hugo to turn the mardown into actual HTML and fire it into our public facing HTTPD directory.
doas -u www hugo --destination="${ABS_WEBSITE_DIR_PUBLIC}" --cleanDestinationDir=true
The --cleanDestinationDir=true
simply removes all other files from the public web directory before building and publishing again. Does what it says really!
Now go and check the blog’s about page, it’s basic still, but we’ll get on to the good stuff next.
9. Skeleton Post
First we’ll create the 'posts'
directory and then we’ll use Hugo to generate our first skeleton post with 'Front Matter'
.
###### COPYPASTASTART ######
doas -u www mkdir -p content/posts
doas -u www hugo new posts/adding-users-and-setting-up-doas.md
###### COPYPASTAEND ######
Hugo takes the posts/adding-users-and-setting-up-doas.md
argument and uses it to create a skeleton post in the contents/posts
directory. If we had another directory we wanted to use, we’d give it something like:
doas -u www hugo new anotherdir/a-post-within-anotherdir.md
10. Front Matter
Let’s take a look at content/posts/adding-users-and-setting-up-doas.md
(the post we generated above):
tatties.scot# cat content/posts/adding-users-and-setting-up-doas.md
+++
title = 'Adding Users and Setting Up Doas'
date = 2024-05-14T15:17:07+01:00
draft = true
+++
These are the dynamically generated settings. But we can hand edit these settings to also include a cover image and more (we’ll get to that later).
11. Create a Post
As we already have the 'Adding Users and Setting Up Doas'
skeleton post with ‘Front Matter’, we’ll use the append flag (tee -a
) so to keep the title/date/draft section which hugo created:
###### COPYPASTASTART ######
doas -u www tee -a content/posts/adding-users-and-setting-up-doas.md >> /dev/null <<EOF
In this tutorial, we'll cover how to add users and set up doas on OpenBSD.
## Adding a User
To add a new user, use the \`useradd\` command:
\`\`\`
# useradd -m john
# passwd john
\`\`\`
## Configuring Doas
Nano is a my favourite text editor:
1. Install the nano package:
\`\`\`
# pkg_add nano
\`\`\`
2. Create the /etc/doas.conf file and add the necessary permissions:
\`\`\`
# echo "permit keepenv :wheel" > /etc/doas.conf
\`\`\`
This allows users in the wheel group to run commands with doas.
3. Add the user to the wheel group:
\`\`\`
# usermod -G wheel john
\`\`\`
Now you can use doas to run commands with elevated privileges.
Happy OpenBSD adventures!
EOF
###### COPYPASTAEND ######
Now, of course.. You don’t need to use KSH HEREDOCS (the EOF bits!) to write blog posts… I’m doing that for the sake of quickly showing you how to get this blog up and running.
Personally, I use Joplin to write my markdown and then I copy and paste it into the .md
files or upload to content/posts
directory using FileZilla, sftp or scp.
12. Build and Publish
Before we build and publish, we need to change draft = true
to draft = false
:
doas -u www sed -i 's/draft = true/draft = false/' content/posts/adding-users-and-setting-up-doas.md
Build the static pages and publish to the public web directory
doas -u www hugo --destination="${ABS_WEBSITE_DIR_PUBLIC}" --cleanDestinationDir=true
Time to head over and see your first blog post!
13. Building A Blog Post with Cover Image
Housekeeping
To keep our static
directory clutter-free, we’ll create an images
directory for this before downloading an image to there.
###### COPYPASTASTART ######
doas -u www mkdir -p static/images
doas -u www ftp https://www.openbsd.org/images/puffy$(uname -r | tr -d .).gif
doas -u www mv puffy*.gif static/images
###### COPYPASTAEND ######
How to Add Cover Images to Posts
We’ll be using the official PaperMod instructions https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-features
Problem is, they only give these instuctions in YAML, but I chose to use TOML…
Not an issue, I will use a YAML to TOML Converter
YAML (the before)
cover:
image: "<image path/url>"
# can also paste direct link from external site
# ex. https://i.ibb.co/K0HVPBd/paper-mod-profilemode.png
alt: "<alt text>"
caption: "<text>"
relative: false # To use relative path for cover image, used in hugo Page-bundles
After the Conversion to TOML
[cover]
image = "<image path/url>"
alt = "<alt text>"
caption = "<text>"
relative = false
Building The Blog Post with Cover Image
#COPYPASTABEGIN
doas -u www tee content/posts/installing-nginx-on-openbsd.md >> /dev/null <<EOF
+++
title = "Installing Nginx on OpenBSD"
date = 2024-05-14T15:17:07+01:00
[cover]
image = "images/puffy$(uname -r | tr -d .).gif"
alt = "Puffy doing puffy things"
caption = "Puffy"
relative = true
+++
In this tutorial, we'll walk through the steps to install Nginx on OpenBSD and set up a "Hello, World!" page.
## Installing Nginx
1. Install the nginx package:
\`\`\`
# pkg_add nginx
\`\`\`
2. Enable and start the nginx service:
\`\`\`
# rcctl enable nginx
# rcctl start nginx
\`\`\`
## Configuring a "Hello, World!" Page
1. Create a new directory for your website:
\`\`\`
# mkdir -p /var/www/htdocs/example.com
\`\`\`
2. Create an index.html file with the following content:
\`\`\`html
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to my OpenBSD website!</p>
</body>
</html>
\`\`\`
3. Configure Nginx to serve your website by creating a new configuration file:
\`\`\`
# vi /etc/nginx/sites-available/example.com
\`\`\`
Add the following content to the file:
\`\`\`nginx
server {
listen 80;
server_name example.com;
root /var/www/htdocs/example.com;
index index.html;
}
\`\`\`
4. Create a symlink to enable the site:
\`\`\`
# ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
\`\`\`
5. Restart Nginx:
\`\`\`
# rcctl restart nginx
\`\`\`
Now, when you visit your OpenBSD server's IP address or domain name, you'll see the "Hello, World!" page.
Enjoy your new Nginx setup on OpenBSD!
EOF
# And change the draft status again:
doas -u www sed -i 's/draft = true/draft = false/' content/posts/installing-nginx-on-openbsd.md
#COPYPASTAEND
Build and Publish
doas -u www hugo --destination="${ABS_WEBSITE_DIR_PUBLIC}" --cleanDestinationDir=true
And go check out your creation.
Full Script
#!/bin/ksh
initial_system_maintenance() {
print "Initial system maintenance"
syspatch
pkg_add nano git hugo
echo 'A root domain name is like tatties.scot, i.e., without the www part.'
}
setting_your_hostname() {
print "Setting your hostname"
while true; do
read -r "hostname_choice?What is your root hostname?: "
if [ -n "$hostname_choice" ]; then
break
fi
done
echo "$hostname_choice" > /etc/myname
hostname -s "$hostname_choice"
}
setting_the_server_variables() {
print "Setting the server variables"
HOSTname="$(hostname)"
HOST_name=$(echo "${HOSTname}" | sed 's/\./_/g')
SUBHOSTname="www.${HOSTname}"
SUB_HOST_name="www_${HOST_name}"
HTTPD_CHROOT="/var/www/htdocs"
REL_WEBSITE_DIR="${HOSTname}"
REL_WEBSITE_DIR_PUBLIC="${REL_WEBSITE_DIR}/public"
REL_ACME_CHALLENGE_DIR="${REL_WEBSITE_DIR}/acme"
ABS_ACME_CHALLENGE_DIR="${HTTPD_CHROOT}/${REL_WEBSITE_DIR}/acme"
ABS_WEBSITE_DIR="${HTTPD_CHROOT}/${REL_WEBSITE_DIR}"
ABS_WEBSITE_DIR_PUBLIC="${ABS_WEBSITE_DIR}/public"
ABS_WEBSITE_DIR_LOGS="${ABS_WEBSITE_DIR}/logs"
HUGO_DIR="${ABS_WEBSITE_DIR}/hugo"
# If httpd.conf already contains a port number, use that. Otherwise, generate a random port number.
WEBSERVERport=$(grep -m 1 -o '127\.0\.0\.1 port [0-9]*' /etc/httpd.conf | awk '{print $3}')
if [ -z "$WEBSERVERport" ]; then
WEBSERVERport=$((RANDOM % (65535 - 1000 + 1) + 1000))
fi
# If sshd_config already contains the default port number, generate a random port number. Otherwise, use same port from sshd_config.
SSHport=$(grep -m 1 -o '#Port 22' /etc/ssh/sshd_config)
if [ -z "$SSHport" ]; then
SSHport=$(grep -m 1 -o 'Port [0-9]*' /etc/ssh/sshd_config | awk '{print $2}')
else
SSHport=$((RANDOM % (65535 - 1000 + 1) + 1000))
fi
}
change_sshd_port() {
print "Change SSHD port"
sed -i "s/^\(#\)\{0,1\}\(Port \)[0-9]*/\2${SSHport}/" /etc/ssh/sshd_config
print "Your new SSH port number is: $SSHport"
print "In future, you can connect with: ssh -p $SSHport $(whoami)@$(hostname)"
}
create_new_user() {
print "Create new user"
while true; do
read -r "USERname?Enter your username: "
if [ -n "$USERname" ]; then
break
fi
done
# Prompt for PASSword
while true; do
read -r "PASSword?Enter your password: "
if [ -n "$PASSword" ]; then
break
fi
done
useradd -m -s /bin/ksh -p $(encrypt ${PASSword}) ${USERname}
usermod -G wheel $USERname
echo "permit persist keepenv :wheel" >> /etc/doas.conf
echo "permit nopass :wheel as www" >> /etc/doas.conf
}
create_httpd_server() {
print "Create HTTPD server"
local RESPONSE=""
install -d -m 750 -o www -g www ${ABS_WEBSITE_DIR}/public
install -d -m 750 -o www -g www ${ABS_WEBSITE_DIR}/logs
install -d -m 750 -o www -g www ${ABS_ACME_CHALLENGE_DIR}/logs
httpd_conf=$(cat <<EOF
chroot "${HTTPD_CHROOT}"
logdir "${ABS_WEBSITE_DIR_LOGS}"
# If a connection comes in without a matching hostname, drop and block it
server "default" {
listen on 127.0.0.1 port ${WEBSERVERport}
block drop
}
server "${HOSTname}" {
alias www.${HOSTname}
listen on 127.0.0.1 port ${WEBSERVERport}
root "${REL_WEBSITE_DIR_PUBLIC}/"
directory index index.html
gzip-static
# Give Letsencrypt access to http://${HOSTname}/.well-known/acme-challenge/*
location "/.well-known/acme-challenge/*" {
root "${REL_ACME_CHALLENGE_DIR}/"
request strip 2
}
}
EOF
)
print "$httpd_conf" > /etc/httpd.conf
doas -u www echo "IMUP!" > ${ABS_WEBSITE_DIR_PUBLIC}/status.txt
if httpd -n; then
rcctl -df enable httpd
rcctl set httpd flags "-f /etc/httpd.conf"
rcctl stop httpd && rcctl -df start httpd && sleep 3
RESPONSE=$(curl -s -H "Host: ${HOSTname}" http://127.0.0.1:${WEBSERVERport}/status.txt)
if [ "$RESPONSE" != "IMUP!" ]; then
echo "Something went wrong during testing this command: curl -s -H "Host: ${HOSTname}" http://127.0.0.1:${WEBSERVERport}/status.txt"
exit 1
fi
else
echo "Something went wrong during testing this command: httpd -n"
fi
print "Finished writing HTTPD config"
}
relayd_proxy() {
print "Create Relayd server"
local RESPONSE=""
relayd_conf=$(cat <<EOF
table <${HOST_name}> { 127.0.0.1 }
table <${SUB_HOST_name}> { 127.0.0.1 }
http protocol "http" {
match request header append "FORWARDED_FOR" value "\$REMOTE_ADDR"
match request header set "FORWARDED_PROTO" value "\$REQUEST_SCHEME"
match request header set "HTTP_HOST" value "\$HOST"
match request header append "REMOTE_ADDR" value "\$REMOTE_ADDR"
match request header set "DOCUMENT_URI" value "\$DOCUMENT_URI"
match request header set "QUERY_STRING" value "\$QUERY_STRING"
match request header set "QUERY_STRING_ENC" value "\$QUERY_STRING_ENC"
match request header set "REMOTE_PORT" value "\$REMOTE_PORT"
match request header set "REMOTE_USER" value "\$REMOTE_USER"
match request header set "SERVER_ADDR" value "\$SERVER_ADDR"
match request header set "SERVER_PORT" value "\$SERVER_PORT"
match request header set "SERVER_NAME" value "\$SERVER_NAME"
match request header set "REQUEST_SCHEME" value "\$REQUEST_SCHEME"
match request header set "REQUEST_URI" value "\$REQUEST_URI"
match request header "Host" value "${HOSTname}" forward to <${HOST_name}>
match request header "Host" value "${SUBHOSTname}" forward to <${SUB_HOST_name}>
}
#£http protocol "https" {
#£ match request header append "FORWARDED_FOR" value "\$REMOTE_ADDR"
#£ match request header set "FORWARDED_PROTO" value "\$REQUEST_SCHEME"
#£ match request header set "HTTP_HOST" value "\$HOST"
#£ match request header append "REMOTE_ADDR" value "\$REMOTE_ADDR"
#£ match request header set "DOCUMENT_URI" value "\$DOCUMENT_URI"
#£ match request header set "QUERY_STRING" value "\$QUERY_STRING"
#£ match request header set "QUERY_STRING_ENC" value "\$QUERY_STRING_ENC"
#£ match request header set "REMOTE_PORT" value "\$REMOTE_PORT"
#£ match request header set "REMOTE_USER" value "\$REMOTE_USER"
#£ match request header set "SERVER_ADDR" value "\$SERVER_ADDR"
#£ match request header set "SERVER_PORT" value "\$SERVER_PORT"
#£ match request header set "SERVER_NAME" value "\$SERVER_NAME"
#£ match request header set "REQUEST_SCHEME" value "\$REQUEST_SCHEME"
#£ match request header set "REQUEST_URI" value "\$REQUEST_URI"
#£
#£ tls keypair "${HOSTname}"
#£ match request header "Host" value "${HOSTname}" forward to <${HOST_name}>
#£ match request header "Host" value "${SUBHOSTname}" forward to <${SUB_HOST_name}>
#£}
relay "${HOST_name}_http_relay" {
listen on 0.0.0.0 port 80
protocol "http"
forward to <${HOST_name}> port ${WEBSERVERport}
forward to <${SUB_HOST_name}> port ${WEBSERVERport}
}
#£relay "${HOST_name}_https_relay" {
#£ listen on 0.0.0.0 port 443 tls
#£ protocol "https"
#£ forward to <${HOST_name}> port ${WEBSERVERport}
#£ forward to <${SUB_HOST_name}> port ${WEBSERVERport}
#£}
EOF
)
print "$relayd_conf" > /etc/relayd.conf
relayd -n && rcctl -df enable relayd httpd
rcctl -df stop relayd httpd && rcctl -df start relayd httpd && sleep 3
RESPONSE=$(curl -s http://${HOSTname}/status.txt)
if [ "$RESPONSE" != "IMUP!" ]; then
echo "Something went wrong during testing this command: curl -s http://${HOSTname}/status.txt"
exit 1
fi
}
acme_setup() {
print "Create TLS certs"
local RESPONSE=""
cat << EOF > /etc/acme-client.conf
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
authority letsencrypt-staging {
api url "https://acme-staging-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-staging-privkey.pem"
}
# We will point to our own conf
include "/etc/acme-client.d/${HOST_name}.conf"
EOF
mkdir -p /etc/acme-client.d
cat << EOF > /etc/acme-client.d/${HOST_name}.conf
domain ${HOSTname} {
alternative names { www.${HOSTname} }
domain key "/etc/ssl/private/${HOSTname}:443.key"
domain full chain certificate "/etc/ssl/${HOSTname}:443.crt"
challengedir "${ABS_ACME_CHALLENGE_DIR}"
sign with letsencrypt
}
EOF
acme-client -vv "${HOSTname}" && sleep 1
sed -i 's/^#£//' /etc/relayd.conf
relayd -n && rcctl -df restart relayd && sleep 3
RESPONSE=$(curl -s https://${HOSTname}/status.txt)
if [ "$RESPONSE" != "IMUP!" ]; then
echo "Something went wrong during testing this command: curl -s https://${HOSTname}/status.txt"
exit 1
fi
(crontab -l 2>/dev/null; echo "0 1 * * * acme-client ${HOSTname}") | crontab -
}
hugo_setup() {
print "Set up Hugo Blog"
umask 002
if [ ! -d "${HUGO_DIR}" ]; then
install -d -m 755 -o www -g www ${HUGO_DIR}
fi
cd "${HUGO_DIR}"
doas -u www hugo new site .
doas -u www git init
doas -u www git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
doas -u www git submodule update --init --recursive
doas -u www tee hugo.toml > /dev/null <<EOF
baseURL = "https://${HOSTname}/"
languageCode = "en-us"
title = "My Blog"
theme = "PaperMod"
[params]
description = "This is my brand new blog"
author = "John Doe"
[[menu.main]]
identifier = "home"
name = "Home"
url = "/"
weight = 1
[[menu.main]]
identifier = "about"
name = "About"
url = "/about/"
weight = 2
EOF
doas -u www mkdir -p layouts
doas -u www cp -R themes/PaperMod/layouts/* layouts/
doas -u www tee content/about.md > /dev/null <<EOF
---
title: "About"
date: $(date +"%Y-%m-%dT%H:%M:%S%z")
---
I'm John Doe, an OpenBSD enthusiast and developer. I created this blog to share tutorials and insights about OpenBSD.
Feel free to explore the blog and learn more about OpenBSD!
EOF
doas -u www mkdir -p content/posts
doas -u www mkdir -p static/images
doas -u www ftp https://www.openbsd.org/images/puffy$(uname -r | tr -d .).gif
doas -u www mv puffy*.gif static/images
doas -u www tee content/posts/installing-nginx-on-openbsd.md >> /dev/null <<EOF
+++
title = "Installing Nginx on OpenBSD"
date = 2024-05-14T15:17:07+01:00
[cover]
image = "images/puffy$(uname -r | tr -d .).gif"
alt = "Puffy doing puffy things"
caption = "Puffy"
relative = true
+++
In this tutorial, we'll walk through the steps to install Nginx on OpenBSD and set up a "Hello, World!" page.
## Installing Nginx
1. Install the nginx package:
\`\`\`
# pkg_add nginx
\`\`\`
2. Enable and start the nginx service:
\`\`\`
# rcctl enable nginx
# rcctl start nginx
\`\`\`
## Configuring a "Hello, World!" Page
1. Create a new directory for your website:
\`\`\`
# mkdir -p /var/www/htdocs/example.com
\`\`\`
2. Create an index.html file with the following content:
\`\`\`html
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>Welcome to my OpenBSD website!</p>
</body>
</html>
\`\`\`
3. Configure Nginx to serve your website by creating a new configuration file:
\`\`\`
# vi /etc/nginx/sites-available/example.com
\`\`\`
Add the following content to the file:
\`\`\`nginx
server {
listen 80;
server_name example.com;
root /var/www/htdocs/example.com;
index index.html;
}
\`\`\`
4. Create a symlink to enable the site:
\`\`\`
# ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
\`\`\`
5. Restart Nginx:
\`\`\`
# rcctl restart nginx
\`\`\`
Now, when you visit your OpenBSD server's IP address or domain name, you'll see the "Hello, World!" page.
Enjoy your new Nginx setup on OpenBSD!
EOF
doas -u www sed -i 's/draft = true/draft = false/' content/posts/installing-nginx-on-openbsd.md
doas -u www hugo --destination="${ABS_WEBSITE_DIR_PUBLIC}" --cleanDestinationDir=true
}
initial_system_maintenance
setting_your_hostname
setting_the_server_variables
change_sshd_port
create_new_user
create_httpd_server
relayd_proxy
acme_setup
hugo_setup
echo "Here's a copy of the variables we used for this:
export HOSTname=\"${HOSTname}\"
export SSHport=\"${SSHport}\"
export USERname=\"${USERname}\"
export PASSword=\"${PASSword}\"
export WEBSERVERport=\"${WEBSERVERport}\"
export HTTPD_CHROOT=\"${HTTPD_CHROOT}\"
export REL_WEBSITE_DIR=\"${REL_WEBSITE_DIR}\"
export REL_WEBSITE_DIR_PUBLIC=\"${REL_WEBSITE_DIR_PUBLIC}\"
export REL_ACME_CHALLENGE_DIR=\"${REL_ACME_CHALLENGE_DIR}\"
export ABS_ACME_CHALLENGE_DIR=\"${ABS_ACME_CHALLENGE_DIR}\"
export ABS_WEBSITE_DIR=\"${ABS_WEBSITE_DIR}\"
export ABS_WEBSITE_DIR_PUBLIC=\"${ABS_WEBSITE_DIR_PUBLIC}\"
export HOST_name=\"${HOST_name}\"
export SUBHOSTname=\"${SUBHOSTname}\"
export SUB_HOST_name=\"${SUB_HOST_name}\"
export HUGO_DIR=\"${HUGO_DIR}\"
> "