Documentation

Manual Binary Deployment

Updated
Browse documentation

Published 2026-08-13. V2 is a prerelease; the web core is release-gated and other previews are named separately. What beta means.

Read this page as HTML, Markdown, or structured JSON—or open the published Markdown with an AI assistant. Gemini receives the prompt through your clipboard because its signed-out page does not reliably prefill URL text; paste when the new tab opens. External assistants need the public site URL.

Manual Binary Deployment

This example keeps compilation and runtime responsibilities explicit. Adjust paths, the service user, and the target name for your application.

Build the release artifact

Amber CLI 2.0.6 builds and checks application assets after installing shards and before compiling the binary. These are build-time commands; the running web process only reads the finished manifest and files.

Terminal
shards install --production
amber assets build
amber assets check
crystal spec
shards build my_app --release
file bin/my_app

For an existing app using the explicit migration wrapper, replace the two amber assets lines with crystal run scripts/build_assets.cr and its manifest verification. Neither path may start the HTTP process or make a warm-up request to create release files.

Copy bin/my_app, config/, and the built public/ artifact to one new release directory. If your application reads other files at runtime, include them deliberately. Do not copy development secrets or a local database.

User uploads are runtime data, not release assets. Keep them on a persistent mounted volume or in object storage and leave them out of the directory replaced by each deployment. Back up local uploads independently. The application release may be read-only after its authored assets have been built.

For a manifest-enabled application, confirm the release contains both public/assets/manifest.json and every fingerprinted file it names. Include the deterministic .gz companions. Do not copy only files that changed; a release directory is a complete unit.

File: config/environments/production.yml — configure only the fallback for unfingerprinted files; Amber applies immutable caching to fingerprinted names.

YAML
static:
  headers:
    Cache-Control: "no-cache"

Configure the process

Store secrets in the host or deployment platform's secret manager. A minimal environment is:

Terminal
AMBER_ENV=production
AMBER_SERVER_HOST=0.0.0.0
AMBER_SERVER_PORT=3000
AMBER_SERVER_SECRET_KEY_BASE=replace-with-a-long-random-secret

AMBER_SERVER_PORT overrides server.port from config/environments/production.yml. Add DATABASE_URL only when the application has a configured database adapter.

Example systemd unit

Ini
[Unit]
Description=my_app Amber service
After=network.target

[Service]
Type=simple
User=my_app
Group=my_app
WorkingDirectory=/srv/my_app
EnvironmentFile=/etc/my_app.env
ExecStart=/srv/my_app/bin/my_app
Restart=on-failure
RestartSec=3
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

The environment file should be readable only by the service administrator and service account. Terminate TLS in a reverse proxy or managed ingress and proxy to 127.0.0.1:3000 when the proxy runs on the same host.

Verify before shifting traffic

Terminal
curl --fail --show-error http://127.0.0.1:3000/

Confirm the expected page, logs, restart behavior, and any persistence or file storage dependencies before sending production traffic. Keep each binary, configuration, generated asset manifest, and generated public assets together as one immutable release. Roll back by switching traffic to the complete prior release; never combine an older manifest with newer asset files.

For a manifest-enabled release, inspect the rendered HTML, copy one CSS, JavaScript, image, font, and binary URL, and request each directly. Verify:

  • the response body matches the built file;
  • CSS and local JavaScript dependencies point at existing fingerprinted URLs;
  • Content-Type matches the manifest, including font/woff2, image/avif, application/wasm, and other deployed formats;
  • fingerprinted URLs return Cache-Control: public, max-age=31536000, immutable;
  • HTML and manifest.json do not receive immutable caching;
  • gzip clients receive valid compressed bytes with the original media type and Vary: Accept-Encoding; and
  • conditional requests and byte ranges still work.

Keep the prior release directory until its HTML can no longer send clients to its asset URLs. A database rollback is a separate decision: do not reverse a non-backward-compatible migration merely because the binary or assets roll back.