summaryrefslogtreecommitdiff
path: root/docs/OPERATIONS.txt
blob: bf675be45f8606f7e6a3cdd41e40f72f340202bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

STACK OPERATIONS

    Root: ~/stack. Workstation: local Linux. Production: ops@23.155.44.67.
    Public source: https://git.doan.luuduct.ai/stack.
    Production commands use bin/run, which selects packed Guix tools/config.
    Direct bin/stack uses host tools; never mix engines against the same storage.

KEEP

    For new-host recovery keep the carry file described in GUIX.txt: encrypted
    application export plus matching checked release, Guix runtime and bootstrap.
    Private state is encrypted; public tools/source are plaintext. Keep its trusted
    checksum and an independent copy on another device/location.
    It preserves one .env, databases, TLS keys, bare repos, working Git history,
    binaries, browser assets, sources and exact service images. Engine storage,
    caches, host accounts/SSH/firewall, disks and OS configuration are excluded.
    Public Git alone cannot recover private state.

    Keep GPG secret key/passphrase separately; default backup recipient:
        3346AA3150F8F16828BB0D14F8C66DF77AFECEA6
    Keep an independent protected key export/revocation certificate. Chat owner
    and visitor private identity files/passwords also need separate backups.
    Never send private keys or passwords through chat.

DEVELOP LOCAL

        cargo stack dev
        cargo stack status
        cargo stack down

    Open http://localhost:8080, /git/, /search/, http://chat.localhost:8080/.
    Alternate port: cargo stack dev --port 9080. Local mode binds loopback only;
    no public TLS or DNS changes. Missing .env is initialized with random secrets.
    infra/services.toml lists each service's environment, mounts and health check.

    Local development uses host Podman. Project storage is var/podman; bare
    podman ps uses another store. From the local checkout:

        podman --root "$PWD/var/podman/storage" --runroot "$PWD/var/podman/run" ps -a

    Keep both global options for logs/exec/images. Use bin/run status on production.
    Never transfer var/podman as backup; export saved images instead.

CHECK AND BUILD LOCAL

        cargo install --locked --version 0.20.2 cargo-deny --root .tools
        cargo install --locked --version 0.9.3 --features cli cargo-about --root .tools
        cargo stack check
        cargo run --release --locked -- release

    Check covers TypeScript compilers/typed ESLint/npm audit, Guix shell fixtures,
    formatting, strict workspace Clippy/tests/private Rustdoc, advisories, exact
    duplicate exceptions and licenses. cargo-about regenerates the license page.
    Dependency edits require deliberate lockfile review, full checks and notices.
    Never waive failures. Format with cargo fmt --all.

    Build the Guix pack first when adding/changing runtime tools: GUIX.txt.
    Release builds static Rust/chat WASM, corresponding source, cgit/chat images
    and complete image export. Output: dist/stack-release-TIMESTAMP.tar.gz and
    .sha256. Actual .env, live data, .git and prior backups are excluded.
    Build/test locally; no compiler or registry pull is needed on the matching
    x86_64 production host. Restore/inspect a disposable release before deployment.

BACK UP PRODUCTION

        cd ~/stack
        ./bin/run backup --include-images

    Briefly pauses Caddy/cgit/SearXNG during file copy; resumes before compression
    and encryption. Chat stays live for SQLite online backup. Export includes
    chat/chat-local snapshots; excludes raw journals and server locks.
    Verifies recipient fingerprint, bare repos and exact image identities.
    Output has restrictive permissions:

        var/exports/stack-TIMESTAMP.tar.gz.gpg
        var/exports/stack-TIMESTAMP.tar.gz.gpg.sha256

    Copy both files off the VPS; substitute actual filenames:

        umask 077
        mkdir -p ~/stack/var/backups/production
        scp ops@23.155.44.67:stack/var/exports/stack-TIMESTAMP.tar.gz.gpg ~/stack/var/backups/production/
        scp ops@23.155.44.67:stack/var/exports/stack-TIMESTAMP.tar.gz.gpg.sha256 ~/stack/var/backups/production/
        cd ~/stack/var/backups/production
        sha256sum -c stack-TIMESTAMP.tar.gz.gpg.sha256

    No scheduled backup. Choose retention/off-host copies; remove matching VPS
    exports only after verification. Never delete .env or var/data.
    Export without --include-images is not standalone production recovery.
    Pair the verified export with a checked release using infra/guix/bundle.sh;
    the resulting carry file restores with the matching manager/source/runtime.

RECOVER ON LINUX

    Follow GUIX.txt for host prerequisites and GPG key access. On a fresh x86_64
    Linux host, as the service user, with a new destination:

        tar -xzf recovery.tar.gz
        sudo ./stack-recovery/bootstrap
        ./stack-recovery/restore /home/ops/stack

    Capsule verifies/decrypts the export, activates its paired release and starts
    four services. A failed activation can resume with the same restore command.
    Keep hostname/origin and identity files unchanged; repoint DNS when IP changes.
    Recovery does not configure host SSH, firewall, account or boot startup.

    A raw format-2 export can be restored for inspection on a host that already
    has compatible tools and any required Guix closure:

        ./bin/run restore /path/export.tar.gz.gpg /path/stack-restored

    Raw restore validates all manifest paths/hashes, defaults local mode with a
    fresh project identity, starts nothing and refuses an existing destination.
    Public release archives restore similarly but contain no private data.
    An old raw export may lack the launcher/runtime; use a paired capsule for
    complete recovery. Test owner/visitor identities and history after recovery.

HOST AND BOOT SETUP

    Host/provider firewall: retain SSH and allow HTTP 80/tcp, HTTPS 443/tcp+udp
    for applicable IPv4/IPv6. Never publish backend container ports. A points to
    the new IPv4; publish AAAA only with working IPv6. Keep www/WKD aliases.
    Rootless IDs, mapping helpers, runtime directory and low-port sysctl: GUIX.txt.
    Debian host-tools fallback: infra/host-setup.sh installs distro Podman and
    prerequisites. Guix supplies its own Podman/network tools.

        cd ~/stack
        ./bin/run up --production
        systemctl --user link ~/stack/infra/stack.service
        systemctl --user daemon-reload
        systemctl --user enable --now stack.service
        systemctl --user status stack.service

    Administrator enables linger for the service user. Unit assumes ~/stack;
    adapt paths for another location. Caddy stores credentials in var/data/caddy,
    issues/renews public certificates and redirects HTTP/www. ACME needs public
    DNS/connectivity. Containers use unless-stopped restart policy.

    Current VPS SSH Git compatibility path /srv/git/stack links to
    /home/ops/stack/var/data/repos/stack. Preserve it for existing clone URLs;
    public HTTPS Git needs no host symlink.

DEPLOY A CHECKED RELEASE

    Review/stage public changes, sign and push the current branch:

        git diff --cached --stat
        git commit -S3346AA3150F8F16828BB0D14F8C66DF77AFECEA6 -m 'Describe the change'
        git push origin HEAD

    Do not deploy with git pull. Take a verified independent export first; retain
    complete old worktree/binary/unit, var/state.json, image-lock.json, images.tar
    and prior engine storage for rollback. Guix upgrade/rollback rules: GUIX.txt.
    Copy the checked public release and checksum to ~/stack/var/incoming.
    Before activation install any new closure through its verified capsule
    bootstrap; an existing managed Guix store needs separate planning.

    Bash on VPS, after that bootstrap; substitute actual TIMESTAMP:

        (
        set -eu
        cd ~/stack
        STACK_ROOT=$PWD
        STACK_RELEASE=$PWD/var/incoming/stack-release-TIMESTAMP.tar.gz
        (cd var/incoming && sha256sum -c stack-release-TIMESTAMP.tar.gz.sha256)
        STACK_STAGE=$(mktemp -d "$PWD/var/incoming/.activate.XXXXXX")
        tar -xzf "$STACK_RELEASE" -C "$STACK_STAGE" stack/bin/stack stack/bin/guix-runtime.tar.gz stack/infra/guix/containers.conf
        mkdir "$STACK_STAGE/runtime"
        tar -xzf "$STACK_STAGE/stack/bin/guix-runtime.tar.gz" --no-same-owner -C "$STACK_STAGE/runtime"
        env PATH="$STACK_STAGE/runtime/bin:$PATH" CONTAINERS_CONF="$STACK_STAGE/stack/infra/guix/containers.conf" "$STACK_STAGE/stack/bin/stack" --root "$STACK_ROOT" activate "$STACK_RELEASE"
        systemctl --user daemon-reload
        systemctl --user restart stack.service
        ./bin/run status
        chmod -R u+w -- "$STACK_STAGE"
        rm -rf -- "$STACK_STAGE"
        )

    Use the NEW manager and matching runtime. Activation verifies archive/platform,
    replaces public source/binaries/images, preserves .env/var/data/.git and
    replaces containers. Expect interruption. The installed unit may already link
    to infra/stack.service; reload its definition rather than copying over itself.
    If activation fails, retain staging/data and diagnose before retry or rollback.
    Verify public routes, TLS/WKD, owner and database before removing incoming files.

RECOVERY LIMITS; KEY ROTATION

    Other CPU architectures need native release builds. Host DNS/PTR, firewall,
    accounts and SSH remain outside the carry file. New databases need consistent
    snapshot/recovery support before inclusion. Preserve both participants' chat
    files/passwords; server backups cannot replace them. CHAT-PRODUCTION.txt.

    For a new backup recipient, publish its public key, update root .env and test
    encryption/recovery. One export can select --recipient FULL_FINGERPRINT and
    --key /path/public-key.asc. Keep old secret keys while retained exports need them.

LICENSE PAGE; REDIRECTS

    cargo-about generates web/THIRD-PARTY-LICENSES.html. Caddy serves it on the
    main-site origin; chat redirects its former local license URL there. Source
    exports retain offline license texts. cgit Source/Raw expose the generated file.
    Homepage /message and /message/ redirect to the configured chat origin.