An open API service indexing awesome lists of open source software.

https://github.com/xieyuheng/x-server

A website server that supports serving many websites using subdomain-based routing.
https://github.com/xieyuheng/x-server

subdomain-routing website-server

Last synced: 10 months ago
JSON representation

A website server that supports serving many websites using subdomain-based routing.

Awesome Lists containing this project

README

          

# X Server

A website server
that supports serving many websites
using subdomain-based routing.

## Install

Install it by the following command:

```sh
npm install -g @xieyuheng/x-server
```

The command line program is called `x-server`.

```
Commands:
help [name] Display help for a command
serve:website [path] Serve a website
serve:subdomain [path] Serve many websites using subdomain-based routing
```

## Docs

- [Serve one website](#serve-one-website)
- [Serve many websites](#serve-many-websites)
- [Config logger](#config-logger)
- [Use custom domain](#use-custom-domain)
- [Get free certificate](#get-free-certificate)
- [Use systemd to start service](#use-systemd-to-start-service)

### Serve one website

Use the `x-server serve:website` command to serve one website:

```sh
x-server serve:website
```

When serving a [single-page application (SPA)](https://en.wikipedia.org/wiki/Single-page_application),
we need to redirect all requests to `index.html`.

Example command for serving a SPA:

```sh
x-server serve:website \
--cors \
--redirect-not-found-to index.html \
--cache-control-pattern 'assets/**: max-age=31536000'
```

To serve a website using HTTPS, we need to provide TLS certificate.

Example command for serving a SPA using HTTPS:

```sh
x-server serve:website \
--cors \
--port 443 \
--redirect-not-found-to index.html \
--cache-control-pattern 'assets/**: max-age=31536000' \
--tls-cert \
--tls-key
```

It is unhandy to issue long command,
thus we also support using a `website.json` config file:

```sh
x-server serve:website /website.json
```

Where `/website.json` is:

```json
{
"server": {
"port": 443,
"tls": {
"cert": "",
"key": ""
}
},
"cors": true,
"redirectNotFoundTo": "index.html",
"cacheControlPatterns": {
"assets/**": "max-age=31536000"
}
}
```

### Serve many websites

The main use case of `x-server` is to
serve many websites in one directory,
using subdomain-based routing.

For example, I have a VPS machine,
where I put all my websites
in the `/websites` directory.

```
/websites/www
/websites/graphwind
/websites/inet
/websites/pomodoro
/websites/readonlylink
...
```

I bought a domain for my server -- say `example.com`,
and configured my DNS to resolve `example.com`
and `*.example.com` to my server.

I also created certificate files for my domain using `certbot`.

- About how to use `certbot`, please see
the ["Get free certificate"](#get-free-certificate) section.

I can use `x-server serve:subdomain` command to serve all of
the websites in `/websites` directory.

```sh
x-server serve:subdomain /websites \
--hostname example.com \
--port 443 \
--tls-cert /etc/letsencrypt/live/example.com/fullchain.pem \
--tls-key /etc/letsencrypt/live/example.com/privkey.pem
```

Then I can visit all my websites via subdomain of `example.com`.

```
https://www.example.com
https://graphwind.example.com
https://inet.example.com
https://pomodoro.example.com
https://readonlylink.example.com
...
```

If no subdomain is given in a request,
`www/` will be used as the default subdomain directory
(while no redirect will be done).

Thus the following websites have the same contents:

```
https://example.com
https://www.example.com
```

Instead of issuing long command,
we can also use a root `website.json` config file.

```sh
x-server serve:subdomain /websites/website.json
```

Where `/websites/website.json` is:

```json
{
"server": {
"hostname": "example.com",
"port": 443,
"tls": {
"cert": "/etc/letsencrypt/live/example.com/fullchain.pem",
"key": "/etc/letsencrypt/live/example.com/privkey.pem"
}
}
}
```

- When using `x-server serve:subdomain`,
the `server.hostname` option is required.

- And each website in `/websites` might have
it's own `website.json` config file.

### Config logger

We can config logger in `/websites/website.json`:

```json
{
...,
"logger": {
"name": "pretty-line",
"disableRequestLogging": true
}
}
```

The type of logger options are:

```ts
export type LoggerOptions = {
name: "json" | "silent" | "pretty" | "pretty-line"
disableRequestLogging?: boolean
}
```

The default logger options are:

```json
{
"name": "pretty-line",
"disableRequestLogging": false
}
```

### Use custom domain

When doing subdomain-based routing,
we can also support custom domain for a subdomain,
by adding a file in `.domain-map/` directory.

```
/websites/.domain-map//subdomain
```

Where the content of the file is the subdomain, for examples:

```
/websites/.domain-map/readonly.link/subdomain -- (content: readonlylink)
...
```

Then I can the following DNS ALIAS records to my custom domains:

- You can also use A record and IP addresses.

| Domain | Type | Value |
|---------------|-------|------------------------|
| readonly.link | ALIAS | readonlylink.example.com. |

Custom domain is only supported when TLS is enabled.
To provide TLS certificate for a custom domain,
add the following files:

```
/websites/.domain-map//cert
/websites/.domain-map//key
```

For example, the listing of `.domain-map/` is the following:

```
/websites/.domain-map/readonly.link/subdomain
/websites/.domain-map/readonly.link/cert
/websites/.domain-map/readonly.link/key
...
```

### Get free certificate

You can use `certbot` to get free certificate for your domains.

- [Certbot website](https://certbot.eff.org/instructions)
- [Certbot on archlinux wiki](https://wiki.archlinux.org/title/certbot)

After install `certbot`,
I prefer creating certificate via DNS TXT record,
using the following command:

```sh
sudo certbot certonly --manual --preferred-challenges dns
```

Then you can follow the prompt of `certbot`
to create the certificate files,
during which you will need to add TXT record
to the DNS record of your domain
to accomplish the challenge given by `certbot`.

After created the certificate files,
I use the follow command to copy them to my `.domain-map`:

```sh
sudo cat /etc/letsencrypt/live//fullchain.pem > /websites/.domain-map//cert
sudo cat /etc/letsencrypt/live//privkey.pem > /websites/.domain-map//key
```

### Use systemd to start service

On a Linux server, we can use `systemd` to start a service,
or enable a service to start whenever the server is booted.

Example service file `fidb-app-x-server.service`:

```
[Unit]
Description=example.com x-server
After=network.target

[Service]
ExecStart=/usr/local/bin/x-server serve:subdomain /websites/website.json
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

Install service:

```
sudo cp .service /etc/systemd/system/
```

Using service:

```
sudo systemctl start .service
sudo systemctl enable .service
sudo systemctl status .service
```

To view log:

```
journalctl -f -u .service
```

Reload systemd config files:

```
sudo systemctl daemon-reload
```

## Development

```sh
npm install # Install dependencies
npm run build # Compile `src/` to `lib/`
npm run build:watch # Watch the compilation
npm run format # Format the code
npm run test # Run test
npm run test:watch # Watch the testing
```

## License

[GPLv3](LICENSE)