When searching online, you may find that NAT rules end with `-> ($ext_if)`, but that will include all aliases, which will make the NAT-ting most likely not behave as intended. You want to NAT on the external IP ( `-> $ext_if_ip` ).
### Base Jail ##### (For creating quickly update-able thin jails later) It's pretty simple to create the base jail. This will download a fresh base install, basically. ```sh bastille bootstrap 12.1-RELEASE ``` You'll want to occasionally update this with: ```sh bastille bootstrap 12.1-RELEASE update ``` We should now be ready to create jails. (On a 25G instance, `ZFS list` currently reflects there is 16.8G remaining space.) ### Initial Jail Creation More foreshadowing! `Usage: bastille create [option] name release ip [interface].` `Options` - Empty, Thick, VNET (none of these) `Interface` - vtnet (no!), bastille0 (yes, but implied) ```sh bastille create caddy_jail 12.1-RELEASE 10.101.10.100 ``` ```sh bastille create bs_jail 12.1-RELEASE 10.101.10.110 ``` ```sh bastille create bw_jail 12.1-RELEASE 10.101.10.120 ``` ```sh bastille create thelounge_jail 12.1-RELEASE 10.101.10.130 ``` ```sh bastille create website_jail 12.1-RELEASE 10.101.10.140 ``` And after creating five thin jails, the remaining space is still 16.8G. Yay, ZFS, again! ### Quick quality of life improvement in the jails Let's create a `.cshrc` for copying into the jails. It's the same as the regular one, but it uses different prompt colors. ```sh # $FreeBSD: releng/12.1/bin/csh/dot.cshrc 338374 2018-08-29 16:59:19Z brd $ # # .cshrc - csh resource script, read at beginning of execution by each shell # # see also csh(1), environ(7). # more examples available at /usr/share/examples/csh/ # alias h history 25 alias j jobs -l alias la ls -aF alias lf ls -FA alias ll ls -lA # A righteous umask umask 22 set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) setenv EDITOR vi setenv PAGER less setenv BLOCKSIZE K if ($?prompt) then # An interactive shell -- set some stuff up # colors for prompt (0 for regular and 1 for bold, or use %B%b for bold) set red="%{\033[0;31m%}" set green="%{\033[0;32m%}" set yellow="%{\033[0;33m%}" set blue="%{\033[0;34m%}" set magenta="%{\033[0;35m%}" set cyan="%{\033[0;36m%}" set white="%{\033[0;37m%}" set end="%{\033[0m%}" # This is needed at the end... :( # prompt vars set name = "${red}%B%n%b${end}" set host = "${red}%m${end}" set dir = "${cyan}%~${end}" set prompt = "[${name}@${host}:${dir}]%# " #set prompt = "%N@%m:%~ %# " set promptchars = "%#" set complete = enhance set filec set history = 1000 set savehist = (1000 merge) set autolist = ambiguous # Use history to aid expansion set autoexpand set autorehash set mail = (/var/mail/$USER) if ( $?tcsh ) then bindkey "^W" backward-delete-word bindkey -k up history-search-backward bindkey -k down history-search-forward endif # Clean up... unset red green yellow blue magenta cyan white end unset name host dir endif # color in autocomplete set color # color in ls alias ls ls -G # LS colors, made with https://geoff.greer.fm/lscolors/ setenv LSCOLORS gxfxcxdxbxegedabagacad ``` Then `mv` each jail's `.cshrc` as `.cshrc.orig`, and then `cp` the `.cshrc.jail` as each jails's new `/root/root/.cshrc`. See below for a script to do this quickly and easily. ## Other Bits It may be a good time to reboot the server. You've made several changes to the system, and you'll want to make sure they stuck and are working correctly. Changes to `/etc/pf.conf` require `pfctl -f /etc/pf.conf`\*\*. Changes to `/etc/rc.conf` require... something. Changing the `.cshrc` requires sourcing it or logging in fresh. The jails need to be started. Rebooting will do all this, including starting the jails. \*\* Just make sure you at least have already run `pfctl -vnf /etc/pf.conf` to make sure the config works. ## Common Initial Jail Setup The beginning steps are mostly the same across the jails. Before jumping in, if you haven't already, remember to `mv` the jail's `.cshrc` as `.cshrc.orig`, and then `cp` the host's `.cshrc.jail` as the jails's new `/root/root/.cshrc`. In fact, here's a script (that magically worked perfectly the first time I ran it), that I just saved in `/usr/local/scripts`. ```sh #!/bin/sh # Copies custom .cshrc from /root/.cshrc.jail in place of the # jail's default .cshrc, and renames the default as .cshrc.orig. # Exit script if error (non-zero return code) set -e # check for a single arg (the name of the jail) if [ "$#" -ne 1 ]; then echo "Usage: $0 JAIL_NAME" >&2 exit 1 fi # Variables to be used jail_name="$1" jails_dir="/usr/local/bastille/jails" jail_dir="${jails_dir}/${jail_name}/root/root" # check that the directory exists if [ ! -d "${jail_dir}" ]; then echo "Directory ${jail_dir} doesn't exist." >&2 exit 1 fi # check that the original .cshrc exists if [ ! -f "${jail_dir}/.cshrc" ]; then echo "File ${jail_dir}/.cshrc doesn't exist." >&2 exit 1 fi # check that the custom .cshrc exists if [ ! -f "/root/.cshrc.jail" ]; then echo "Custom .cshrc.jail in /root doesn't exist." >&2 exit 1 fi mv ${jail_dir}/.cshrc ${jail_dir}/.cshrc.orig cp /root/.cshrc.jail ${jail_dir}/.cshrc # Write to log briefly what happened echo "Added custom .cshrc to ${jail_name}." exit 0 ``` Don't forget to `chmod +x` it. Then you just run it with `/usr/local/scripts/custom_cshrc.shUpdates cannot be installed when the system securelevel (`jail.conf` setting) is greater than zero.
So we must first edit `.../jails/$jail/jail.conf` to change `securelevel` from `2` to `0`, then restart the jail. Then the updating can happen. ```sh bastille cmd $jail freebsd-update fetch install bastille pkg $jail update bastille pkg $jail upgrade -y ```(Most everything below is performed ***outside*** the jail.)
Install some initial necessary packages. ```sh bastille pkg bs_jail install -y vim-console git sudo bash ``` ## Advanced Prep (nullfs) ##### (Relocate database outside the jail) If we ever have a problem with this jail and need to blow it away, it would be nice for the database to live on. We can do this! In fact, this is probably one of several steps that could/should be taken to ensure data not specific to the jail is saved outside the jail. First, let's create a directory for it the db to live. You can `mkdir -p` this step. I have ZFS and `/zroot/data` already, so it'll be: ```sh zfs create -o compress=lz4 -o atime=off zroot/data/dbs/ ``` ```sh zfs create -o compress=lz4 -o atime=off zroot/data/dbs/bookstack ``` MariaDB (MySQL) stores the database in `/var/db/mysql`. In fact, it probably would store multiple databases in there if we were using it for something else in the jail. Luckily, we're not. So there's our directory where we'll mount the new directory. In order to get a `/var/db/mysql` in the first place, `mysql` needs to be installed, so we'll do that now. ```sh bastille pkg bs_jail install -y mariadb102-client mariadb102-server ```As mentioned on a prior page, newer packages for `mariadb` seem to behave differently, so parts of this tutorial related to `mariadb` may need to be adjusted.
I'm leaving myself (and whoever else) a possible hint. A newer `mysql` has a different syntax. The following link talks about it midway down the page: [https://arstechnica.com/gadgets/2020/05/caddy-offers-tls-https-and-more-in-one-dependency-free-go-web-server/](https://arstechnica.com/gadgets/2020/05/caddy-offers-tls-https-and-more-in-one-dependency-free-go-web-server/) ... I suspect there's more to it though...
The user and group that own the BookStack db are both `88` (which is the mysql user and group, which you can see in the `stdout` from the previous command). We've gotta match that, and the permissions. ```sh cd /usr/local/data/dbs/ ``` ```sh chown 88:88 bookstack/ ``` Next double check that the folder `/var/db/mysql` exists. It should. If it does, proceed with: ```sh bastille stop bs_jail ``` Now it's time to set up the `fstab`. In the case of bastille, it's in `/usr/local/bastille/jails/$NAME`. For a thin jail, there will already be a line in the `fstab`, so this can be pasted in prior to it, or after, or just the relevant row. ```sh # Device Mountpoint FStype Options Dump Pass# /usr/local/data/dbs/bookstack /usr/local/bastille/jails/bs_jail/root/var/db/mysql nullfs rw,late 0 0 ``` While the jail is stopped, we need to ensure `mysql` (`mariadb`) has the powers is needs. ```sh echo 'allow.raw_sockets = "1";' >> /usr/local/bastille/jails/bs_jail/jail.conf ``` Now you can restart the jail and finish the setup. ```sh bastille start bs_jail ``` ## Install PHP Install PHP, as well as the necessary PHP extensions. ```sh bastille pkg bs_jail install -y php72 php72-mbstring php72-tokenizer php72-pdo php72-pdo_mysql \ php72-openssl php72-hash php72-json php72-phar php72-filter php72-zlib php72-dom \ php72-xml php72-xmlwriter php72-xmlreader php72-pecl-imagick php72-curl php72-session \ php72-ctype php72-iconv php72-gd php72-simplexml php72-zip php72-filter php72-tokenizer \ php72-calendar php72-fileinfo php72-intl php72-mysqli php72-phar php72-opcache php72-tidy ``` I guess we can check the version. ```sh bastille cmd bs_jail php --version ``` Soft-link `php.ini-production` to `php.ini`. ```sh bastille cmd bs_jail ln -s /usr/local/etc/php.ini-production /usr/local/etc/php.ini ``` Enable and start PHP-FPM. ```sh bastille sysrc bs_jail php_fpm_enable=yes ``` ```sh bastille service bs_jail php-fpm start ``` ## Install MariaDB Install MariaDB. (Skip this one step if you already ran this command in anticipation of nullfs-mounting the db folder.) ```sh bastille pkg bs_jail install -y mariadb102-client mariadb102-server ``` Might as well check the version. ```sh bastille cmd bs_jail mysql --version ``` Enable and start MariaDB. ```sh bastille sysrc bs_jail mysql_enable="yes" ``` ```sh bastille service bs_jail mysql-server start ``` Check if it's running, because we might have permissions issues or something: ```sh bastille service bs_jail mysql-server status ```If there's an issue, one possibility could be the inability to write to `/tmp`. A `bastille cmd bs_jail chmod 1777 /tmp` would solve that. But after `mariadb102`, there seems to be some other issue that I haven't figured out yet.
Assuming we're up and running, let's move on. #### Get MariaDB ready Run the secure installation executable to lock things down. Note your root password you create. ```sh bastille cmd bs_jail mysql_secure_installation ``` Log into MariaDB as the root user. ```sh bastille cmd bs_jail mysql -u root -p ``` Create a database (or use an existing name, if you'll be importing, which I will). ```sql CREATE DATABASE dbname; # substitute with your choice of name, though it does not matter if creating new GRANT ALL ON dbname.* TO 'username' IDENTIFIED BY 'password'; # substitute any user and pass FLUSH PRIVILEGES; exit; ``` ## Install Nginx Install Nginx. ```sh bastille pkg bs_jail install -y nginx ``` Check the version. ```sh bastille cmd bs_jail nginx -v ``` Enable and start Nginx. ```sh bastille sysrc bs_jail nginx_enable=yes ``` ```sh bastille service bs_jail nginx start ``` Set up Nginx for BookStack. ```sh bastille cmd bs_jail vim /usr/local/etc/nginx/bookstack.conf ``` And we'll add: ```nginx server { listen 80; # listen [::]:80; # you may need to comment this out server_name bookstack.mydomain.tld; # substitute hostname.domain root /usr/local/www/bookstack/public; index index.php index.html; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; include fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; } } ``` Now we need to include `bookstack.conf` in the main `nginx.conf` file. ```sh bastille cmd bs_jail vim /usr/local/etc/nginx/nginx.conf ``` And add the following line to the `http``{}` block. ```nginx include bookstack.conf; ``` Test the Nginx configuration changes. ```sh bastille cmd bs_jail nginx -t ``` Good? Then reload Nginx. ```sh bastille service bs_jail nginx reload ``` ## Install Composer Install Composer by running the script on their website. Note the final step is not on their website. Go to their website for line 2 below: [https://getcomposer.org/download](https://getcomposer.org/download). The remaining steps are the same (plus line 5).This is going into the `bs_jail` console again briefly!
Substitute with the user you just created (and whose shell you're in now).
Run the composer install command from the `/usr/local/www/bookstack` directory. ```sh composer install ``` Copy the `.env.example` file to `.env` and populate it with your own database (and mail details?). ```sh cp .env.example .env ``` ```sh vim .env ``` You can generally get away with just changing the db name, db user, and db password (per MariaDB steps above). You may need to put the user and password in double quotes. Come back to this step if `php artisan migrate` says `access denied`. If importing a database, be sure to use that `db` name. For a public web server, be sure to update APP\_URL as well. Optional: Ensure that the `storage`, `bootstrap/cache` and `public/uploads` folders are writable by the web server. (Prob can ignore given we've got a `chown` incoming.) In the application root (where you should already be), run the following command. ```sh php artisan key:generate ``` ## Finish up! To update the database: ```sh php artisan migrate ``` If there was an error here, fix the problem, then run the following, and then jump back up three steps (to the .`env` file). ```sh php artisan config:clear php artisan cache:clear ``` Change ownership of the `/usr/local/www/bookstack` directory to `www`. ```sh sudo chown -R www:www /usr/local/www/bookstack ``` You can now login using the default admin details `admin@admin.com` with a password of `password` (or, if you've restored a db, then you can log in with those credentials). It is recommended to change these details directly after your first login. Create your user account as an admin user, log in with it, and then disable the default admin user. ## Are We Really Done? As things stand, the BookStack webserver is listening on the jail's internal IP on port 80 (http). I would not recommend setting up `pf` to redirect http traffic to the jail. The jail will be waiting and ready when we can access it securely. We'll do that next in our second... err... third jail. We'll create a simple website in the second jail. Plus it'll buy time for the following... Also! In our initial legwork of getting the server set up, we touched on DNS records. Well, now is a good time (actually, these records don't seem to instantaneously populate, so *before* now would have been better) to create a CNAME record. Over in NameCheap, the 'hostname' is "bookstack", or "bs", or whatever you want... "docs"? ... and "mydomain.tld" is the 'value', and save, and you're done. ## Bonus At the time of writing this, BookStack has not implemented a change requested by users (and even submitted). But it works! One notable item missing from BookStack is the ability to go to the next or previous pages. Well, if you add the following script to the custom header settings, it'll insert this into the `` of the html, and bam, buttons. The one thing you'll want to do is set your own `rgb` numbers in the two `.bnav-page-button:hover` CSS items, so you'll get whatever color you want, rather than the red that is currently used. Check out the relevant PR for more info. https://github.com/BookStackApp/BookStack/issues/1381 ```JavaScript ``` ## Bonus #2: Updating According to BookStack site, this can be done very quickly in a single line. We'll try it. ```sh git pull origin release && composer install --no-dev && php artisan migrate ``` It works! It warns you that you're doing this migration in production, and you say 'yes' and it's done. ## References [https://www.vultr.com/docs/how-to-install-bookstack-on-freebsd-12](https://www.vultr.com/docs/how-to-install-bookstack-on-freebsd-12) Updating: https://www.bookstackapp.com/docs/admin/updates/ I skipped a few things, but it should work as I describe. # Website Jail Before this, I can't think of a time where I edited or wrote html. I can remember creating a basic `index.php` as a test for nginx and/or apache a couple times while tinkering with Nextcloud, but that might be it. Accordingly, this will be a very basic start of a very simple website. I maybe look forward to doing "cool" complicated stuff in the future, but for now we'll have close to nothing on it. I'm creating the web page because I figure that I might as well have a landing page for the domain itself, but I'm more interested in setting up the reverse proxy work for the subdomains. To set the expectations properly, the goal is to create an `html` file that renders in a browser by visiting `mydomain.tld`. We'll not be worrying about TLS/https (because `caddy` will eventually do that for us). We'll simply install a web server, create the `html` file, port forward (`rdr`) in `PF` to the jail, and visit in the browser. Someone who's done this a couple times - even if they're documenting it - might be be done in under two minutes. It took me more than two minutes. ## Prep Run the `custom_cshrc.sh` you created in `/usr/local/scripts` to put a custom `.cshrc` file in the jail. Remember, the script just takes the jail name as its only argument. If desired, adjust the date and time with `tzsetup` or `bastille cmd website_jail tzsetup`. ## Web Server We'll keep it simple and consistent (i.e., BookStack is served by `nginx`), so we'll install `nginx`. ```sh bastille pkg website_jail install -y nginx vim-console ``` And then we'll enable it and start it. ```sh bastille sysrc website_jail nginx_enable="YES" ``` ```sh bastille service website_jail nginx start ``` We'll configure it in a moment. ## Internet Content That sure is a fancy title for a bare `html` file. Let's just hop into the jail console for a few minutes. ```sh bastille console website_jail ``` And we'll head to the usual FreeBSD spot, create a website directory, and then file. ```sh cd /usr/local/www ``` ```sh mkdir mydomain.tld && cd mydomain.tld ``` ```sh vim index.html ``` And we will create our initial homepage. ```htmlHow exciting.
Be sure to check out all the great related services. Links coming soon...
``` ## Configuration Now we can create our configuration in `nginx` so it knows how to listen and what content to serve. ```sh vim /usr/local/etc/nginx/nginx.conf ``` In theory, all we have to do is change `server_name localhost` to `server_name mydomain.tld www.mydomain.tld` and change `root /usr/local/www/nginx` to `root /usr/local/www/mydomain.tld`. With any luck, we can reload `nginx` and be ready to test (almost). Before moving forward, `exit` out of the jail console. First we test the config (even though the test is built into the reload). ```sh bastille cmd website_jail nginx -t ``` If successful, we perform the reload. ```sh bastille service website_jail nginx reload ``` ## Testing It Out You'll need the jail's IP for this, which you can get from `bastille list`. Then there needs to be a redirect rule in `PF`, which is basically port forwarding. There's an example already in `/etc/pf.conf`, so it just needs to be uncommented, and updated with the website jail's internal IP. ```sh # the macro website_ip = "10.101.10.140" # the port forward rdr pass inet proto tcp from any to any port {80, 443} -> $website_ip ``` And it needs to be tested with: ```sh pfctl -vnf /etc/pf.conf ``` ##### Hiccup NameCheap.com provides a default CNAME record that redirects my internet traffic to their "parking page" and I hadn't deleted that yet, so I had to wait on it to die. Visiting the IP address does successfully display the webpage, but it would have been nice to see DNS do what it's supposed to too. Of course, it worked via hostname eventually. #### Last Step Remove those rules from `pf` and force reload `pf`. We will be using `https` in no time flat after the next jail is up.