# ๐ Quickstart
After [installation](/start/install/), follow these steps to create and
validate a configuration, start the server, and verify its response.
## ๐งพ Before you start
The installed service listens on port 80 and uses
`/etc/Pingclair/Pingclairfile`. Stop it before testing to free its ports:
```bash
sudo pc service stop
```
```bash
mkdir -p ~/demo/public
cd ~/demo
echo '
hello from ~/demo/public
' > public/index.html
```
## 1. โ๏ธ Write a configuration
Create `~/demo/Pingclairfile`:
```caddyfile
{
admin 127.0.0.1:2019
}
http://localhost:8080 {
file_server ./public
}
```
Three details matter:
- The unnamed block at the top holds global options. `admin` opens the Admin
API, which `pingclair start`, `stop`, and `reload` use to reach the running
server.
- The `http://` scheme in the site address forces plaintext. Without it,
Pingclair treats `localhost` as a name, serves HTTPS with a certificate from
its own authority, and a plain HTTP client sees an empty reply
([HTTPS](/start/https/)).
- The `file_server` root is relative to the working directory.
## 2. โ
Validate before you run
```bash
pingclair validate
```
```text
โ
Configuration 'Pingclairfile' is valid!
```
`validate` reads `./Pingclairfile` by default and also detects `./Caddyfile`. It
compiles the configuration and applies semantic checks, such as whether
certificate paths exist. A configuration that fails validation does not run,
and the output prints the reason on the last line.
## 3. ๐งญ Inspect the compiled configuration
```bash
pingclair adapt --pretty
```
```text
{
"debug": false,
"servers": [
{
"name": "localhost",
"names": [
"localhost"
],
"listen": [
"[::]:8080"
],
```
The compiled JSON is the configuration used by the server. Check this output
when a directive behaves unexpectedly. To inspect formatting changes, run:
```bash
pingclair fmt --diff
```
`fmt` prints the canonical form, which uses one tab per indentation level.
## 4. ๐ Run it
In the foreground, where the log stays attached to your terminal:
```bash
pingclair run Pingclairfile
```
For local development, add `--watch` to reload the configuration after each
file change:
```bash
pingclair run --watch Pingclairfile
```
```text
โป๏ธ Configuration reloaded successfully
โ
Configuration reloaded completed successfully in 2.478622ms
```
To keep the server running after the shell exits, start it in the background:
```bash
pingclair start -c Pingclairfile
```
```text
โ
Pingclair started in the background (pid 4432)
```
`pingclair start`, `stop`, and `reload` reach the running server through the
Admin API, which is why the configuration above sets `admin`. `pingclair run`
does not need it.
## 5. ๐ Verify
```bash
curl -i http://localhost:8080/
```
`ETag` and `Last-Modified` mean the file server read the file from disk. The
body is `public/index.html`. To stop a background server:
```bash
pingclair stop
```
```text
โ
Pingclair stopped
```
## โก Servers in one command
Three subcommands run without a configuration file and are suitable for local
tests or temporary environments:
```bash
pingclair file-server --listen :8081 --root ./public
pingclair reverse-proxy --from :8082 --to 127.0.0.1:8081
pingclair respond --listen :8083 -s 200 -b "hello from respond"
```
Each prints its listener on startup:
```text
๐ Starting file server on :8081 serving ./public (browse: false)
๐ Starting reverse proxy: :8082 -> ["127.0.0.1:8081"]
Server address: [::]:8083
```
Every request to `:8082` is proxied to the file server on `:8081`, and `:8083`
answers with the body you passed. `respond` is for development only.
## ๐ Move it into the service
The service loads `/etc/Pingclair/Pingclairfile`. Copy the configuration there
to apply it when the service starts, including after a reboot:
```bash
sudo cp Pingclairfile /etc/Pingclair/Pingclairfile
sudo pingclair validate /etc/Pingclair/Pingclairfile
sudo pc service reload
curl -i http://localhost/
```
`pc service reload` requests a configuration reload by sending
`SIGUSR1`. `pingclair reload` reaches the same code through the Admin API and
reports the reload result, but it requires the `admin` global option.
`sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)"` sends the
signal directly, with no Admin API needed.
Validate first either way, and check the result afterwards. `systemctl reload`
reports only that the signal was delivered; the reload result โ applied, or
refused with a reason โ appears on the unit's status line and in the journal. A
refused reload leaves the previous configuration serving.
[Run it as a service](/start/service/#-what-a-reload-means) covers the details.
## โ ๏ธ Troubleshooting
- **`Address already in use`.** The installer's service still holds `:80`, or
another process holds your port. `sudo ss -ltnp | grep :80` names the owner;
`sudo pc service stop` frees the default one.
- **`Empty reply from server` on `http://localhost:8080`.** The request uses
plaintext HTTP with a TLS listener. Add the `http://` scheme to the site
address, or use `https://` and trust the internal certificate.
- **`Cannot reach admin API at 127.0.0.1:2019`.** The configuration has no
`admin` option, so nothing is listening for `pingclair stop` and
`pingclair reload`. Add it to the global options block, or stop the foreground
process with Ctrl-C.
- **`curl` does not complete a loopback request.** A system proxy may be
intercepting the request. Repeat it with `curl --noproxy '*'`.
- **Validation fails with `Unsupported feature`.** The directive is recognized
but not implemented, and the message names the alternative, as in
`encode br`: Brotli is not implemented for proxied responses, so the message
points at `encode zstd gzip`.
## ๐งญ Next steps
- [HTTPS](/start/https/): certificates for a public name, from Let's Encrypt or
the internal authority.
- [Run it as a service](/start/service/): the unit, its reload semantics, and
its logs.
- [Pingclairfile](/reference/pingclairfile/): the language itself, including
matchers, snippets, and imports.