Files
myoffice_public/proxmox

MyOffice on Proxmox (Gitea releases)

Three-tier setup on your Gitea:

Tier Repo Visibility Contents
1. Dev myoffice Private Full source + Actions
2. Public code myoffice-public Public Build tree (.publishinclude) + Proxmox scripts + public README
3. Published app Releases on myoffice-public Public myoffice-publish.tar.gz

Public sync does not include Docker, private .gitignore, *.bat, tests, docs, or private Actions (.gitea/). See .publishinclude.

CT install downloads the release tarball (not source). No Docker/nginx/SDK/Node inside the CT — proxy with your existing nginx LXC to Kestrel :9100.

[private myoffice] --sync-public--> [myoffice-public full source + README]
[private myoffice] --publish+release--> [Gitea Release .tar.gz]
                                              |
[User Proxmox] one-line curl myoffice.sh --> [LXC: Postgres + ASP.NET + app]
                                              ^
[User nginx] proxy_pass http://ct-ip:9100 ----+

End user: create CT (one line)

Shown on the public repo README.md after sync. Example for this instance:

bash -c "$(curl -fsSL https://mygit.ase.com.ua/alexandr/myoffice_public/raw/branch/master/proxmox/myoffice.sh)"
# Optional trailing IP → CT /etc/hosts for mygit (when hairpin DNS fails):
# bash -c "$(curl -fsSL …/proxmox/myoffice.sh)" 192.168.100.10

Optional env before the command: GITEA_URL, GITEA_OWNER, GITEA_REPO, GITEA_BRANCH, RELEASE_TAG (latest or v1.2.3).

Whiptail: Default / Advanced (Public URL, release tag) → creates CT → installs Postgres + ASP.NET runtime → downloads release → configures FrontEnd/CORS + local Postgres → systemd.

End user: build from public source

git clone https://mygit.ase.com.ua/alexandr/myoffice_public.git
cd myoffice_public
./proxmox/publish.sh --tar

Maintainer: publish a release

On the private repo (build PC or Gitea Actions):

$env:GITEA_TOKEN = '<token with write:repository on myoffice-public>'

.\proxmox\publish.ps1 -Tar
.\proxmox\release.ps1 -GiteaUrl https://mygit.ase.com.ua -Owner alexandr -Repo myoffice_public -Tag v1.2.3
.\proxmox\sync-public.ps1 -GiteaUrl https://mygit.ase.com.ua -Owner alexandr -Repo myoffice_public -Branch master -Push
  • proxmox/publish.ps1_Published/ + myoffice-publish.tar.gz
  • proxmox/release.ps1 → Gitea Release asset
  • proxmox/sync-public.ps1 → allowlisted build tree + public README.md (from README.public.md)

Or via Gitea Actions on the private repo (.gitea/workflows/publish.yml): push master → tag latest, or push tag v* / manual dispatch.

Lab-only SSH deploy (no Gitea): .\proxmox\deploy.ps1 -TargetHost <ct-ip>

What runs inside the CT

Service How Port
PostgreSQL apt + systemd 127.0.0.1:5432
MyOffice API + SPA dotnet via myoffice-api.service 9100
/opt/myoffice/api       # extracted release (API + wwwroot)
/opt/myoffice/proxmox   # install/update helpers + env

Config chain:

  • Front → API: same-origin SPA (environment.proxmox.ts)
  • API → Postgres: CT appsettings.shared.Production.json
  • Browser → app: nginx → http://<ct-ip>:9100

Proxy (your nginx LXC)

location / {
    proxy_pass http://<myoffice-ct-ip>:9100;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

In Advanced install, set Public URL to the exact browser URL (e.g. https://office.ase.com.ua) so CORS / OpenIddict issuer / FrontEnd:Host match.

Update later

pct enter <CTID>
/opt/myoffice/proxmox/update.sh          # re-download RELEASE_TAG + restart
/opt/myoffice/proxmox/update.sh logs
/opt/myoffice/proxmox/update.sh status

Release settings are stored in /opt/myoffice/proxmox/env.

Gitea ops checklist

  • Create private myoffice and public myoffice-public
  • Raise release attachment size limit if needed
  • Token for maintainers: write:repository on public repo
  • TLS (or trust custom CA) so Proxmox/curl can download
  • Private repo secret PUBLIC_TOKEN for Actions (.gitea/workflows/publish.yml)

Gitea runner caching

Three layers (independent):

Layer What How
Toolcache .NET SDK / Node binaries setup-dotnet / setup-node write to /opt/hostedtoolcache. Persist it on the act_runner host (Docker volume) so the next job reuses downloads (steps still run, but skip re-download — you already saw Found in cache @ /opt/hostedtoolcache/...).
Actions cache NuGet + npm packages Workflow uses actions/cache@v4 for ~/.nuget/packages and ~/.npm. Needs the runner cache server (default on act_runner).
Skip setup No setup steps at all Bake SDK + Node into the job Docker image (or host runner), then set job env SKIP_SETUP_DOTNET=true and SKIP_SETUP_NODE=true.

Example act_runner volume (compose):

volumes:
  - /var/run/docker.sock:/var/run/docker.sock
  - act-toolcache:/opt/hostedtoolcache   # persist SDK/Node between jobs

If jobs use ephemeral containers without that volume, SDKs download every run.

Defaults

  • Debian 12 LXC, unprivileged, --onboot 1
  • Prompts: IP (DHCP or static), CPU (default 2), RAM (default 2048 MiB), Disk (default 10 GiB)
  • Bridge vmbr0 / listen :9100

Demo logins

  • App: user_UAH@user_UAH.userUAH / user_UAH (also USD, EUR)
  • Postgres: user/db/password myoffice