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.
- Host: GitHub
- URL: https://github.com/xieyuheng/x-server
- Owner: xieyuheng
- License: gpl-3.0
- Created: 2023-09-13T17:48:42.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2025-07-20T06:30:07.000Z (11 months ago)
- Last Synced: 2025-08-16T05:27:44.489Z (10 months ago)
- Topics: subdomain-routing, website-server
- Language: TypeScript
- Homepage:
- Size: 549 KB
- Stars: 23
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE-OF-CONDUCT.md
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)