- ente
- Jonathan Haack
- Haack’s Networking
- webmaster@haacksnetworking.org
//Ente//
Latest Updates: https://wiki.haacksnetworking.org/doku.php?id=computing:ente
This tutorial is for Debian users who want to setup Ente manually. I used this tutorial Ente Manual Install as a jumping off point for what is 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 rustupthenrustup 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.
- Open https://gnulinux.pics and sign up.
- OTP: ”journalctl -u ente-museum -n 200 –no-pager”
- User id: 34982349839489320843 (example)
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
Now, let’s setup Garage. 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 steps for upgrading garage:
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. Here is a museum.yaml example:
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
Here is a draft instance upgrade recipe:
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!
Happy Hacking,
— oemb1905