# Installation ## Requirements - Linux x86_64 (the `.deb` needs glibc >= 2.30: Debian 11+, Ubuntu 20.04+). No OpenSSL or PHP - TLS is rustls and SQLite is built in. - IMAP server (Dovecot recommended: `UIDPLUS`, `MOVE`, `SPECIAL-USE`, `CONDSTORE`, `UNSELECT`). - SMTP submission (Postfix on 587 with SASL) or a local `sendmail`. - Optional CalDAV/CardDAV. - A TLS reverse proxy (nginx, RustProxy, Apache). ActivePush listens on `127.0.0.1` only by default. ## Debian package ```bash ./dev.sh deb # on the build machine (Rust stable; cargo-zigbuild makes it portable) sudo apt install ./dist/active-push_*_amd64.deb ``` | Path | Content | |---|---| | `/usr/bin/active-push` | binary (server + CLI) | | `/lib/systemd/system/active-push.service` | service with systemd sandboxing | | `/etc/active-push/environment` | listen addresses, panel TLS, log level (conffile) | | `/var/lib/active-push/active-push.db` | SQLite: settings, devices, states, statistics, audit (0600) | | `/usr/share/doc/active-push/` | documentation and nginx examples | | `/usr/share/active-push/zpush-import.py` | Z-Push configuration importer | `postinst` creates the `active-push` system user and enables and starts the service. Upgrading the package restarts the service (push connections are released and devices reconnect). `apt purge` also removes data. ### Portable builds `scripts/build-deb.sh` uses `cargo zigbuild` with a glibc 2.31 baseline when it is installed (`pip install ziglang && cargo install cargo-zigbuild`), otherwise a normal `cargo build`. The `libc6` dependency is computed from the binary's symbols. `GLIBC_TARGET=0` forces a native build. ### First administrator ```bash sudo -u active-push active-push admin setup-token # one-time token, valid 60 minutes ssh -L 9091:127.0.0.1:9091 admin@server # from your workstation # browser: http://127.0.0.1:9091 -> paste the token, choose login and password (min. 12 characters) ``` Without a browser: `sudo -u active-push active-push admin init --username admin`. Lost password: `sudo -u active-push active-push admin reset-password` (revokes all sessions). Always run CLI commands as `active-push`; the binary refuses to touch a data directory owned by another user. ## nginx Replace the Z-Push fastcgi locations with the snippet from `deploy/nginx-active-push.conf`: ```nginx location = /Microsoft-Server-ActiveSync { proxy_pass http://127.0.0.1:8081; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3660s; # Ping holds the request for up to ~59 minutes proxy_send_timeout 3660s; proxy_buffering off; client_max_body_size 64m; } location = /AutoDiscover/AutoDiscover.xml { include snippets/active-push-autodiscover.conf; } location = /Autodiscover/Autodiscover.xml { include snippets/active-push-autodiscover.conf; } location = /autodiscover/autodiscover.xml { include snippets/active-push-autodiscover.conf; } # health check for monitoring / load balancers (no authentication, no data) location = /activesync-healthz { proxy_pass http://127.0.0.1:8081/healthz; access_log off; } ``` `snippets/active-push-autodiscover.conf` is `deploy/active-push-autodiscover.conf`. **Important:** `X-Forwarded-For $remote_addr` (overwrite, not append) together with the default trusted proxy `127.0.0.1/32` gives the real client IP for lockouts and logs. Port 8081 answers `/` with a short text, `/healthz` with `ok` (also checks the database) and anything else with a plain 404. ## RustProxy Create a vhost for the mail domain that routes `/Microsoft-Server-ActiveSync` and the three autodiscover paths to `http://127.0.0.1:8081` with a response timeout of at least 3660 s and response buffering disabled; point a health check at `/healthz`. RustProxy sets `X-Forwarded-For`, so its address must be in **Security -> Trusted proxies** (loopback by default). ## Postfix (submission) Recommended: SMTP on 587 authenticated with the device user's credentials (`auth: user_credentials`). With `smtpd_sender_login_maps` + `reject_sender_login_mismatch` the mail server enforces the sender as well. The `sendmail` method needs `NoNewPrivileges=false` and `ReadWritePaths=/var/spool/postfix/maildrop` in the unit (setgid `postdrop`), which is why it is not recommended. ## Panel outside localhost The panel refuses to start on a non-loopback address unless allowed: ```ini # /etc/active-push/environment ACTIVE_PUSH_ALLOW_REMOTE_ADMIN=true ACTIVE_PUSH_ADMIN_LISTEN=0.0.0.0:9091 ACTIVE_PUSH_ADMIN_TLS_CERT=/etc/active-push/tls/fullchain.pem ACTIVE_PUSH_ADMIN_TLS_KEY=/etc/active-push/tls/privkey.pem ``` and set **Security -> Networks allowed to use the panel**. Certificates must be readable by the `active-push` group (e.g. copied by a certbot deploy hook). ## Upgrades Install the new package; the schema is migrated automatically on start. Settings, devices and states are kept. ## Backups See [LOGS.md](LOGS.md#backups). Losing the database never loses mail - devices resynchronise. ## Building from source without a package ```bash cargo build --release sudo install -m 0755 target/release/active-push /usr/bin/active-push sudo adduser --system --group --home /var/lib/active-push active-push sudo install -d -o active-push -g active-push -m 0700 /var/lib/active-push sudo install -m 0644 deploy/active-push.service /etc/systemd/system/ sudo install -d -m 0750 -g active-push /etc/active-push sudo install -m 0640 -g active-push deploy/environment.example /etc/active-push/environment sudo systemctl daemon-reload && sudo systemctl enable --now active-push ```