Skip to content

ggfevans/jellyfin-remote-access

Jellyfin Remote Access

License: MIT Docker Nginx Tailscale CodeRabbit Pull Request Reviews

A secure, production-ready Docker-based solution for remotely accessing your home Jellyfin media server without exposing your home network directly to the internet.

Architecture Diagram

📋 Overview

This project provides a complete, production-ready implementation for securely exposing a Jellyfin media server to the internet. It solves common challenges faced by home media server enthusiasts:

  • Accessing your media when away from home
  • Sharing your media library with friends and family
  • Avoiding the security risks of direct port forwarding
  • Working around ISP restrictions (CGNAT, blocked ports, etc.)

🏗️ Architecture

The solution uses a VPS (Virtual Private Server) as a secure gateway to your home Jellyfin server:

Internet → VPS (Nginx + Let's Encrypt) ↔ Tailscale VPN ↔ Home Network (Jellyfin)

Components

  • Nginx: Reverse proxy that handles HTTPS traffic and forwards requests to Jellyfin
  • Certbot: Automatically obtains and renews Let's Encrypt SSL certificates
  • Tailscale: Creates a secure private network between your VPS and home server
  • Jellyfin: Media server running on your home network

✨ Features

  • 🔒 End-to-end encryption via Tailscale and HTTPS
  • 🚫 No ports opened on your home network
  • 📜 Automatic SSL certificate management
  • 🔄 Optimized Nginx configuration for media streaming
  • 🐳 Complete Docker Compose setup for easy deployment
  • 🛡️ Security hardening out of the box

🔧 Prerequisites

  • A VPS with a public IP address (DigitalOcean, Linode, etc.)
  • A domain name pointed to your VPS
  • Docker and Docker Compose installed on your VPS
  • Jellyfin installed on your home server
  • Tailscale account and configured tailnet
  • Basic familiarity with the command line and Docker

🚀 Quick Start

  1. Clone this repository to your VPS:

    git clone https://github.com/ggfevans/jellyfin-remote-access.git
    cd jellyfin-remote-access
  2. Copy the example configuration files:

    cp .env.example .env
    cp tailscale.env.example tailscale.env
    cp init-letsencrypt.sh.example init-letsencrypt.sh
    chmod +x init-letsencrypt.sh
  3. Set up your Tailscale network:

    • Create a Tailscale account at https://tailscale.com
    • Install Tailscale on your home Jellyfin server
    • Generate an auth key in the Tailscale admin console
    • Update tailscale.env with your hostname and auth key
  4. Configure your environment:

    • Edit .env with your domain and email
    • Update the Jellyfin Tailscale IP in .env
    • Edit init-letsencrypt.sh with your domain
  5. Initialize SSL certificates:

    ./init-letsencrypt.sh
  6. Start the services:

    docker compose up -d
  7. Visit your domain in a web browser to access Jellyfin!

📝 Detailed Setup Guide

1. Domain Configuration

Update your domain settings in the following files:

  • init-letsencrypt.sh - Set domains array
  • data/nginx/app.conf - Replace yourdomain.com with your domain
  • nginx/jellyfin.conf - Replace your_domain.com with your domain

2. Tailscale Configuration

The Tailscale container creates a secure tunnel between your VPS and home network:

  1. Edit tailscale.env:

    TS_HOSTNAME=your_tailscale_hostname
    TS_AUTHKEY=tskey-auth-yourauthkeyhere
    
  2. Make sure Jellyfin on your home network is reachable via Tailscale:

    • Install Tailscale on your home Jellyfin server
    • Note the Tailscale IP address (e.g., 100.x.y.z)
  3. Update nginx/jellyfin.conf to point to your Jellyfin Tailscale IP:

    set $upstream_jellyfin "http://100.x.y.z:8096";
    

3. Nginx Configuration

The included configurations are already optimized for Jellyfin, but you may need to adjust:

  • moz_ssl - SSL parameters based on Mozilla's recommendations
  • proxy_params - Proxy settings for Jellyfin
  • website.conf - Main Nginx configuration for your domain

4. Certificate Initialization

Run the initialization script to set up Let's Encrypt:

chmod +x init-letsencrypt.sh
./init-letsencrypt.sh

This script will:

  • Create a temporary Nginx configuration
  • Obtain initial certificates from Let's Encrypt
  • Set up automatic renewal

5. Starting the Stack

Launch all services:

docker compose up -d

Verify all containers are running:

docker compose ps

🔍 Troubleshooting

Certificate Issues

If Certbot fails to obtain certificates:

  • Ensure your domain is correctly pointed to your VPS
  • Check that ports 80 and 443 are open on your VPS
  • Examine Certbot logs: docker compose logs certbot

Connection Problems

If you can't connect to Jellyfin:

  • Verify Tailscale is connected on both the VPS and home server
  • Check Tailscale connectivity: tailscale ping your-jellyfin-hostname
  • Ensure Jellyfin is accessible directly via its Tailscale IP
  • Examine Nginx logs: docker compose logs nginx

Streaming Issues

If videos buffer or play poorly:

  • Check your home upload bandwidth
  • Adjust Jellyfin transcoding settings
  • Consider modifying Nginx buffer settings in proxy_params

🛡️ Security Considerations

This setup provides several security advantages:

  • No open ports on your home network
  • End-to-end encryption between VPS and home server
  • HTTPS encryption for all external traffic
  • Isolated containers with minimal permissions
  • Content Security Policy headers to prevent XSS attacks

Additional hardening you might consider:

  • Setting up SSH key-only authentication on your VPS
  • Configuring a firewall (UFW) on your VPS
  • Enabling rate limiting in Nginx for login attempts
  • Regular security updates for all components

📚 Advanced Configuration

Custom Error Pages

Custom error pages are located in data/nginx/html/. You can modify:

  • 404.html - Not found errors
  • maintenance.html - Displayed during maintenance

Nginx Optimization

The included Nginx configuration is optimized for media streaming, with:

  • Efficient proxy buffering
  • Connection keep-alive settings
  • Browser caching for static assets
  • Gzip compression

Multiple Domains

To add additional domains:

  1. Update the domains array in init-letsencrypt.sh
  2. Add server blocks for each domain in data/nginx/website.conf
  3. Run the initialization script again

🔄 Updating

To update the components:

docker compose pull
docker compose down
docker compose up -d

📊 Monitoring

Consider adding these monitoring solutions:

🤝 Contributing

Contributions are welcome! Please read our Contributing Guidelines and Code of Conduct before submitting a Pull Request.

Reporting Issues

  • Check existing issues before creating a new one
  • Use the issue templates provided
  • Include logs and configuration (without sensitive data)

Development

See CONTRIBUTING.md for development setup instructions.

🔒 Security

For security concerns, please read our Security Policy.

📜 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgements

📞 Support

About

No description or website provided.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks