Files
pic/QUICKSTART.md
T
roof 8a9f4f50c6
Unit Tests / test (push) Successful in 12m12s
docs: bring all docs current with this session's changes
Update README, QUICKSTART, wiki, service-developer-guide, and CLAUDE.md for:
optional store services (email/calendar/files), sshuttle+proxy egress exits,
provider-aware Network Services/DNS overview, DHCP/dnsmasq removal, split-horizon
VPN DNS, container hardening (slim images, unprivileged WireGuard, webui port 8080,
pinned ntp/coredns), installer changes (host NTP, PIC_DEBUG, clean output, systemd),
and the backup overhaul (full secrets coverage + optional passphrase encryption).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 15:56:03 -04:00

7.8 KiB

Quick Start

This guide walks through a first-time PIC installation on a clean Linux host.


Prerequisites

  • Linux x86-64 host — Debian, Ubuntu, Fedora, RHEL, or Alpine
  • 2 GB+ RAM, 10 GB+ disk
  • Always-required ports: 53, 80, 443, 51820/udp
  • Email service only (when installed): 25, 587, 993
  • WireGuard kernel module available on the host (modprobe wireguard); required — userspace WireGuard is not supported

The installer handles all software dependencies (git, docker, make, etc.) automatically.


curl -fsSL https://install.pic.ngo | sudo bash

Always review the script before running it:

curl -fsSL https://install.pic.ngo | less

The installer runs 7 steps and prints clean one-line progress for each. Run with PIC_DEBUG=1 or --debug for full verbose output. A complete log is always written to /var/log/pic-install.log.

The installer:

  1. Detects your OS and installs Docker, git, make via the system package manager
  2. Installs and starts host NTP (chrony) — required for ACME certificate issuance and DDNS token registration
  3. Creates a pic system user and adds it to the docker group
  4. Clones the repository to /opt/pic
  5. Runs make install — generates keys and config, writes a systemd unit. The admin password is printed once here; it does not appear again.
  6. Runs make start-core to bring up the six core containers
  7. Enables the pic systemd unit so the stack starts on reboot, then waits for the API health check

When it finishes, open the URL it prints:

http://<host-ip>:8081/setup

Option B — Manual install

Use this if you want to control where PIC is installed, or if you are installing on a machine that already has Docker.

git clone https://git.pic.ngo/roof/pic.git pic
cd pic
sudo make install
make start-core

Then open http://<host-ip>:8081/setup in a browser.

Note: install host NTP before running make install if you plan to use pic_ngo domain mode. The installer does this automatically in Option A.

sudo apt-get install -y chrony && sudo systemctl enable --now chrony

Complete the setup wizard

The setup wizard appears automatically on first start. All API requests redirect to /setup until it is finished.

The wizard asks for:

  • Cell name — used for hostnames and DDNS subdomain. Lowercase letters, digits, hyphens, 2–31 characters. Example: myhome.
  • Domain mode — how HTTPS certificates are issued:
    • pic_ngo — automatic <cell-name>.pic.ngo subdomain with a wildcard Let's Encrypt cert via DNS-01 (recommended for internet-facing cells; requires accurate host clock)
    • cloudflare — wildcard Let's Encrypt cert via Cloudflare DNS-01 (bring your own domain)
    • duckdns — Let's Encrypt via DuckDNS DNS-01
    • http01 — Let's Encrypt via HTTP-01 (no wildcard; cell must be reachable on port 80)
    • lan — internal CA only, no internet required (for LAN-only installs)
  • Timezone
  • Services to install — email, calendar, files (optional; installed in the background after setup completes; can be added later via the Services store page)
  • Admin password — minimum 12 characters, must contain uppercase, lowercase, and a digit

Click Complete Setup. The wizard creates the admin account, writes cell identity to config/api/cell_config.json, and redirects to the login page. Any services you selected begin installing in the background.


Log in

After the wizard you are redirected to /login.

  • Username: admin
  • Password: the password you set in the wizard

Add a WireGuard peer

Go to Peers in the sidebar.

  1. Click Add Peer.
  2. Enter a peer name (e.g. laptop).
  3. The API generates a key pair and assigns the next available VPN IP automatically.
  4. Click the QR code icon to display the peer configuration as a QR code.
  5. Scan the QR code with a WireGuard client (Android, iOS, or the WireGuard desktop app).

Once connected, *.cell names resolve through the cell's CoreDNS and traffic can be routed through the cell.


Installing and managing services

Email, calendar, and file storage are optional services installed from the built-in service store. They are not running by default.

To install a service:

  1. Go to Services in the sidebar.
  2. Find the service card (Email, Calendar, Files, or any other listed service).
  3. Click Install. PIC fetches the manifest, starts the container, and wires up DNS and Caddy routes automatically.
  4. The service appears in the sidebar navigation once installation completes.

To check service status:

The Services page shows each installed service as "running" or "stopped". You can also check via the API:

curl -s http://<host-ip>:3000/api/services/active

To uninstall a service:

Click Uninstall on the service card. The container is stopped and removed. Data in data/services/<id>/ is kept on disk unless you delete it manually.


Day-to-day operations

# Check container status and API health
make status

# Follow logs from all services
make logs

# Follow logs from a single service
make logs-api
make logs-wireguard
make logs-caddy

# Open a shell inside a container
make shell-api
make shell-dns

Backup and restore

make backup      # archives config/ and data/ into backups/cell-backup-<timestamp>.tar.gz
make restore     # list available backups

The backup archive is written mode 0600. It contains secrets and key material — WireGuard keys, the internal CA, vault keys, admin credentials, DDNS token, cell links, and Caddy certificates. Store it securely.

Data volumes for installed store services (email mailboxes, calendar data, file storage) are captured separately via the API-driven backup (POST /api/config/backup), which also supports an optional passphrase for encryption at rest. The encrypted file is named <backup_id>.tar.gz.age.

To restore from a make backup archive:

tar -xzf backups/cell-backup-YYYYMMDD-HHMMSS.tar.gz
make restart

After restore, the API re-generates the Caddyfile and Corefile from the restored config and re-applies routing rules automatically.


Updating PIC

make update      # git pull + rebuild + restart

Uninstalling

make uninstall   # stops containers; prompts to also delete config/ and data/

Troubleshooting

Containers not starting

make logs
make logs-api

Look for errors about missing config files or port conflicts.

Port 53 already in use

On Ubuntu and Debian, systemd-resolved listens on port 53. Disable it:

sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

Then run make start again.

WireGuard container fails to start

The WireGuard container runs unprivileged (NET_ADMIN only, no privileged mode). It requires the host kernel's WireGuard module — either compiled in (Linux 5.6+) or loadable.

sudo modprobe wireguard

On minimal installs you may need wireguard-tools and the kernel headers for the running kernel. On kernels that lack a builtin WireGuard module, check your distro's wireguard-dkms or wireguard-linux-compat package.

API returns 428 and redirects to /setup

The first-run wizard has not been completed. Open http://<host-ip>:8081 and finish the wizard.

API returns 401 / UI shows "Not authenticated"

Your session expired or you have not logged in. Go to http://<host-ip>:8081/login.

API returns 503 "Authentication not configured"

The auth file exists but contains no accounts. To recover:

make reset-admin-password

This generates a new admin password and prints it.

Forgot the admin password

make show-admin-password    # print current password
make reset-admin-password   # generate a new random password