Install Ghost on FreeBSD 13
A guide to installing Ghost on FreeBSD 13 from scratch.
How old is it?
I don't have anything funny to say, actually. The new post will continue to be updated in place after every major/minor release or when Ghost changes node/database dependencies.
My first post for this blog was about setting Ghost up on FreeBSD, which I had just done. I've migrated to a new server running FreeBSD 13 to celebrate the new release, and recent Ghost installer updates changed some things. So we'll do this over.
One thing I want to get out of the way is how much Ghost v4 has changed things. v4 has new monetization features that hobby bloggers might not want to use, whereas v3 is just a friendly blogging app. If you're interested in having email subscribers and paid content, you'll want to use v4. I'm going to describe installing both, but as of the time I'm writing this, my website is still on Ghost v3.
Nothing about what I'm going to show you is officially supported by the project, so don't go crying to them or me if this breaks during an upgrade.
Let's go ahead and install Ghost's dependencies.
# pkg install mysql57-client mysql57-server node14 npm-node14 nginx py37-certbot py37-certbot-nginx
Now let's get the database ready. Enable the server and run the secure installation script. The prompts are self-explanatory.
# service mysql-server enable
# service mysql-server start
# mysql_secure_installation
Prepare a database and user for ghost.
# mysql -u root -p
CREATE USER 'ghost'@'localhost' IDENTIFIED BY 'IsThisEnoughBitsOfEntropy?_^';
CREATE DATABASE yourblog_ext_prod;
GRANT ALL privileges ON `yourblog_ext_prod`.* TO 'ghost'@'localhost';
Install ghost-cli
. We'll handle the user account and web directories next.
# npm install ghost-cli -g
Run adduser
and follow the prompts to make an unprivileged user named ghost
. The official docs say to give it sudoer permissions, but I'm saying not to. From a default install, this just means don't add the user to the group wheel
.
# mkdir /usr/local/www/yourblog.ext
# chown ghost:ghost /usr/local/www/yourblog.ext
# chmod 775 /usr/local/www/yourblog.ext
# su - ghost
$ cd /usr/local/www/yourblog.ext
Install either v3 or v4 of ghost.
ghost install v3
OR
ghost install v4
Answer the following questions accordingly:
System checks failed with message: 'Operating system is not Linux'
Some features of Ghost-CLI may not work without additional configuration.
For local installs we recommend using `ghost install local` instead.
? Continue anyway? Yes
? Enter your blog URL: https://yourblog.ext/
? Enter your MySQL hostname: localhost
? Enter your MySQL username: ghost
? Enter your MySQL password: [hidden]
? Enter your Ghost database name: yourblog_ext_prod
? Do you wish to set up Systemd? No
? Do you want to start Ghost? No
Fix permissions on the file the database password is in and start up.
$ chmod 600 /usr/local/www/yourblog.ext/config.production.json
$ ghost start
The rest of the steps require you switch back to the root user.
Let's enable nginx and get our certificate setup.
# service enable nginx
# service start nginx
# certbot run --nginx -d yourblog.ext -d www.yourblog.ext
Edit the http block in /usr/local/etc/nginx/nginx.conf to follow standard practices:
http {
include mime.types;
include /usr/local/etc/nginx/sites-enabled/*.conf;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
}
Create the sites-enabled and sites-available folders:
# mkdir /usr/local/etc/nginx/sites-available
# mkdir /usr/local/etc/nginx/sites-enabled
Edit /usr/local/etc/nginx/sites-available/yourblog_ext.conf
to look like the following:
server {
listen 80;
server_name yourblog.ext www.yourblog.ext;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name yourblog.ext www.yourblog.ext;
location / {
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:2368/;
}
location /ghost/ {
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:2368/ghost/;
allow 12.34.56.78; # YOUR IP ADDRESS GOES HERE otherwise your site will get hijacked
deny all;
}
ssl_certificate /usr/local/etc/letsencrypt/live/yourblog.ext/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/yourblog.ext/privkey.pem;
}
Here we have it redirecting to https because it's 2020. /ghost/ is the admin page, and we want it so that only you have access to it before you launch this. The setup wizard will let you create the admin account on the spot, and robots look for these kind of things. Afterward, you can either remove that, leave it, or add more allow lines to other addresses you'll connect from.
Now make sure that you or I did not make any mistakes here and resolve as needed.
ln -s /usr/local/etc/nginx/sites-available/yourblog_ext.conf /usr/local/etc/nginx/sites-enabled/yourblog_ext.conf
nginx -t
service nginx restart
Login to https://[yourbloghere]/ghost/ and begin setup. You should be ready to go.
Let's throw a service together so this will persist past a reboot. Create /usr/local/etc/rc.d/ghost
and modify the following to be relevant to your service:
#!/bin/sh
# PROVIDE: ghost
# REQUIRE: mysql
# KEYWORD: shutdown
. /etc/rc.subr
name="ghost"
rcvar="ghost_enable"
extra_commands="status"
load_rc_config ghost
start_cmd="ghost_start"
stop_cmd="ghost_stop"
restart_cmd="ghost_restart"
status_cmd="ghost_status"
PATH=/bin:/usr/bin:/usr/local/bin:/home/ghost/.bin
ghost_start()
{
su ghost -c "/usr/local/bin/ghost start -d /usr/local/www/yourblog.ext"
}
ghost_stop()
{
su ghost -c "/usr/local/bin/ghost stop -d /usr/local/www/yourblog.ext"
}
ghost_restart()
{
ghost_stop;
ghost_start;
}
ghost_status()
{
su ghost -c "/usr/local/bin/ghost status -d /usr/local/www/yourblog.ext"
}
run_rc_command "$1"
Fix the permissions and enable the service. It'll come up on the next reboot.
# chmod 755 /usr/local/etc/rc.d/ghost
# service ghost enable
# service ghost status