İçeriğe Atla
MS Mehmet Sarı Solution architecture notes

I Deleted Google Photos: All My Memories to My Own Server with Immich

I'm sharing my migration process from Google Photos to my own server with Immich, including the reasons, setup steps, and challenges I faced.

100%

It had been on my mind for a long time: taking my digital memories, my photos and videos, out of the hands of cloud services and bringing them completely under my own control. The conveniences offered by Google Photos were undeniable, but over time, data privacy and vendor lock-in issues began to bother me. Especially the changes in free storage limits and future uncertainties were factors that accelerated this decision.

Finally, I made my decision and completed this transition. In this post, I will share why I left Google Photos, why I chose an open-source solution called Immich, how I set it up on my own server, how I transferred my data, and the technical details and lessons learned during this process. My goal is to provide a practical guide for those who want to manage their own digital assets.

Why My Own Photo Server? My Reasons for Leaving Google

It’s true that our lives have become easier with the proliferation of cloud services. Google Photos, especially when it offered unlimited storage, was the top choice for many of us. However, this situation changed over time, and some red lines became apparent for me.

The first reason was data privacy and control. Our photos are our special memories, our personal data. Storing them on a large company’s servers, under their terms, never gave me complete confidence. Aside from issues like ad targeting or data analysis, the lack of complete control over my data was unacceptable, especially for someone who has been dealing with system security as an MSP for years. On my own server, I determine where my data is, who can access it, and under what conditions it is processed.

The second major factor was the risk of long-term cost and vendor lock-in. Google Photos’ abandonment of its free unlimited storage model concretized this risk. Companies can change their policies and revise their pricing over time. Let’s say you pay a small amount today, but five years from now, this amount could increase exponentially. Moving millions of photos elsewhere is both time-consuming and technically exhausting. This was a situation that made me dependent on a single provider, and I wanted to break free from this dependency.

A third reason was performance and feature limitations. Situations like the compression of videos of a certain size or the inability to preserve original quality bothered me. On my own server, I can keep everything in its original quality as long as my storage space allows. Furthermore, the lack of transparency regarding how AI-powered features like tagging and facial recognition are processed in the cloud was also a question mark. Accessing similar features on my own server with open-source Immich alleviated these concerns.

In light of these reasons, I decided to take my photo and video archive from the cloud and move it to my own server. This was not just a technical transition but also an important step towards digital independence.

First Look at Immich: Why I Chose This Solution

After deciding to leave Google Photos, I started researching alternatives on the market. I had important criteria: it had to be open source, have an active development process, have mobile applications, and support modern features (like AI tagging, facial recognition). After reviewing several different solutions, Immich stood out because it met most of these criteria and then some.

Firstly, being open source was a fundamental requirement for me. I can examine the code, get community support, and influence the future direction of development. This offers much more flexibility and transparency than closed-source software. Immich’s GitHub repository is very active, which indicates that the project is alive and constantly being improved.

Secondly, Immich’s rich feature set impressed me. Thanks to its mobile applications, I can automatically back up photos, create albums, and easily manage my memories. Most of the features offered by Google Photos (search, sharing, map view) can also be found in Immich. Especially the AI-powered tagging and facial recognition features are quite successful despite running on my own server. These features make searching through thousands of photos much easier. For example, I can quickly find relevant photos with keywords like “cats” or “birthday.”

Thirdly, its technical architecture and ease of installation were also important. Immich has a microservices-based architecture that can be easily deployed with Docker Compose. It consists of components such as a PostgreSQL database, Redis, Nginx (as a reverse proxy), machine learning services, and the main application server. This modular structure provides scalability and ease of maintenance when needed. Since I manage many of my services with Docker Compose, Immich’s structure was not unfamiliar to me.

Alternatively, there were solutions like PhotoPrism and Nextcloud Photos. While PhotoPrism is a powerful photo management tool, its mobile app experience and AI features were not as advanced as Immich’s. Nextcloud Photos works well as part of the Nextcloud ecosystem, but since I was looking for a photo-focused solution, I thought Immich was more optimized.

In short, Immich turned out to be a solution that was technically robust, feature-rich, and aligned with the open-source philosophy for me. I am quite satisfied with this choice.

Preparing the Infrastructure: Installation with Docker Compose

To install Immich on my own server, I leveraged my existing infrastructure. Since I typically run my systems on a VPS (Virtual Private Server) with Docker Compose, Immich fit perfectly into this setup. The installation process was quite straightforward when following the correct steps.

First, you need to choose a suitable server for Immich. My preference was a VPS with sufficient disk space (this varies depending on your photo archive; I needed several TBs) and enough CPU power for machine learning operations. For example, I recommend at least 8GB RAM and a 4-core CPU for a typical setup. On the disk side, choosing an NVMe SSD or a high-performance SATA SSD based on the size of your photos will improve performance, especially during thumbnail generation and search operations. I use Ubuntu Server LTS as the operating system.

Before starting the installation, I made sure Docker and Docker Compose were installed on my server. If not installed, you can quickly install them with the following commands:

# Docker installation
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io -y

# Docker Compose installation (I usually prefer the latest version)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Once Docker and Docker Compose were ready, I downloaded the docker-compose.yml file provided by Immich’s own documentation and made minor adjustments according to my needs. This file defines all Immich components (server, microservices, web interface, machine learning, PostgreSQL, Redis).

An example docker-compose.yml structure might look like this:

version: "3.8"

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:release
    command: ["start-server.sh"]
    volumes:
      - /path/to/your/upload_location:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env
    ports:
      - 2283:3001 # Internal port for Immich API
    restart: always

  immich-microservices:
    container_name: immich_microservices
    image: ghcr.io/immich-app/immich-microservices:release
    command: ["start-microservices.sh"]
    volumes:
      - /path/to/your/upload_location:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env
    restart: always

  immich-web:
    container_name: immich_web
    image: ghcr.io/immich-app/immich-web:release
    env_file:
      - .env
    restart: always

  immich-machine-learning:
    container_name: immich_machine_learning
    image: ghcr.io/immich-app/immich-machine-learning:release
    env_file:
      - .env
    restart: always

  postgres:
    container_name: immich_postgres
    image: postgres:15
    environment:
      POSTGRES_USER: immich
      POSTGRES_PASSWORD: your_strong_password
      POSTGRES_DB: immich
    volumes:
      - /path/to/your/postgres_data:/var/lib/postgresql/data
    restart: always

  redis:
    container_name: immich_redis
    image: redis:6.2-alpine
    restart: always

In this file, I replaced /path/to/your/upload_location and /path/to/your/postgres_data with the paths to my persistent storage areas on my server. Additionally, I defined the environment variables Immich needed (e.g., database connection information, API keys, etc.) in the .env file. For security, I made sure to change your_strong_password to a unique and strong password.

After all these preparations were complete, I ran the docker compose up -d command in the directory where the docker-compose.yml file was located to bring Immich online. The services started running within a few minutes. On the first run, Immich creates the database schema and starts all necessary components. I then set up an Nginx reverse proxy to provide external HTTPS access to Immich; you can refer to my posts on “Nginx reverse proxy” for more on this.

After installation, I accessed the Immich web interface, created my first user account, and checked if the system was working correctly. From this point, I was ready to move on to the main task: data transfer.

Data Transfer and Synchronization: From Google Takeout to Immich

After completing the Immich setup, the most critical stage was to safely and completely transfer all my memories from Google Photos to my own server. This process required a bit more attention and manual intervention than I expected.

The first step was to download my data from Google Photos using Google Takeout. Google Takeout is a tool that allows you to download your data from Google services in bulk. From there, I selected only Google Photos and requested to download my entire archive as ZIP or TGZ files. My archive was quite large, so the download took several days and was split into multiple parts.

After transferring the downloaded files to my server, the real challenge began. Google Takeout downloads not only photos but also a separate JSON file (with a .json extension) for each photo. These JSON files contain metadata such as the date the photo was taken, location information, and album information. For Immich to process this metadata correctly, the photos and their corresponding JSON files needed to be correctly matched.

The main issues I encountered were:

  1. JSON Metadata Matching: There was a JSON file for each photo (e.g., IMG_1234.jpg and IMG_1234.jpg.json). However, in some cases, filenames didn’t match or JSON files were missing.
  2. Date and Time Information: The filenames of some photos did not reflect the original capture date. It was necessary to correct this information using fields like photoTakenTime or creationTime in the JSON files.
  3. Duplicate Files: There could be duplicate files due to backups or uploads from different devices that accumulated in Google Photos over time.
  4. Folder Structure: Google Takeout downloaded data in folders organized by year and month, but this structure was not directly ideal for Immich.

To solve these problems, I used Immich’s own CLI tool (immich-cli). The immich-cli tool is very useful for uploading photos from your local disk to the Immich server. Options like --dedupe (to remove duplicates) and --album (to create an album during upload) made my job easier.

The basic steps I used to transfer my data were:

  1. Preparing the Data: I extracted the downloaded Google Takeout archives to a temporary directory on my server (/mnt/google_takeout_import).

  2. Metadata Processing (Optional but Important): For some older photos, I used tools like exiftool to correct metadata. For example, writing the creationTime information from the JSON file to the photo’s EXIF data:

    # Example: Writing the date from JSON to a JPG file with exiftool
    # This command checks for the existence of the corresponding JSON file.
    find /mnt/google_takeout_import -name "*.jpg" -print0 | while IFS= read -r -d $'\0' file; do
        json_file="${file}.json"
        if [ -f "$json_file" ]; then
            creation_time=$(jq -r '.photoTakenTime.timestamp' "$json_file" | xargs -I {} date -d @{} +"%Y:%m:%d %H:%M:%S")
            if [ -n "$creation_time" ]; then
                exiftool -overwrite_original "-DateTimeOriginal=$creation_time" "-CreateDate=$creation_time" "$file"
            fi
        fi
    done

    This script checks the corresponding JSON file for each JPG file and reads the photoTakenTime.timestamp field to write it to the photo’s DateTimeOriginal and CreateDate EXIF tags. This ensures Immich receives correct date information. The jq and exiftool packages must be installed.

  3. Uploading to Immich: I uploaded the photos using the Immich CLI tool. Uploading large folders in chunks made the process more manageable in case of potential disconnections or errors.

    # Immich CLI installation (if not installed)
    npm install -g @immich-app/cli
    
    # Immich CLI upload command
    immich upload --recursive --dedupe --album "Google Takeout Import" /mnt/google_takeout_import/

    I used --recursive to scan subfolders, --dedupe to skip files already in Immich, and --album to add all these files to an album named “Google Takeout Import.” This made it easier for me to organize after the transfer.

After these steps, thousands of my photos and videos were successfully transferred to my Immich server. The initial synchronization and thumbnail generation took some time, but eventually, all my memories were securely on my own server, under my control.

Security and Backup Strategies

Setting up my own photo server not only meant retrieving my data from Google but also entirely entrusting me with the responsibility of ensuring the security and continuity of this data. As an MSP, I pay particular attention to this issue. Without a good security and backup strategy, self-hosting has no meaning.

Security Layers

The security measures I implemented for my Immich server consist of several layers:

  1. Network Level Firewall: I use a firewall (e.g., ufw or a hardware firewall like Sophos XGS) in front of my server. I only opened the necessary ports (e.g., 80 and 443 for Nginx) to the outside world. Instead of directly exposing Immich’s own port 3001, I placed it behind an Nginx reverse proxy. This reduces the attack surface by preventing direct access.
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable
    These commands open HTTP and HTTPS ports on my server. Access to Docker services on the internal network is provided only through Nginx.
  2. Nginx Reverse Proxy and SSL/TLS: I use Nginx reverse proxy for external access to the Immich web interface and API. Nginx acts as both a load balancer and a security layer. Most importantly, I encrypt all communication with free SSL/TLS certificates provided by Let’s Encrypt. This guarantees encrypted data transfer.
    server {
        listen 80;
        server_name immich.mydomain.com;
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name immich.mydomain.com;
    
        ssl_certificate /etc/letsencrypt/live/immich.mydomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/immich.mydomain.com/privkey.pem;
    
        location / {
            proxy_pass http://localhost:2283; # Immich internal API port
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            client_max_body_size 5000M; # Max upload size
            proxy_read_timeout 300s;
            proxy_send_timeout 300s;
        }
    }
    This Nginx configuration redirects all HTTP requests to HTTPS, uses SSL certificates, and securely proxies to the Immich service. I increased values like client_max_body_size and proxy_read_timeout for smooth uploading of large photo/video files.
  3. Strong Passwords and User Management: I use strong, unique passwords for my user accounts on Immich. I will enable Multi-factor authentication (MFA) as soon as it becomes available. Additionally, I use SSH keys instead of passwords for SSH access to the server and regularly check logs.
  4. Keeping Up-to-Date: I regularly keep the operating system and Docker containers updated. This is vital for patching known security vulnerabilities. I regularly run docker compose pull && docker compose up -d to keep Immich containers updated.

Backup Strategies

Backup is the only way to recover your data in case of a disaster. For me, the 3-2-1 rule is the gold standard: 3 copies of data, on 2 different media, with 1 copy offsite.

  1. Immich Database Backup: Immich stores all metadata in a PostgreSQL database. Regularly backing up this database is critical. I take a copy of the database once a day using pg_dump.
    # Taking a PostgreSQL database backup
    docker exec immich_postgres pg_dump -U immich immich > /path/to/backup/db_backup_$(date +%Y%m%d%H%M%S).sql
    This command takes a dump of the immich database within the immich_postgres container and saves it to the specified backup directory.
  2. Photo and Video File Backup: All photo and video files uploaded by Immich are stored in the upload directory. This directory must also be regularly backed up. I back up this directory to an offsite storage area with Acronis. Acronis offers a very flexible and reliable solution for image and file backups. I also take snapshots of these files on my Synology NAS.
  3. Offsite Backup: Local backups are important, but you need an offsite backup to protect against situations like fire, theft, or hardware failure. I transfer both my database backup and photo files securely to cloud storage (e.g., Backblaze B2 or an S3-compatible service). Tools like rclone are very useful for this.
    # Offsite backup with rclone (example)
    rclone sync /path/to/backup remote:immich-backups --log-file=/var/log/rclone-immich.log
    This command synchronizes my local backup directory with a remote storage area. remote here is a configured rclone target.

Thanks to these security and backup strategies, I can be sure that my memories on my Immich server are safe. Managing my own data also means taking the necessary steps to protect that data.

Performance Improvements and Maintenance Tips

Running a photo management system like Immich on your own server is a task that requires performance and continuous maintenance. Especially when dealing with thousands of photos and videos, it becomes inevitable to apply certain optimizations and regular maintenance routines to ensure the system runs smoothly.

Performance Improvements

  1. Storage I/O Optimization: Photo and video files require intensive disk I/O, especially during thumbnail generation and search operations. Therefore, using a high-speed SSD (NVMe preferred) as the main storage significantly improves performance. Having the PostgreSQL database on an SSD also improves the speed of metadata queries.
    • For example, when I moved a 100GB photo library to an NVMe SSD, the initial indexing and thumbnail generation times decreased by approximately 30-40% compared to a SATA SSD.
  2. CPU and RAM Resources: Immich’s machine learning component (immich-machine-learning) and microservices (immich-microservices) heavily utilize the CPU during intensive tasks like facial recognition and object detection. Sufficient CPU cores (at least 4-6 cores) and RAM (at least 8-16GB, depending on library size) are crucial.
Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

MS

Mehmet Sarı

Çözüm Mimarı & IT Altyapı Uzmanı (MSP)

Çözüm mimarisi, network, sunucu altyapıları, yedekleme, storage, güvenlik ve MSP operasyonu ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Comments

Server-side AI Moderation

Comments are AI-moderated server-side and stored permanently.

?
0/2000

Server-side AI moderation

✉️ Free · No spam · Unsubscribe anytime

Curated digest, hand-picked by me — not the AI

Once a week: the most important post of the week, behind-the-scenes notes, and a "what I actually used this week" section. Less noise, more signal.

  • 📌
    Best of the week Single most-worth-reading post
  • 🔧
    Toolbox notes Real tools I used this week
  • 🧠
    Behind-the-scenes Notes that don't make it to blog

We don't spam. Unsubscribe anytime. · Tracked only by Umami (self-hosted, no Google).

Your Reading Stats

0

Posts Read

0m

Reading Time

0

Day Streak

-

Favorite Category

Related Posts