Wordpress -> Frog

:: communication, web

After thirteen years with Wordpress, I decided to switch to static site generation for this blog. As a Racket programmer, Frog was a natural choice. This post highlights some of the lessons I learned in the process. I’m running MacOS locally and deploying to Ubuntu Linux.

Tidying Up

I took the opportunity to clean out some cruft, so I only moved a subset of posts over from the old blog, and some of the posts were elided.

Frog Installation

Installing Frog and Python (for syntax highlighting) was straightforward from the quick start guide.

Modify frog.rkt

The Wordpress permalink is slightly different than the default Frog permalink, so I set the current-permalink parameter to match the Wordpress version. Also, the default executable name for Python in Frog is python, and this needs to be changed to python3. Here is my resulting frog.rkt file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#lang frog/config

;; Called early when Frog launches. Use this to set parameters defined
;; in frog/params.
(define/contract (init)
  (-> any)
  (current-scheme/host "https://blog.lojic.com")
  (current-permalink "/{year}/{month}/{day}/{title}.html") ; Match Wordpress
  (current-title "Lojic Technologies")
  (current-author "Brian Adkins"))

;; Called once per post and non-post page, on the contents.
(define/contract (enhance-body xs)
  (-> (listof xexpr/c) (listof xexpr/c))
  ;; Here we pass the xexprs through a series of functions.
  (~> xs
      (syntax-highlight #:python-executable "python3"
                        #:line-numbers? #t
                        #:css-class "source")
      (auto-embed-tweets #:parents? #t)
      (add-racket-doc-links #:code? #t #:prose? #f)))

;; Called from `raco frog --clean`.
(define/contract (clean)
  (-> any)
  (void))

Syntax Highlighting

Once Python3 was installed, and frog.rkt modified as above, syntax highlighting just worked. For example, to highlight Racket code, specify the language after the opening triple backticks:

    ```racket
    #lang racket

    (define (fac n)
      (if (< n 2)
        1
        (* n (fac (sub1 n)))))
    ```

results in:

1
2
3
4
5
6
#lang racket

(define (fac n)
  (if (< n 2)
      1
      (* n (fac (sub1 n)))))

Embedding Youtube Videos

I will likely write some Racket code to make embedding Youtube videos easier, but for now it’s sufficient to click on the “share” link for the video and choose “Embed”. Simply copy the <iframe>...</iframe> code directly to the post. You may want to edit width and height I like 600 x 338:

<iframe width="600" height="338" src="https://www.youtube.com/embed/VgMwkxz0aBw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

results in:



Nginx Configuration

I needed to create an nginx configuration to accomplish the following:

Configure SSL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
server {
  listen 443 ssl;
  # ...
  ssl_certificate      /.../blog.lojic.com.crt;
  ssl_certificate_key  /.../blog.lojic.com.key;
  ssl_session_timeout  5m;
  ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  ssl_prefer_server_ciphers   on;
  ssl_session_cache shared:SSL:10m;
}

Force the use of SSL

The nginx docs say to use return instead of a rewrite rule for this:

1
2
3
4
5
server {
  listen 80;
  server_name blog.lojic.com;
  return 301 https://blog.lojic.com$request_uri;
}

My Wordpress URLs look like https://blog.lojic.com/2020/11/22/my-post-title/ but with Frog, the trailing / will be replaced with .html e.g. https://blog.lojic.com/2020/11/22/my-post-title.html. The following rewrite rule takes care of this:

1
2
3
server {
  rewrite "^(/\d{4}/\d{2}/\d{2}/[-A-Za-z0-9]+)/?$" $1.html permanent;
}

Rewrite the RSS feed URL

1
2
3
server {
  rewrite ^/feed/$ /feeds/all.rss.xml permanent;
}

Handle old path vs. new sub-domain URLs

In the past, I hosted my blog on the website using a path e.g. https://lojic.com/blog/2020/11/22/my-post-title.html to convert this to the sub-domain URL, I added the following config on my lojic.com site configuration since the requests would be going to lojic.com instead of blog.lojic.com:

rewrite ^/blog(.*)$ https://blog.lojic.com/$1 permanent;

nginx configuration file

Here is the resulting nginx configuration for the blog:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server {
  listen 80;
  server_name blog.lojic.com;
  return 301 https://blog.lojic.com$request_uri;
}

server {
  listen 443 ssl;
  server_name blog.lojic.com;
  root /home/deploy/sites/lojic-blog;
  index index.html;

  # Direct posts I excluded from new site to main page 11/23/2020
  rewrite ^/2007/08/27/greasemonkey-script-for-netflix-half-star-ratings https://blog.lojic.com;
  rewrite ^/2008/01/05/learning-logo-part-one https://blog.lojic.com;
  rewrite ^/2009/03/10/tarski-wordpress-theme https://blog.lojic.com;
  rewrite ^/2009/05/06/learning-logo-part-2 https://blog.lojic.com;
  rewrite ^/2009/06/28/learning-logo-part-3 https://blog.lojic.com;
  rewrite ^/2009/07/26/learning-logo-part-4 https://blog.lojic.com;
  rewrite ^/2009/03/11/retrieve-sunrise-sunset-twilight-in-ruby https://blog.lojic.com;
  rewrite ^/2009/05/02/programming-in-standard-ml-part-1 https://blog.lojic.com;
  rewrite ^/2009/05/02/programming-in-standard-ml-part-2 https://blog.lojic.com;
  rewrite ^/2009/08/15/programming-in-standard-ml-part-3 https://blog.lojic.com;
  rewrite ^/2009/08/29/daniel-weinreb-re-lisp-use-at-ita https://blog.lojic.com;
  # End exclusion rewrites

  rewrite ^/feed/?$ /feeds/all.rss.xml permanent;  
  rewrite ^/2007/04/22/pandoracom(.*) /2007/04/22/pandora-com$1 permanent;
  rewrite ^/2008/09/03/ubuntu-804-linux-wake-on-lan https://blog.lojic.com/2008/09/03/ubuntu-linux-8-04-wake-on-lan.html;
  rewrite ^/2009/07/22/trifuncorg https://blog.lojic.com/2009/07/22/trifunc-org.html;
  rewrite "^(/\d{4}/\d{2}/\d{2}/[-A-Za-z0-9]+)/?$" $1.html permanent;

  ssl_certificate      /.../blog.lojic.com.crt;
  ssl_certificate_key  /.../blog.lojic.com.key;

  ssl_session_timeout  5m;

  ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  ssl_prefer_server_ciphers   on;
  ssl_session_cache shared:SSL:10m;
}