Guide
This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale (TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot open any port on the internet but want to run their own selfhosted service for themselves, friends and family only.
Before getting start keep the following NOTE in mind.
NOTE
If someone is behind double or triple CGNAT; must install tailscale system wide by running curl -fsSL https://tailscale.com/install.sh | sh
in your linux terminal and sudo tailscale up
otherwise dns resolver will fail and uploading will not work. This is not necessary for those who are not behing CGNAT. This guide also work on docker rootless and normal.
CAUTION
Remember that current docker update 28.0.0 has some bug and cannot connect to external network. Make sure to install docker-ce 27.5.0, docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker 28.1.0 will resolve this issue in next week. Refrence links are Moby Github Repo Issues 49511 and Moby Github Repo Issues 49519
IMPORTANT
For Docker rootless, the user must have local permissions for all directories required by the Ente-photos self-hosted server. This can be achieved by running sudo chown -R 1000:1000 /home/ubuntu/docker/ente
. In the Linux terminal, you can check the UID with id -u
or simply id
. The first user typically has UID 1000. To allow listening and pinging on any port without root privileges, create a file called /etc/sysctl.d/99-rootless.conf
with the following content:
net.ipv4.ip_unprivileged_port_start=0
net.ipv4.ping_group_range = 0 2147483647
than run sudo sysctl --system
. Create ~/.config/systemd/user/docker.service.d/override.conf
with the following content:
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
and Restart the docker daemon systemctl --user restart docker
Instead of --volume /var/run/docker.sock:/var/run/docker.sock
in TSDPROXY compose.yaml, use --volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock
GETTING START WITH SETUP
First of all create a directory sudo mkdir -p /home/ubuntu/docker/tsdproxy/config
than cd docker/tsdproxy
and create compose.yaml file by running sudo nano compose.yaml
. Populate it with the following:
services:
tsdproxy:
image: almeidapaulopt/tsdproxy
container_name: tsdproxy
restart: unless-stopped
environment:
TZ: Asia/Singapur # change me
volumes:
- $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock # for docker rootless otherwise /var/run/docker.sock:/var/run/docker.sock
- tsdproxy_data:/data
- /home/lee/docker/tsdproxy/config:/config
networks:
- proxy
labels: # giving the labels here will create tsdproxy instance in tailscale admin counsle and GUI can be accessable through tailscale if device is connected
- tsdproxy.enable=true
- tsdproxy.name=tsdproxy
- tsdproxy.ephemeral=false # this is optional but useful
volumes:
tsdproxy_data:
name: tsdproxy_data
networks:
proxy:
name: proxy
Now login into your tailscale account admin counsle > settings > keys > Generate authkey. Give any description and must select resuable, because the key get purged if not selected after rebooting machine. It is advisable to create Tags in ACLs settings tag: tsdproxy
tag: ente
tag: minio
as well. This will create a tag nodes with no key expirory. One is safe to reboot restart docker or machine.
Copy the generated authkey as it is shown only once. Make tsdproxy.yaml file in
cd docker/tsdproxy/config
by runningsudo nano tsdproxy.yaml
and pupolate it with the following contant:
defaultproxyprovider: default
docker:
local:
host: unix:///var/run/docker.sock
defaultproxyprovider: default
files: {}
tailscale:
providers:
default:
authkey: ""
authkeyfile: "/config/authkey"
controlurl: https://controlplane.tailscale.com
datadir: /data/
http:
hostname: 0.0.0.0
port: 8080
log:
level: info
json: false
proxyaccesslog: true
In the same directory run sudo nano authkey
and paste the authkey just copied earlier from tailscale admin counsel.
Here Tailscale (TSDPROXY) setup is complet in all respect. Just run
docker compose up -d
. Check your tailscale amdin counsel and you will see tsdproxy node up and running. Make sure that HTTPS is enabled in tailscale DNS settings. You can visit the TSDPROXY web GUI by https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
ente Part
First make the following necessary files/directories:
sudo mkdir -p /home/ubuntu/docker/ente/custom-logs
sudo mkdir -p /home/ubuntu/docker/ente/data
sudo mkdir -p /home/ubuntu/docker/ente/minio-data
sudo mkdir -p /home/ubuntu/docker/ente/postgres-data
sudo mkdir -p /home/ubuntu/docker/ente/scripts/compose
Than give user permission for each of the above directory. sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs
etc etc. Make sure not to skip /home/ubuntu/docker/tsdproxy/config
cd docker/ente/script/compose
and run sudo nano credentials.yaml
than populate it with the following:
db:
host: postgres
port: 5432
name: ente_db
user: pguser # change me
password: pgpass #change me
s3:
are_local_buckets: true
b2-eu-cen:
key: test # change me
secret: testtest # change me
endpoint: https://minio.xyz.ts.net
region: eu-central-2
bucket: b2-eu-cen
wasabi-eu-central-2-v3:
key: test # change me
secret: testtest # change me
endpoint: localhost:3200
region: eu-central-2
bucket: wasabi-eu-central-2-v3
compliance: false
scw-eu-fr-v3:
key: test # change me
secret: testtest # change me
endpoint: localhost:3200
region: eu-central-2
bucket: scw-eu-fr-v3
In the same directory run sudo nano minio-provision.sh
and populate it with the following contant:
#!/bin/sh
# Script used to prepare the minio instance that runs as part of the development
# Docker compose cluster.
while ! mc config host add h0 http://minio:3200 test testtest #(change me)
do
echo "waiting for minio..."
sleep 0.5
done
cd /data
mc mb -p b2-eu-cen
mc mb -p wasabi-eu-central-2-v3
mc mb -p scw-eu-fr-v3
Now cd docker/ente
and run sudo nano docker-compose.yaml
and populate it with the following:
services:
museum:
image: ghcr.io/ente-io/server
ports:
- 9080:8080 # 9080 because tsdproxy is running on 8080:8080
# - 2112:2112 # Prometheus metrics
depends_on:
postgres:
condition: service_healthy
environment:
# Pass-in the config to connect to the DB and MinIO
ENTE_CREDENTIALS_FILE: /credentials.yaml
# ENTE_CLI_SECRETS_PATH: /cli-data/secret.txt
# ENTE_CLI_CONFIG_PATH: /cli-data/
volumes:
- /home/ubuntu/docker/ente/custom-logs:/var/logs
- /home/ubuntu/docker/ente/museum.yaml:/museum.yaml:ro
- /home/ubuntu/docker/ente/scripts/compose/credentials.yaml:/credentials.yaml:ro
#- /home/ubuntu/docker/ente/cli-data:/cli-data
#- /home/ubuntu/docker/ente/exports/ente-photos:/exports
- /home/ubuntu/docker/ente/data:/data:ro
networks:
- ente
- proxy
labels:
tsdproxy.enable: "true"
tsdproxy.name: "ente"
# # Resolve "localhost:3200" in the museum container to the minio container.
socat:
image: alpine/socat
network_mode: service:museum
depends_on:
- museum
command: "TCP-LISTEN:3200,fork,reuseaddr TCP:minio:3200"
postgres:
image: postgres:15
ports:
- 5432:5432
environment:
POSTGRES_USER: pguser # change me
POSTGRES_PASSWORD: pgpass # change me
POSTGRES_DB: ente_db
# Wait for postgres to be accept connections before starting museum.
healthcheck:
test:
[
"CMD",
"pg_isready",
"-q",
"-d",
"ente_db",
"-U",
"pguser" # change it accouding to the POSTGRES_USER: pguser
]
start_period: 40s
start_interval: 1s
volumes:
- /home/ubuntu/docker/ente/postgres-data:/var/lib/postgresql/data
networks:
- ente
minio:
image: minio/minio
# Use different ports than the minio defaults to avoid conflicting
# with the ports used by Prometheus.
ports:
- 3200:3200 # API
- 3201:3201 # Console
environment:
MINIO_ROOT_USER: test # change me
MINIO_ROOT_PASSWORD: testtest # change me
MINIO_SERVER_URL: https://minio.xyz.ts.net
command: server /data --address ":3200" --console-address ":3201"
volumes:
- /home/ubuntu/docker/ente/minio-data:/data
networks:
- ente
- proxy
labels:
tsdproxy.enable: "true"
tsdproxy.name: "minio"
minio-provision:
image: minio/mc
depends_on:
- minio
volumes:
- /home/ubuntu/docker/ente/scripts/compose/minio-provision.sh:/provision.sh:ro
- /home/ubuntu/docker/ente/minio-data:/data
networks:
- ente
entrypoint: sh /provision.sh
networks:
ente:
name: ente
proxy:
external: true
Thats it. Run
docker compose up -d
. Wait till every container become healthy. Open web browser. Make sure tailscale is installed on the machine. Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. First time it will take minute or two to get SSL cert. Downnload Desktop or mobile app. Tap 7 time on the screen, which will prompt developer mode. Add https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux terminal and rundocker logs ente-museum-1
. Search for userauth. Feed the six digit and Done.
For getting 100TB (limitless) storage. Just Install ente-cli for windows. Extract it and add folder. Name it export. Add config.yaml file along and populate it with the following:
endpoint:
api: "https://ente.xyz.ts.net"
accounts: "http://localhost:3001"
log: false
Right-Click in the directory where you have extracted ente-cli. Select open in terminal
. Run
.\ente.exe account bob # change bob to yours
Hit Enter twice. For export directory, just write export. As already created export folder earlier. Write email. The one which is already used befor when creating ente account in ente desktop app. Type the same Password used before for the account.Run
.\ente.ext account list
This will list all account details. Copy Acount ID.
Navigate to museum.yaml file.
cd docker/ente
. Runsudo nano museum.yaml
and add the account ID under Admins. Delete any previous entries. Restart ente-museum-1 container from linux terminal. Rundocker restart ente-museum-1
. All well, now you will have 100TB storage. Repeat if for any other accounts you want to give unlimited storage access.