---
title: Blog
---

[[_TOC_]]

# Tutorial

## How to write a new blog post in GitLab

The steps below describe how to create a new blog post directly via GitLab using
the Web IDE for users unfamiliar with the `git` command-line client.

Users comfortable with `git` are free to create and push a new branch to the
repository directly, without using the Web IDE. In this case a Merge Request
should still be created to allow the review process to occur.

### Enter the Web IDE

#### 1. Navigate to the GitLab blog project at https://gitlab.torproject.org/tpo/web/blog

  * We'll create a new branch in the repository, so your account will require
    `Developper` permissions in the project

  * If you're missing the permissions, please ask TPA. Opening a Merge Request
    from a personal fork will cause CI to fail to deploy the preview

#### 2. Click the `Web IDE` button just above the file listing

  * The GitLab Web IDE allows you to create a new commit right in your browser,
    without the `git` command-line client

### Edit the content file

#### 3. On the left column, click the `New Directory` icon

#### 4. Enter `content/blog/<blog-post-slug>`

  * `<blog-post-slug>` will constitute the URL part after
    `https://blog.torproject.org/` (also called the permalink)

#### 5. In the left column still, navigate to the new directory and open the drop-down menu to the right of the new directory item

#### 6. Click `New file` to create a new file in that directory

#### 7. Enter `contents.lr` as the new file name

#### 8. In the text editor which appears, draft the new blog post

  * Required fields are `title`, `author`, `pub_date`, `summary` and `body` and
    `categories` ([sample contents.lr](#sample-contentslr))

  * Markdown is accepted in `summary` and `body` fields

  * The `summary` field is only displayed in the sidebar and index pages, its
    content is not displayed on the blog post page

  * At least once category must be chosen from [the list](#list-of-categories)

  * You can preview the formatting of various Markdown elements
    [here](https://blog.torproject.org/markdown-demo/)
    ([source](https://gitlab.torproject.org/tpo/web/blog/-/blob/main/content/blog/markdown-demo/contents.lr))

### Upload images and/or attachments

#### 9. Upload the lead image and any other images or attachments in the same directory

  * The lead image must be uploaded as `lead.png`, `lead.jpg` or `lead.gif`

  * A default Tor logo image will be displayed if the lead image is omitted

  * Image widths should not exceed 1000 pixels

  * If you can, please [compress your PNG](#Compress) files using a tool such as
    `zopflipng`

  * Don't worry about uploading duplicate images from other posts, as they will
    be deduplicated in GitLab (just make sure not to modify them unless
    necessary)

### Create a new commit and review

#### 10. When finished drafting the new blog post, click `Commit..`

  * Look for a blue button in the lower-left corner

  * Ensure `Create a new branch` is selected and (optionally) enter a branch
    name in the field below (eg. `nov-2021-yec-post`)

  * Ensure `Start new merge request` is checked

#### 11. Click once more the `Commit` button

  * Prefix the Merge request title with `Draft:` to indicate the post is not yet
    ready to be merged

  * Within a few minutes, GitLab CI should build and upload the draft version
    online

  * Once the build is ready, a `View app` button should appear in the merge
    request: clicking this link will open a browser tab to the preview URL

#### 12. Add more commits if any changes or adjustments are needed

  * New commits on the branch will automatically trigger a new preview build and
    deployment

#### 13. Once the blog post is finalized, retitle the Merge request to remove the `Draft:` prefix

  * Once the merge request is reviewed and accepted by a project maintainer,
    a full project build will be triggered and deployed to
    https://blog-staging.torproject.org

  * If the staging build passes QA, a deployment to production must be
    triggered manually via the [Pipelines][] or [Environments][] project pages

[Pipelines]: https://gitlab.torproject.org/tpo/web/blog/-/pipelines
[Environments]: https://gitlab.torproject.org/tpo/web/blog/-/environments

### Comment topic

#### 14. When the blog post is published, visit the page with a javascript-enabled browser

  * This will trigger the Discourse forum to create a new topic with the contents
    of the blog post in the [News][] category.

  * Adjustments to the topic source HTML might be required, notably to allow the
    forum to display images correctly (known Discourse bug being worked on)

[News]: https://forum.torproject.net/c/news/11

# How-to

## Pager playbook

### Roll-back to pevious version

In case an undesirable change has been accidentally deployed to production, it's
possible to trigger a roll-back of the environment to the previous state. To do
this, navigate to the [Environments][] page, identify which version to roll-back
to and click the corresponding `Rollback environment` button in the left-most
column.

Please note that it's not possible to roll-back to an environment that was built
more than 1 week ago, because environments depend on build artifacts and those
are configured to expire after 1 week.

### Emergency modification

To modify the site in an emergency, it's possible to bypass GitLab completely and
edit the site HTML directly. The steps to do so are described here:

 1. Log-in to `static-gitlab-shim.torproject.org`
 2. `cd /srv/static-gitlab-shim/blog.torproject.org/public`
 3. Edit the website sources files directly, in-place
 4. Execute `sudo -u mirroradm static-update-component blog.torproject.org`

This will immediately deploy changes to the web mirrors.

Please note that using the technique, any changes made henceforth to the GitLab
project repository and deployed to production will overwrite these modifications.

## Disaster recovery

See [howto/static-component#disaster-recovery](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/static-component#disaster-recovery).

# Reference

## Installation

See [service/static-shim#adding-a-new-static-site-shim-in-puppet](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/service/static-shim#adding-a-new-static-site-shim-in-puppet).

## SLA

See [howto/static-component#sla](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/static-component#sla).

## Design

### Sample contents.lr

```
title: New Tor Blog
---
author: lavamind
---
pub_date: 2021-08-17
---
categories: announcements
---
summary:
The new Tor Blog is here!
---
body:
The new Tor Blog is here!

The new Tor Blog now runs on top of the Lektor static site generator.
```

### List of categories

In the process of migrating the blog from Drupal to Lektor, the number of tags
has been reduced to 20 (from over 970 in Drupal). For details about this work,
see tpo/web/blog#40008

The items below may now be used in the `categories` field:

| areas of work | topics         | operations    |
|---------------|----------------|---------------|
| circumvention | advocacy       | jobs          |
| network       | releases       | fundraising   |
| applications  | relays         | announcements |
| community     | human rights   |               |
| devops        | usability      |               |
| research      | reports        |               |
| metrics       | onion services |               |
|               | localization   |               |
|               | global south   |               |
|               | partners       |               |

When drafting a new blog post, a minimum of one category must be chosen, with a
suggested maximum of three.

### Compress PNG files

When care is taken to minimize the size of web assets, accessibility and
performance is improved, especially for visitors accessing the site from
low bandwidth connections or low-powered devices.

One method to achieve this goal is to use a tool to compress lossless PNG files
using `zopflipng`. The tool can be installed via `apt install zopfli`. To
compress a PNG image, the command may be invoked as such:

    zopflipng --filters=0me -m --prefix lead.png

This command will process the input file and save it as `zopfli_lead.png`. The
output message will indicate if the image size was reduced and if so, by what
percentage.

### Comments embedding

When a new blog post is published, a javascript snippet included on the page will
trigger the Discourse forum to create a new topic in the `News` category with the
contents of the new post. In turn, replies to the forum topic will appear
embedded below the blog post.

The configuration for this feature on the Discourse side is located in the Admin
section under **Customize** -> [Embedding][]

The key configuration here is **CSS selector for elements that are allowed in
embeds**. Without the appropriate CSS selectors listed here, some parts of the
blog post may not be imported correctly. There is no documentation of how this
parameter works, but through trial and error we figured out that selectors must
one or two levels "close" to the actual HTML elements that we need to appear in
the topic. In other words, specifying `main article.blog-post` as a selector and
hoping that all sub-elements will be imported in the topic doesn't work: the
sub-elements themselves must be targetted explicitely.

[Embedding]:https://forum.torproject.net/admin/customize/embedding

## Maintainer, users, and upstream

This website is maintained collaboratively between the TPA web team and the
community team. Users of this service are the general public.

## Monitoring and testing

For monitoring, see [howto/static-component#monitoring-and-testing](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/static-component#monitoring-and-testing).

There are no automated tests such as spellchecks or dead link checking for this
service. In case of malformed Lektor content files, the build job will fail.

## Logs and metrics

See [howto/static-component#logs-and-metrics](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/static-component#logs-and-metrics).

## Backups

Backups of this website exist both in the Bacula backups of the GitLab
server (as artifacts) and backups of the
`static-gitlab-shim.torproject.org` server. See the [static components
disaster recovery procedures](howto/static-component#disaster-recovery) for how to restore a site.

## Other documentation

 * [howto/static-component](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/howto/static-component)
 * [service/static-shim](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/service/static-shim)
 * [Lektor documentation](https://www.getlektor.com/docs/)

# Discussion

## Drupal to Lektor migration

The Tor Project runs a [blog](https://blog.torproject.org/) since 2007. It's used to provide an official source of news to the community regarding software releases, fundraising, events and general Tor Project updates. However, there are several outstanding [issues](https://gitlab.torproject.org/tpo/web/blog-trac/-/issues/33115) with the current site, including problems with comment moderation which are not easily fixed using Drupal:

 * Hosting the Drupal site at a third party is a significant expense
 * Technical maintenance of the blog is a challenge because upstream upgrades frequently cause breakage
 * Posts must be drafted with a clunky Javascript HTML editor instead of Markdown
 * Moderation is a chore for port authors, causing comments to sometimes linger in the moderation queue

It has been decided to migrate the site to a SSG (static site generator). This is currently listed as [Need to have](https://gitlab.torproject.org/tpo/tpa/team/-/wikis/roadmap/2021#need-to-have) in the 2021 TPA roadmap. (The option to fix the Drupal site was on the table for a short while, but is now abandoned.)

### Goals

We should migrate the site to an SSG as soon as possible.

#### Must have

 * Migration of existing blog post and events content (title, author, date, images)
 * Preservation of existing URLs (both aliases and node/\* paths)
 * RSS/Atom feed for blog posts and events
 * Ability to edit migrated content if required (posts and events)
 * Ability to comment blog posts (externally)

#### Nice to have

 * Migration and continued use of existing blog post tags
 * Straightforward content migration
 * Archive of existing blog post comments (see rationale [here](https://gitlab.torproject.org/tpo/web/blog-trac/-/issues/33115 at bottom))
 * Web-based "admin" interface
 * RSS/Atom feeds per-tag and per-author
 * [Styleguide](https://styleguide.torproject.org/) compliant template already exists ([Lektor](https://gitweb.torproject.org/project/web/template.git/), [Hugo](https://github.com/irl/torproject-hugo))

#### Non-goals

 * Author or admin-moderated comments

### Proposed solution

Migrate the site to Lektor, which is already used for https://www.torproject.org, and implement a Discourse instance for discussions, as a replacement for blog comments. This was the solution retained by @hiro for this project, as documented in https://gitlab.torproject.org/tpo/web/blog-trac/-/issues/33115.

There are two options for using Discourse as a blog comments platform:

#### Embedded

Using an embedded-Javascript snippet added in the site template, as documented [here](https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963). When a blog post page is opened, the Javascript loads the corresponding topic on the Discourse site. New topics are added to Discourse automatically when new posts are created.

 * Pro: comments are visible on the blog, no need to visit/open another site
 * Pro: comments can be posted to the Discourse topic directly from within the blog
 * Con: posting comments requires a Discourse account
 * Con: requires Javascript

#### RSS/Atom feed polling

A Discourse plugin can be configured to poll the blog website RSS/Atom feed at regular intervals and create new topics automatically when a new post is published. It's possible we can predict Discouse topic URLs so that Lektor can generate the required link in the template and insert it at the bottom of blog posts (eg. a "Click here to join the discussion"-type link)

 * Pro: no Javascript required on the blog
 * Pro: comments not visible directly on the blog
 * Con: comments not visible directly on the blog

### Alternatives considered

 * **Hugo** is another friendly SSG, and a [Tor styleguide](https://github.com/irl/torproject-hugo) has been made for it, however its preferable to avoid using different web stacks unless there's a compelling reason for it. There's only one known [Drupal migration script](https://gohugo.io/tools/migrations/#drupal) by it appears to have been created for Drupal 7 and seems unmaintained. In any case it's "assembly required" which isn't much different from hacking a quick script to migrate to Lektor instead.
 * **Discourse** might also be an option to completely replace the blog: we could configure https://blog.torproject.org to show content from a specific topic on Discourse. The challenge is that importing content is not as straightforward compared to a SSG where we just need to write text files. Maintaining existing URLs could also be a challenge and would require some form of redirect mapping on `blog.torproject.org`. We would also lose the flexibility to add standalone pages or other forms of content on the blog, ~~such as a calendar view of events~~ [event calendar plugin](https://meta.discourse.org/t/discourse-calendar/97376). ([example](https://www.daemon.com.au/))
