# How to host Worldwideportal for others to use
If you are a MUD admin and want to make it easy for your players to access the MUD over the web,
or if you want to host your own instance of Worldwideportal to access other MUDs, this guide is
for you.

No matter which option you take, you'll need either a Linux system of some form. This could be the same system you host your MUD on, or a different one if necessary. You could self-host, or use a cheap cloud instance (try Linode, Vultr, DigitalOcean etc..., or find a provider on Lowendbox). Mac or Windows users can either manually run a Linux VM (and be sure to forward the ports mentioned to it), or use Docker Desktop or similar container technology that automatically runs containers in a VM.

## First step: Pick an approach

Worldwideportal provides a few options for how you set it up, ranging from really quick and easy
options where everything is automated, to options that give you more control. Pick the option that
seems best for you.

Don't worry if you don't understand everything here - just default to the simplest option if you don't understand the details, and follow the steps.

* Simplest: Let Worldwideportal handle everything, including managing certificates, and expose its ports directly to the Internet. Run it in a container for one-line deployment. This requires that port 80 (the web port) and your main HTTPS port (443 recommended since it is the default) are not used for anything else - for example, that you are not also running a web server on the same system.
* Or: Provide Worldwideportal with a certificate you request externally. Notify it when the certificate is updated. Run it in a container for one-line deployment. Let Worldwideportal listen on the HTTPS port you want inbound connections from.
* Or: Run Worldwideportal from a container without enabling TLS (HTTPS), but set it up so it is only accesible locally. Then reverse proxy to it, and provide TLS offload (i.e. HTTPS) from a web server already running on your server.
* Or: Build Worldwideportal from source for complete flexibility and control, including the ability to apply your own custom patches to it.

## Option 1: Simple but less flexible installation

### Create a configuration file

Make a new directory - we'll call it `/etc/worldwideportal`, but you can put it wherever you like, on the system where Worldwideportal will run.

`sudo mkdir /etc/worldwideportal`

In that directory, save the following file template on your system as `worldwideportal.toml`:

```
# Your main port to listen on for accepted connections. This will usually be 443,
# which is the default https port, so people won't need to explicitly specify a
# port in the URL.
# Note: Using this template, you'll also accept connections on port 80. This is
# not configurable, as it needs to be port 80 for LetsEncrypt to generate a
# certificate.
listen_port = 443
# Accept connections on any address.
bind_address = "::"
# No need to change this path when using a container.
static_root = "/frontendstatic"
[tls]
# These will be automatically created and maintained.
# No need to change them when using the container.
private_key_file = "/config/privkey.pem"
certificate_chain_file = "/config/fullchain.pem"
[tls.acme]
# You must change this to a real email address that goes to you.
# It is use to sign up with LetsEncrypt. They will send you emails if something
# goes wrong and your certificate is about to expire.
# Worldwideportal will tell LetsEncrypt (or whatever other ACME provider) that you
# have accepted the subscriber agreement - see
# https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf and check you
# agree before proceeding.
contact_email = "youremail@example.org"
# No need to change this when using the container. Will be created for you.
acme_account_file = "/config/acme_account.json"
# This sets who will provide your certificate. If you are testing things,
# use staging - you won't get a certificate recognised by browsers, but there are
# laxer rate limits.
# Use the staging provider; comment out after getting it working.
acme_provider = "https://acme-staging-v02.api.letsencrypt.org/directory"
# Uncomment this instead for a real production certificate...
#acme_provider = "https://acme-v02.api.letsencrypt.org/directory"
renew_if_days_left = 30
[[muds]]
# This should match the DNS record that points at the machine you are running this on.
hostname = "your-mud-hostname.org"
# The hostname (can be IP address) and port to connect over telnet to your MUD.
# Since this will run in a container, you can't use localhost, but can use
# host.containers.internal (Docker: host.docker.internal) if need be.
upstream_mud = "example.org:1234"
# What to send to the MUD on connect before sending user data. You can leave it blank
# to send nothing. %i will be substituted for the real IP address of the user (
# to help you see the real IP and avoid abuse - but you'd have to configure your
# MUD to accept that). Use %n to send a newline.
banner_to_mud = ""
# banner_to_mud = "real_ip %i%n"
# This can be an empty file, or put code in it to customise Worldwideportal to your
# MUD. It is sent to the browser and run there.
startup_script_file = "/config/mymud.lua"
# This should at least include your hostname. You can use * as a wildcard.
allowed_origins = ["your-mud-hostname.org"]
```

Edit the file, following the instructions in the comments (lines starting with `#`) to customise it for
your MUD. Leave the acme_provider setting pointing at staging for now while you work on getting everything
working right - only change to production when you have staging working.

Create an empty Lua script, matching `startup_script_file`:
`touch /etc/worldwideportal/mymud.lua`

Set up DNS with your DNS provider (if you haven't already) to make the domain name
point to your system (i.e. create A/AAAA records).

Install Podman if it isn't already (or you can use Docker if you prefer it - just replace
podman with docker in the command you run to start the container).

On Debian / Ubuntu systems:
`sudo apt-get install podman`

On Centos / Fedora etc...
`sudo dnf -y install podman`

Check [here](https://podman.io/docs/installation#installing-on-linux) to install on other distros.

As a final step to podman setup, to make sure your container restarts on system boot, make sure you have run:
`sudo systemctl enable podman-restart`

Create a container to run your MUD with Docker use a line like this:

`sudo podman run --name worldwideportal --restart=always -v /etc/worldwideportal:/config -p 80:80 -p 443:443 quay.io/blasthavers/worldwideportal:latest /config/worldwideportal.toml`

(adjust the 443 to whatever port you are listening on if you want to require a port number).

Try connecting to Worldwideportal at `https://your-mud-hostname.org/` (adjusting the hostname; if you aren't using port 443, put the port in the URL like `https://your-mud-hostname.org:port/`). You will expect an error about a non-trusted certificate (since you used LetsEncrypt staging for now) - but not an error that you can't connect.

If you do experience other problems (e.g. because LetsEncrypt staging can't connect to your server using your hostname to verify the certificate, or you got the configuration wrong), you can diagnose the problem by checking the logs. When using podman, use `sudo journalctl -xe -t worldwideportal` to view the logs, which should tell you what is going wrong.

To switch to a certificate recognised by browsers, edit `/etc/worldwideportal/worldwideportal.toml` and uncomment (remove the `#` from the start of the line) the line `acme_provider = "https://acme-v02.api.letsencrypt.org/directory"`. Similarly, comment out (add a `#` to the start) the line mentioning acme-staging-v02. Then delete the old certificate / key / account file: `sudo rm /etc/worldwideportal/privkey.pem /etc/worldwideportal/fullchain.pem /etc/worldwideportal/acme_account.json`, and restart worldwideportal with `podman restart worldwideportal`.

Connect to it again to check that everything works.

## Option 2: Providing your own certificate

Follow option 1, except delete the entire section of `/etc/worldwideportal/worldwideportal.toml` starting at `[tls.acme]`.

Before starting the server, copy your PEM-formatted X.509 certificate (including the full chain of certificates) - colloquially called an SSL certificate - into `/etc/worldwideportal/fullchain.pem`. Copy the corresponding private key into `/etc/worldwideportal/privkey.pem`.

Whenever you rotate the certificate (e.g. from Certbot or similar), copy the new files over these files, and tell worldwideportal to reload its configuration with `kill -HUP $(pidof worldwideportal-server)` from your certificate renewal hook (or manually). This won't disconnect users who are connected.

## Option 3: Using a reverse proxy

Follow the instructions in option 1, but leave delete the `[tls]` and `[tls.acme]` sections. You probably want to change the default port from 443 to avoid confusion, since in this case `worldwideportal` will speak plain HTTP.

When you start your container, you'll probably want to give it a static local IP. Run `sudo podman network inspect podman` to find the subnet range for the default network (often `10.88.0.0/16`, meaning anything under `10.88`). Pick an unused address in the subnet, e.g. `10.88.143.12` if the subnet is `10.88.0.0/16`, and add `--ip 10.88.143.12` to the podman command when starting the container for the first time.

When you configure your server to proxy to Worldwideportal, note that there are two types of requests:

* Requests to GET static assets for Worldwideportal over normal HTTP.
* WebSocket requests to `/ws`.

Many reverse proxies need special configuration for WebSockets. e.g. for Apache Httpd mod_proxy, `ProxyPass "/ws" ws://10.88.143.12:1234/ws`. For nginx, you'll need something like:

```
location /ws/ {
    proxy_pass http://10.88.143.12:1234;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
```

## Option 4: Building from source

You can also build worldwideportal from source.

It has two parts: 
* The [backend server](https://git.blastmud.org/blasthavers/worldwideportal-server).
* The [frontend browser application](https://git.blastmud.org/blasthavers/worldwideportal) - served up by the backend server.

Both parts are in Rust, and you'll need [Trunk](https://trunkrs.dev/) to build the frontend.

### Check out the repositories

```
git clone https://git.blastmud.org/blasthavers/worldwideportal-server
git clone https://git.blastmud.org/blasthavers/worldwideportal
```

### Install Rustup and Cargo

Follow the instructions from [https://doc.rust-lang.org/cargo/getting-started/installation.html](https://doc.rust-lang.org/cargo/getting-started/installation.html).

The quickest option there is to run `curl https://sh.rustup.rs -sSf | sh`.

### Install trunk

`cargo install --locked trunk`

### Build worldwideportal-server

```
pushd worldwideportal-server
cargo build --release
popd
```

### Build worldwideportal

```
pushd worldwideportal
trunk build --release
popd
```

### Use the server

Your worldwideportal-server binary is available in `worldwideportal-server/target/release/worldwideportal-server`.

Run it by passing the configuration TOML as a command line argument.

The configuration file includes an option `static_root` which should point to the directory with the frontend in it.
The build commands above placed this in `worldwideportal/dist` - but configuring it as an absolute path is recommended.
