# Using Fly.io and NGINX for Proxying Obsidian Publish

> How to use Fly.io and NGINX to proxy your Obsidian Publish site.

Source: https://curiouslychase.com/engineering/using-flyio-and-nginx-for-proxying-obsidian-publish/

> [!caution]
> This post is a work in progress and is mostly incomplete. If you'd like to see some movement on it, feel free to reach out on [LinkedIn](https://www.linkedin.com/in/curiouslychase/) or Discord 

As someone who likes to hack on internet things, I decided that I wanted to serve my Obsidian Publish site through Fly.io using NGINX.

This is an exhaustive walkthrough of how to configure and deploy an NGINX app server with Fly.io to serve an [Obsidian Publish](https://curiouslychase.com/posts/obsidian-publish/) site.

For this example, I'll be referring to my `server_name` and serving my site at `notes.curiouslychase.com`. Anywhere you see me reference `server_name`, make sure to replace `notes.curiouslychase.com` with your hostname.

# Prerequisites

This tutorial is for anyone who has knowledge of working with code. It doesn't have to be _strong_ knowledge, but you do need to be able to have some idea of how to use an editor and a terminal.

- Basic proficiency with a text editor ([VS Code](https://curiouslychase.com/posts/vs-code/), [Emacs](https://curiouslychase.com/engineering/emacs/), Vim, etc.)
- Basic proficiency with Linux/MacOS command line and terminal to use it ([VS Code](https://curiouslychase.com/posts/vs-code/) has an integrated terminal, but you can also use iTerm or Terminal on Mac. If you're on Linux, it depends on your distribution.)
- [Obsidian](https://curiouslychase.com/tools/obsidian/) Publish subscription 
- A Fly.io account
- A domain name (in this example, I'll be walking through configuration with [Namecheap](https://curiouslychase.com/tools/namecheap/))

# Goals
- Host your [Obsidian Publish](https://curiouslychase.com/posts/obsidian-publish/) site on your own domain
- Enhance your existing published site with metadata for your site

## Learning Goals
- What is a reverse proxy?

# What You'll Learn
- Setup a Fly.io app
- Create a configuration file to serve your Obsidian Publish site
- Add a way to add metadata to the page that is served
- Deploy a reverse proxy
- Setup a domain to point to the app
- Verify a static HTML response

# Setting up Fly.io to serve your Obsidian Publish site

## Setup a Fly.io App

Before setting up a fly.io app, you'll need to have an account. If you don't have one yet, you can visit their [Sign up page](https://fly.io/app/sign-up). Once you've created your account, it will ask you if you want to setup 

## Install `flyctl` (TODO)

## Create the `flyctl` app (TODO)

Run `flyctl create`

After running this command, you should now have a `fly.toml` in the directory you're working from.

This is the file that the command for `deploy` will use to provision and configure your app's resources

## Create the `nginx.conf` (TODO)

In your editor, create a file `nginx.conf`.

This is where all the configuration for _your site_ happens. NGINX uses this configuration to determine what to do when a request comes into your app. 

## Create the `Dockerfile` (TODO)

## Quick check-in

Fly.io apps are deployed via a terminal by using a `fly.toml` file ([Configuration as Code](https://curiouslychase.com/engineering/configuration-as-code/)) and a `Dockerfile`.

Before you deploy, here are the **3 files** you should have (_in the same directory_) and a recap of what they do:
- `fly.toml` - This is the file that the command for `deploy` will use to provision and configure your app's resources
- `Dockerfile` - Fly.io creates a container with this `Dockerfile` so that it can serve the container _as_ the app.
- `nginx.conf` - This is where all the magic for _your site_ happens. NGINX uses this configuration to determine what to do when a request comes into your app.

## Deploy your Fly.io app (TODO)

## Verify your work (TODO)

Now you should be able to visit the `Hostname` that you found in Your fly.io app overview.

In my case, it's `notes-curiouslychase.fly.dev`:

# Point your domain name at your Fly.io app

## Get IP Addresses from Fly.io (TODO)

## Add A record to point to IP Address (TODO)

## Provision certificates on Fly.io (TODO)

## Now you wait

One of the downsides to DNS is that you have to wait for a new record to propagate from your Domain Registrar to your computer.

That means you could be waiting anywhere from 5 minutes to 24 hours, so be patient!

One way to verify your changes are propagated is to visit [DNS Checker](https://dnschecker.org/#A) and check what IP addresses show. To do this:
- add the hostname you're using (in my case, notes.curiouslychase.com)
- make sure it says "A" in the select box for the DNS record type
- click **Search**

If all goes well, you should see a list of...
- location somewhere around the world
- IP address your site points to
- A checkmark 

The IP address should match the IP address of your Fly.io application. 

Here's an example of mine:

I have no idea why "Berkeley" has an ❌. If anyone is in Berkeley or has an idea of why, feel free to let me know on [LinkedIn](https://www.linkedin.com/in/curiouslychase/)!

# Wrapping Up (TODO)

# Notes

## Disable Port in Redirect

I noticed when I was adding `rewrite` rules (using `curl` to debug), that the location's `listen` port was included in the redirect URL.

In order to disable that, in my `nginx.conf`, I had to add the following:
```
port_in_redirect off;
```

## Don't forget to escape `+` on rewrite source

In order to use `rewrite` to redirect a path that changes in sites deployed with [Obsidian Publish](https://curiouslychase.com/posts/obsidian-publish/), you need to escape the `+` symbols. 

As an example, if I want to redirect `/MongoDB+Queries`, I need to escape with `\` in the source because it's using a [Regular Expression](https://curiouslychase.com/posts/regular-expression/). The destination does _not_ need the same treatment.

```
rewrite ^/MongoDB\+Queries$ /20+-+Notes/MongoDB permanent;
```

# Links

# Complete Files

## `fly.toml`
```toml

app = "notes-curiouslychase"

kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]
PARAMS = "--with-http_sub_module"

[experimental]

  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []

  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"
```

## `Dockerfile`

```dockerfile
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/nginx.conf
```

## `nginx.conf`

```nginx
resolver 8.8.8.8;

server {
	listen 8080;
	listen [::]:8080;

	server_name notes.curiouslychase.com;

	location / {
		if ($http_x_forwarded_proto = "http") {
			return 301 https://$server_name$request_uri;
		}

		set $site "https://publish.obsidian.md/serve?url=notes.curiouslychase.com";
		proxy_pass $site;
		proxy_ssl_protocols TLSv1.2;
		proxy_ssl_server_name on;

	}

}
```
