First Steps#

This walkthrough takes a freshly installed Angie from the package's welcome page to a server that hosts files, forwards requests to an application, serves both over HTTPS with certificates it obtains by itself, and reports its own statistics. If you already run nginx, migrate its configuration instead of rebuilding it by hand.

Each step extends the file the previous one leaves behind, so work through them in order. Only the HTTPS step is optional: it is the one step that needs a public domain name, and nothing after it depends on it.

You need Angie installed from a package on a systemd-based Linux and an account that can use sudo. On Alpine and FreeBSD, the installation page gives the service commands to use in place of systemctl.

Checking the Installation#

Confirm the installed version:

$ angie -v
Angie version: Angie/1.12.1

Start the service and request the default page:

$ sudo systemctl start angie
$ curl -I localhost
HTTP/1.1 200 OK
Server: Angie/1.12.1
...

The response comes from the welcome-page server that the package ships; the next step shows where it is defined.

Configuration changes are applied with a reload, not a restart: the master process re-reads the configuration and starts new worker processes, while the old workers finish the requests they are serving before exiting. For the full set of start, stop, reload, and log-rotation commands, the signals behind them, and the command-line parameters, see Runtime Control.

Configuration Layout#

The main configuration file is angie.conf; its location is compiled into the binary:

$ angie -V 2>&1 | tr ' ' '\n' | grep conf-path
--conf-path=/etc/angie/angie.conf

The file is organized into contexts — blocks that group the directives belonging to one kind of traffic:

  • events — general connection processing

  • http — HTTP traffic

  • mail — mail traffic

  • stream — TCP and UDP traffic

Files under /etc/angie/http.d/ are included inside http, so they hold server blocks and http-level directives. A server block describes one virtual server, and a location block inside it describes how to handle one set of request URIs.

The welcome page comes from /etc/angie/http.d/default.conf, the only server the package defines. This walkthrough replaces that file and leaves angie.conf as installed.

Inheritance between contexts, the syntax rules, and the size and time units used by directive parameters are covered in Configuration Files.

Serving Static Files#

Start with files on disk. Create two directories with one file each; the contents name the directory, so a response shows where the file came from:

$ sudo mkdir -p /data/www /data/images
$ echo 'Hello from /data/www' | sudo tee /data/www/index.html
Hello from /data/www
$ echo 'Hello from /data/images' | sudo tee /data/images/example.png
Hello from /data/images

The second file only stands in for an image; a real PNG behaves the same.

Replace the contents of /etc/angie/http.d/default.conf with:

/etc/angie/http.d/default.conf#
server {
    listen 80;

    location / {
        root /data/www;
    }

    location /images/ {
        root /data;
    }
}

Test the configuration and reload:

$ sudo angie -t && sudo systemctl reload angie

Both files are now reachable, and a missing one gives a 404:

$ curl localhost/index.html
Hello from /data/www
$ curl localhost/images/example.png
Hello from /data/images
$ curl -o /dev/null -w '%{http_code}\n' localhost/images/missing.png
404

Both locations are prefix locations: a request URI matches when it starts with the given string, and the longest matching prefix wins. /index.html matched location /, the shortest possible prefix, which catches everything the other locations do not.

The root directive does not name the directory to serve from — it names the directory the whole request URI is appended to, which is why location /images/ needs root /data, not /data/images: the URI /images/example.png appended to /data gives /data/images/example.png.

Note

When a request does not do what you expect, the answer is almost always in the access and error logs, written to /var/log/angie/.

How a request is matched against virtual servers and locations, including regular expression locations and the order they are tested in, is described in Connections, Sessions, Requests, Logs. The directives that map URIs onto files — root, alias, index, try_files — are in the HTTP modules reference.

Proxying to an Application#

Angie's second common job is to stand in front of an application and forward requests to it. Here Angie itself plays the application: a second server, listening only on loopback port 8080, serves a directory of its own. Replace it with the real application later.

$ sudo mkdir -p /data/app
$ echo 'Hello from the application' | sudo tee /data/app/index.html
Hello from the application

Put that server in a file of its own:

/etc/angie/http.d/app.conf#
server {
    listen 127.0.0.1:8080;

    root /data/app;
}

In default.conf, replace root in location / with proxy_pass, and match images by extension instead of by prefix:

/etc/angie/http.d/default.conf#
server {
    listen 80;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

    location ~ \.(gif|jpg|png)$ {
        root /data;
    }
}

Test the configuration and reload:

$ sudo angie -t && sudo systemctl reload angie

Requests now reach the application, except the ones for images:

$ curl localhost/
Hello from the application
$ curl localhost/images/example.png
Hello from /data/images

The second location starts with ~, which makes it a regular expression location instead of a prefix. Angie checks prefix locations first and remembers the longest match, then tries the regular expressions in the order they appear; if one of them matches, it wins. That is what lets a single short pattern carve the image requests out of the catch-all above it, so Angie answers them from disk without involving the application.

proxy_pass has a large set of companion directives — for request headers, timeouts, buffering, and caching — documented in the Proxy module. To spread requests across several application servers instead of one, define an upstream block and proxy to it by name.

Automatic HTTPS#

This step needs a domain name that resolves to this host's public address, and port 80 reachable from the internet: the certificate authority validates ownership by fetching a file over HTTP. Without both, skip to the next step; nothing later depends on this one.

Angie obtains and renews certificates itself, over ACME, with no external client and no renewal cron job. Add an acme_client above the server block (an http-level directive) and reference the client from the server, putting your own names in place of example.com and www.example.com:

/etc/angie/http.d/default.conf#
acme_client example https://acme-v02.api.letsencrypt.org/directory;

server {
    listen 80;
    listen 443 ssl;

    server_name example.com www.example.com;
    acme example;

    ssl_certificate     $acme_cert_example;
    ssl_certificate_key $acme_cert_key_example;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

    location ~ \.(gif|jpg|png)$ {
        root /data;
    }
}

Angie resolves the certificate authority's name through /etc/resolv.conf by default, so no resolver directive is needed. On a host with no IPv6 connectivity, add resolver conf ipv6=off; above the server block so it stops asking for AAAA records it cannot use.

The certificate is issued for the domain names listed in server_name across the servers that reference the same client; entries that are not domain names, such as regular expressions and _, are skipped with a warning in the error log. The certificate reaches ssl_certificate through a variable rather than a file path, so there is nothing to install and nothing to rotate by hand.

Test the configuration and reload:

$ sudo angie -t && sudo systemctl reload angie

Angie binds port 443 as soon as the configuration is applied, but it cannot complete a TLS handshake until the certificate arrives, so requests to that port fail during the handshake in the meantime. Issuance is not instant; it depends on the certificate authority. Once the certificate is in place:

$ curl -I https://www.example.com/
HTTP/1.1 200 OK
...

If it never arrives, look at the client's state under /status/http/acme_clients/example in the API of the next step and at the ACME messages in the error log; if that is not enough, turn on the debug log.

Note

While you are still getting the configuration right, point acme_client at the certificate authority's staging directory — for Let's Encrypt, https://acme-staging-v02.api.letsencrypt.org/directory — so that failed attempts do not count against the production rate limits. Switch to the production URL once a certificate appears.

DNS and TLS-ALPN validation, wildcard certificates, external account binding, and moving over from Certbot are covered in ACME Configuration; the directives and variables are in the ACME module.

Server Statistics#

Angie reports its own state through a built-in REST API. Add a location for it, restricted to local requests, and give the server a status_zone so its counters are collected:

/etc/angie/http.d/default.conf#
acme_client example https://acme-v02.api.letsencrypt.org/directory;

server {
    listen 80;
    listen 443 ssl;

    server_name example.com www.example.com;
    acme example;

    ssl_certificate     $acme_cert_example;
    ssl_certificate_key $acme_cert_key_example;

    status_zone site;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

    location ~ \.(gif|jpg|png)$ {
        root /data;
    }

    location /status/ {
        api /status/;

        allow 127.0.0.1;
        deny all;
    }
}

If you skipped the HTTPS step, add only the highlighted lines. The package's default.conf shipped this same /status/ location; it went away when you replaced that file, so put it back.

Test the configuration and reload; the API then answers with JSON:

$ sudo angie -t && sudo systemctl reload angie
$ curl localhost/status/angie/
{
    "version": "1.12.1",
    "build_time": "2026-07-17T06:58:49Z",
    "address": "192.0.2.10",
    "generation": 1,
    "load_time": "2026-07-17T10:23:06.011Z"
}

/status/connections reports accepted, dropped, active, and idle connections. Per-server and per-location counters are opt-in: a server appears under /status/http/server_zones/ and a location under /status/http/location_zones/, each only once it carries a status_zone of its own. The server above carries one, its locations do not:

$ curl localhost/status/http/server_zones/site
{
    "ssl": {
        "handshaked": 3,
        "reuses": 0,
        "timedout": 0,
        "failed": 0
    },

    "requests": {
        "total": 5,
        "processing": 1,
        "discarded": 0
    },

    "responses": {
        "200": 3,
        "404": 1
    },

    "data": {
        "received": 412,
        "sent": 1418
    }
}

The ssl object is there because the server listens with ssl; without it the zone starts at requests.

The full set of API sections — upstreams, caches, resolvers, shared memory zones, ACME clients, and, in Angie PRO, dynamic configuration — is documented in the API module. If you would rather look at it than curl it, Console Light renders the same data as a web panel.

Where to Go Next#

Instructions

Step-by-step guides for specific tasks: SSL, OIDC, clustering, monitoring dashboards, and custom metrics.

Modules

The reference for every directive and variable, grouped by module.

Quick Access

Short links that jump straight to a directive's documentation.

Migrating from nginx

If you also run nginx elsewhere, move those configurations across.