User Tools

Site Tools


computing:ente

  • ente
  • Jonathan Haack
  • Haack's Networking
  • webmaster@haacksnetworking.org

Ente


This tutorial is for Debian users who want to setup Ente manually. I used this tutorial as a jumping off point and setup Ente as documented below. Since minio is now paywalled, I used Garage as the s3-compat bucket and just pointed it at the vm's virtiofs mountpoint which points to underlying btrfs r10 on the host (encrypted w/ LUKS).

Go / Node / Rust:

  • Go: apt install golang-go
  • Node/npm: apt install nodejs npm
  • Rust: apt install rustup then rustup default stable

Addresses:

  • IPv4: 8.28.86.133
  • IPv6: 2604:fa40:0:10::36
  • Apex: gnulinux.pics

DNS A/AAAA for:

  • gnulinux.pics
  • api.gnulinux.pics
  • s3.gnulinux.pics
  • albums.gnulinux.pics
  • accounts.gnulinux.pics
  • auth.gnulinux.pics
  • share.gnulinux.pics
  • cast.gnulinux.pics
  • embed.gnulinux.pics
  • memories.gnulinux.pics
  • legacy.gnulinux.pics

Setup base system,

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl wget git gnupg lsb-release build-essential pkg-config postgresql postgresql-contrib libsodium23 libsodium-dev caddy ufw
sudo systemctl enable --now postgresql
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
git clone https://github.com/ente-io/ente.git /root/ente

Now, Go, Rust, and Node setup:

sudo apt install -y golang-go rustup nodejs npm
rustup default stable
go version
rustc --version
node -v
npm -v

Setup PostgreSQL and create the db with sudo -u postgres psql and something like:

CREATE USER ente WITH ENCRYPTED PASSWORD 'ENTE_DB_PASS';
CREATE DATABASE ente_db OWNER ente;
GRANT ALL PRIVILEGES ON DATABASE ente_db TO ente;
\q

Next, lock access to db:

echo 'host    ente_db    ente    127.0.0.1/32    scram-sha-256' | sudo tee -a /etc/postgresql/*/main/pg_hba.conf
echo 'host    ente_db    ente    ::1/128         scram-sha-256' | sudo tee -a /etc/postgresql/*/main/pg_hba.conf
sudo systemctl reload postgresql
PGPASSWORD='ENTE_DB_PASS' psql -h 127.0.0.1 -U ente -d ente_db -c 'SELECT 1;'

Edit museum.yaml and configure it, build its web apps, start it, and create unit:

cd /root/ente/server
go mod tidy
go build cmd/museum/main.go
go run tools/gen-random-keys/main.go
cp config/example.yaml museum.yaml

Edit /root/ente/server/museum.yaml using keys from second to last step above. Now, create systemd unit.

sudo tee /etc/systemd/system/ente-museum.service >/dev/null << 'EOF'
[Unit]
Description=Ente Museum
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/root/ente/server
ExecStart=/root/ente/server/main
Restart=on-failure
RestartSec=3
Environment=GIN_MODE=release
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now ente-museum
curl -sS http://127.0.0.1:8080/ping

Build the Web apps and migrating content from repo

cd /root/ente/web
npm ci
export NEXT_PUBLIC_ENTE_ENDPOINT=https://api.gnulinux.pics
npm run build
npm run build:albums
npm run build:accounts
npm run build:auth
npm run build:cast
npm run build:share
npm run build:embed
npm run build:memories
sudo mkdir -p /var/www/ente/apps
sudo rm -rf /var/www/ente/apps/*
sudo cp -a apps/photos/out   /var/www/ente/apps/photos
sudo cp -a apps/albums/out   /var/www/ente/apps/albums
sudo cp -a apps/accounts/out /var/www/ente/apps/accounts
sudo cp -a apps/auth/out     /var/www/ente/apps/auth
sudo cp -a apps/cast/out     /var/www/ente/apps/cast
sudo cp -a apps/share/out    /var/www/ente/apps/share
sudo cp -a apps/embed/out    /var/www/ente/apps/embed
sudo cp -a apps/memories/out /var/www/ente/apps/memories
sudo chown -R caddy:caddy /var/www/ente

Setup Caddy reverse proxy / load balancer, acme certs, and vhosts with nano /etc/caddy/Caddyfile and enter the following:

{
    email admin@gnulinux.pics
}
api.gnulinux.pics {
    reverse_proxy 127.0.0.1:8080
}
gnulinux.pics {
    root * /var/www/ente/apps/photos
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
albums.gnulinux.pics {
    root * /var/www/ente/apps/albums
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
accounts.gnulinux.pics {
    root * /var/www/ente/apps/accounts
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
auth.gnulinux.pics {
    root * /var/www/ente/apps/auth
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
share.gnulinux.pics {
    root * /var/www/ente/apps/share
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
cast.gnulinux.pics {
    root * /var/www/ente/apps/cast
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
embed.gnulinux.pics {
    root * /var/www/ente/apps/embed
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
memories.gnulinux.pics {
    root * /var/www/ente/apps/memories
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
legacy.gnulinux.pics {
    root * /var/www/ente/apps/accounts
    encode gzip
    file_server
    try_files {path} {path}.html /index.html
}
s3.gnulinux.pics {
    header Access-Control-Allow-Origin *
    header Access-Control-Allow-Methods "GET, PUT, POST, HEAD, DELETE, OPTIONS"
    header Access-Control-Allow-Headers *
    header Access-Control-Expose-Headers "ETag, Accept-Ranges, Content-Range, Content-Length, Content-Type"
    header Access-Control-Max-Age 3600
    @options method OPTIONS
    handle @options {
        respond 204
    }
    reverse_proxy 127.0.0.1:3900
}

Verify after making config, then restart service, debug as needed:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl enable --now caddy
sudo systemctl reload caddy
curl -sS http://127.0.0.1:8080/ping
curl -sSI https://gnulinux.pics
curl -sS https://api.gnulinux.pics/ping

End point works now, go to url in browser and create first user then use the id# to lock it as admin.

  1. Open https://gnulinux.pics and sign up.
  2. OTP: journalctl -u ente-museum -n 200 –no-pager
  3. User id: 34982349839489320843

You need to locate the id# by searching logs for your email in close proximity as per above. Or, alternately, make a one-liner:

journalctl -u ente-museum --no-pager | grep -F -A 80 'user@example.com' | grep -oE 'user_id=[1-9][0-9]*' | tail -1

Once that's done, go edit nano /root/ente/server/museum.yaml:

internal:
    admins:
        - USER_ID
    trusted-client-ip-header: X-Forwarded-For

Restart service,

sudo systemctl restart ente-museum

How to edit admin user to give them more storage:

PGPASSWORD='ENTE_DB_PASS' psql -h 127.0.0.1 -U ente -d ente_db -c "UPDATE subscriptions SET storage = 25::bigint * 1024 * 1024 * 1024 WHERE user_id = USER_ID RETURNING user_id, storage;"
# 100 250 500 750 → same, change 25
# 1TB = 1024   1.5TB = 1536   2TB = 2048

## 8. Garage (needed before uploads work) Warning: If you rerun layout/bucket/key it hoses the current bucket.

sudo mkdir -p /var/lib/garage/meta /mnt/warehouse/media/glpics
curl -fL -o /tmp/garage https://garagehq.deuxfleurs.fr/_releases/v2.4.1/x86_64-unknown-linux-musl/garage
sudo install -m 0755 /tmp/garage /usr/local/bin/garage
garage --version

Create config .toml file and start garage service:

sudo tee /etc/garage.toml >/dev/null << 'EOF'
metadata_dir = "/var/lib/garage/meta"
data_dir = "/mnt/warehouse/media/glpics"
db_engine = "sqlite"
replication_factor = 1
rpc_bind_addr = "127.0.0.1:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "GARAGE_RPC_SECRET"
[s3_api]
s3_region = "garage"
api_bind_addr = "127.0.0.1:3900"
root_domain = ".s3.gnulinux.pics"
[admin]
api_bind_addr = "127.0.0.1:3903"
admin_token = "GARAGE_ADMIN_TOKEN"
EOF

Create systemd unit for garage to monitor and restart service:

sudo tee /etc/systemd/system/garage.service >/dev/null << 'EOF'
[Unit]
Description=Garage S3
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/garage -c /etc/garage.toml server
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now garage
sudo systemctl status garage --no-pager

Create bucket on the same host and name it / give perms for Ente's default s3-compatible endpoint:

garage -c /etc/garage.toml status
NODE=$(garage -c /etc/garage.toml node id -q | head -1)
garage -c /etc/garage.toml layout assign -z dc1 -c 1T "$NODE"
garage -c /etc/garage.toml layout apply --version 1
garage -c /etc/garage.toml bucket create b2-eu-cen
garage -c /etc/garage.toml key create ente-photos
garage -c /etc/garage.toml bucket allow b2-eu-cen --read --write --owner --key ente-photos
garage -c /etc/garage.toml key info ente-photos

Once the bucket is built, add the creds it spit out into /root/ente/server/museum.yaml and restart Museum.

s3:
    are_local_buckets: false
    use_path_style_urls: true
    b2-eu-cen:
        key: GARAGE_ACCESS_KEY
        secret: GARAGE_SECRET_KEY
        endpoint: s3.gnulinux.pics
        region: garage
        bucket: b2-eu-cen

Restart the service

sudo systemctl restart ente-museum

Draft Upgrade Garage Steps

VER=v2.4.1
ARCH=x86_64-unknown-linux-musl
curl -fL -o /tmp/garage "https://garagehq.deuxfleurs.fr/_releases/${VER}/${ARCH}/garage"
/tmp/garage --version
sudo systemctl stop ente-museum garage
sudo cp -a /usr/local/bin/garage /usr/local/bin/garage.bak-$(date +%F)
sudo install -m 0755 /tmp/garage /usr/local/bin/garage
sudo systemctl start garage ente-museum
garage -c /etc/garage.toml status
curl -sS https://api.gnulinux.pics/ping

Potential steps if garage upgrade fails:

sudo systemctl stop garage
sudo cp /usr/local/bin/garage.bak-YYYY-MM-DD /usr/local/bin/garage
sudo systemctl start garage

Do not layout/bucket/key on upgrade - it will hose current bucket. Example museum.yaml example config layout for base setup

db:
    host: 127.0.0.1
    port: 5432
    name: ente_db
    user: ente
    password: ENTE_DB_PASS
s3:
    are_local_buckets: false
    use_path_style_urls: true
    b2-eu-cen:
        key: GARAGE_ACCESS_KEY
        secret: GARAGE_SECRET_KEY
        endpoint: s3.gnulinux.pics
        region: garage
        bucket: b2-eu-cen
apps:
    public-albums: https://albums.gnulinux.pics
    embed-albums: https://embed.gnulinux.pics
    public-locker: https://share.gnulinux.pics
    public-paste: https://share.gnulinux.pics
    cast: https://cast.gnulinux.pics
    accounts: https://accounts.gnulinux.pics
    public-memories: https://memories.gnulinux.pics
    legacy: https://gnulinux.pics
key:
    encryption: MUSEUM_KEY_ENCRYPTION
    hash: MUSEUM_KEY_HASH
jwt:
    secret: MUSEUM_JWT_SECRET
internal:
    admins:
        - USER_ID
    trusted-client-ip-header: X-Forwarded-For
smtp:
    host: mail.example.com
    port: 587
    username: SMTP_USER
    password: SMTP_PASS
    email: SMTP_FROM
    sender-name: gnulinux.pics

Draft update sequence

sudo apt update && sudo apt upgrade
rustup update
cd /root/ente && git pull
cd /root/ente/server
go mod tidy
go build cmd/museum/main.go
sudo systemctl restart ente-museum
cd /root/ente/web
npm ci
export NEXT_PUBLIC_ENTE_ENDPOINT=https://api.gnulinux.pics
npm run build
npm run build:albums
npm run build:accounts
npm run build:auth
npm run build:cast
npm run build:share
npm run build:embed
npm run build:memories
sudo rsync -a --delete apps/photos/out/   /var/www/ente/apps/photos/
sudo rsync -a --delete apps/albums/out/   /var/www/ente/apps/albums/
sudo rsync -a --delete apps/accounts/out/ /var/www/ente/apps/accounts/
sudo rsync -a --delete apps/auth/out/     /var/www/ente/apps/auth/
sudo rsync -a --delete apps/cast/out/     /var/www/ente/apps/cast/
sudo rsync -a --delete apps/share/out/    /var/www/ente/apps/share/
sudo rsync -a --delete apps/embed/out/    /var/www/ente/apps/embed/
sudo rsync -a --delete apps/memories/out/ /var/www/ente/apps/memories/
sudo chown -R caddy:caddy /var/www/ente
sudo systemctl reload caddy
curl -sS https://api.gnulinux.pics/ping

Store secrets properly

oemb1905 2026/09/21 02:50

computing/ente.txt · Last modified: by oemb1905