Self hosted

Best Self-hosted Apps in 2023

Dive into the best self-hosted apps of 2023, including media servers, password managers, and other tools to take control of your data

You can run many great self-hosted apps in your home lab or on your media server with only a small amount of tinkering. Let’s look at the best self-hosted apps in 2023 and a list of apps you should check out.

1. Plex

Plex is a self-hosted app that if you are going to self-host anything, normally plex is on that list of self-hosters and home labbers. It is one of the self-hosted apps for media that includes many features, even in the free version so you can stream movies, TV shows, and home videos.

01 plex media server
01 plex media server

Pros:

  • Good device compatibility for accessing media

  • Advanced features including analytics.

  • Allows managing large media libraries easily

Cons:

  • Premium features are locked behind a paywall.

  • Not entirely open-source.

Docker Compose:

version: '3'
services:
  plex:
    image: plexinc/pms-docker:latest
    ports:
      - "32400:32400"
    volumes:
      - /path/to/plex/database:/config
      - /path/to/media:/data

2. Jellyfin

Jellyfin offers a free media server solution, ensuring users maintain full control over their media and avoid streaming services with ads.

02 jellyfin open source media
02 jellyfin open source media

Pros:

  • Fully open-source.

  • No premium walls, every feature is accessible from the start.

  • Active community support, including regular updates and security patches.

Cons:

  • Lacks some of the polish and features of its competitors.

  • It might require additional configuration for reverse proxy setups, but this is true of many solutions.

Docker Compose:

version: '3'
services:
  jellyfin:
    image: jellyfin/jellyfin
    ports:
      - "8096:8096"
    volumes:
      - /path/to/config:/config
      - /path/to/cache:/cache
      - /path/to/media:/media

3. Emby

For those wanting an alternative to Plex but still desiring some premium features, Emby strikes a balance between functionality and cost.

03 emby open source media contender
03 emby open source media contender

Pros:

  • Offers live TV support and other nice features

  • Integrates with cloud services for backup and sync.

  • A User-friendly interface allows even non tech-savvy users to self-host their media.

Cons:

  • While it has a free version, some features are behind a paywall.

  • Requires periodic server management for optimal performance.

Docker Compose:

version: "2.3"
services:
  emby:
    image: emby/embyserver
    container_name: embyserver
    runtime: nvidia # Expose NVIDIA GPUs
    network_mode: host # Enable DLNA and Wake-on-Lan
    environment:
      - UID=1000 # The UID to run emby as (default: 2)
      - GID=100 # The GID to run emby as (default 2)
      - GIDLIST=100 # A comma-separated list of additional GIDs to run emby as (default: 2)
    volumes:
      - /path/to/programdata:/config # Configuration directory
      - /path/to/tvshows:/mnt/share1 # Media directory
      - /path/to/movies:/mnt/share2 # Media directory
    ports:
      - 8096:8096 # HTTP port
      - 8920:8920 # HTTPS port
    devices:
      - /dev/dri:/dev/dri # VAAPI/NVDEC/NVENC render nodes
      - /dev/vchiq:/dev/vchiq # MMAL/OMX on Raspberry Pi
    restart: on-failure

4. Nextcloud

Nextcloud stands out as one of the best self-hosted apps for users looking to have control over their files. It provides file sync and a number of apps for calendar, contacts, notes, and other services, making it a hub for all your cloud services.

04 nextcloud self hosted cloud storage
04 nextcloud self hosted cloud storage

Pros:

  • Offers an all-in-one solution: file sync, calendars, contacts, and other apps.

  • Supports multiple users, and can be used for businesses or families.

  • Provides end-to-end encryption for sensitive information.

Cons:

  • Might require some initial server setup and maintenance.

  • Increasing capacity may require hardware upgrades.

Docker Compose:

version: '2'

volumes:
  nextcloud:
  db:

services:
  db:
    image: mariadb:10.6
    restart: always
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    volumes:
      - db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=
      - MYSQL_PASSWORD=
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

  app:
    image: nextcloud
    restart: always
    ports:
      - 8080:80
    links:
      - db
    volumes:
      - nextcloud:/var/www/html
    environment:
      - MYSQL_PASSWORD=
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=db

5. Home Assistant

There really is a name in home automation that keeps coming up if you are looking at doing this in a self-hosted way and that is Home Assistant. Home Assistant is a tool for home automation that allows you to control many devices and different types of solutions, and have full control over your home environment.

05 home assistant home automation software
05 home assistant home automation software

Pros:

  • Vast compatibility with many smart devices.

  • Allows for complex automation.

  • Active community and constant updates.

Cons:

  • It might require additional configuration, especially for non-standard devices.

  • Learning curve for beginners.

Docker Compose:

services:
  homeassistant:
    image: lscr.io/linuxserver/homeassistant:latest
    container_name: homeassistant
    network_mode: host
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /path/to/data:/config
    ports:
      - 8123:8123 #optional
    devices:
      - /path/to/device:/path/to/device #optional
    restart: always

6. Bitwarden

If you want to self-host a password manager there are a few that allow you to do this. However, Bitwarden is one of the best that you will find. It lets you have a self-hosted solution to store and manage all your passwords in one place and you control the storage and access.

Take a look at my writeup on Bitwarden Unified Docker installation here: Bitwarden Unified Docker installation self-hosted password manager.

06 bitwarden open source password manager
Bitwarden open source password manager

Pros:

  • Enables two-factor authentication for added security.

  • Can be accessed from any browser or device.

  • Open-source and transparent.

Cons:

  • Setup requires an understanding of security best practices.

  • Dependency on internet access for external access

Docker Compose:

version: '3.3'

services:
  traefik2:
    image: traefik:latest
    restart: always
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
    ports:
      - 80:80
      - 443:443
    networks:
      traefik:
        ipv4_address: 172.19.0.10
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    container_name: traefik

  bitwarden:
    depends_on:
      - db
    env_file:
      - '~/homelabservices/bitwarden/settings.env'
    image: bitwarden/self-host:beta
    restart: always
    networks:
      traefik:
        ipv4_address: 172.19.0.20
    volumes:
      - '~/homelabservices/bitwarden/data:/etc/bitwarden'
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.bitwarden.rule=Host(`bitwarden.cloud.local`)"
      - "traefik.http.routers.bitwarden.tls=true"
      - "traefik.http.routers.bitwarden.entrypoints=websecure"
      - "traefik.http.services.bitwarden.loadbalancer.server.port=8080"
    container_name: bitwarden

  db:
    environment:
      MARIADB_USER: "bitwarden"
      MARIADB_PASSWORD: "password"
      MARIADB_DATABASE: "bitwarden_vault"
      MARIADB_RANDOM_ROOT_PASSWORD: "true"
    image: mariadb:10
    restart: always
    networks:
      traefik:
        ipv4_address: 172.19.0.30
    volumes:
      - '~/homelabservices/mariadb/data:/var/lib/mysql'
    container_name: mariadb

      
networks:
  traefik:
    driver: bridge
    name: traefik
    ipam:
      driver: default
      config:
        - subnet: 172.19.0.0/16

7. Ghost

Ghost, as a blogging platform, offers a slick and modern way for creators to self-host their content. It provides a minimalist design that emphasizes content and readability.

07 ghost blogging platform
07 ghost blogging platform

Pros:

  • SEO-friendly out of the box.

  • Easily integrates with various services like Google Analytics.

  • Supports multiple users for team blogs or businesses.

Cons:

  • Lacks some of the plugins and themes available to more mature platforms like WordPress.

  • Initial configuration can be challenging for non-technical users.

Docker Compose:

version: '3.1'

services:

  ghost:
    image: ghost:4-alpine
    restart: always
    ports:
      - 8080:2368
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      # this url value is just an example, and is likely wrong for your environment!
      url: http://localhost:8080
      # contrary to the default mentioned in the linked documentation, this image defaults to NODE_ENV=production (so development mode needs to be explicitly specified if desired)
      #NODE_ENV: development

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

8. Gitea

Gitea provides a modern way to manage your code repositories without relying on external services. It provides many features for a self-hosted version control system.

08 gitea self hosted git service
08 gitea self hosted git service

Pros:

  • Lightweight and speedy compared to similar platforms.

  • Comes with a built-in issue-tracking system.

  • Compatible with most CI/CD systems out of the box.

Cons:

  • Fewer features when compared to giants like GitHub or GitLab.

  • UI might seem minimalistic for those used to more elaborate platforms.

Docker Compose:

version: "3"

networks:
  gitea:
    external: false

services:
  server:
    image: gitea/gitea:1.20.5
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"

9. Grafana

For those who understand the need to track server health, user statistics, Kubernetes clusters, and even Google Analytics data, Grafana is the de facto standard for open-source dashboard monitoring tools.

09 grafana self hosted visualization tool
09 grafana self hosted visualization tool

Pros:

  • Highly customizable dashboards.

  • Integrates seamlessly with multiple data sources, including cloud services.

  • An active community providing plugins, free dashboards, and features regularly.

Cons:

  • Requires some initial setup and knowledge to harness its capabilities fully.

  • It can be overwhelming for beginners due to its many features and configuration possibilities.

Docker Compose:

version: '3'
services:
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - /path/to/grafana/data:/var/lib/grafana

10. Dashy

When running many self-hosted home services, you need a way to keep up with access to these services, especially when they may exist on non-standard ports across various container hosts. Dashy offers a customizable start page to keep everything in the same place. Think of it as your central hub on the web.

10 dashy dashboard for self hosted home lab services
10 dashy dashboard for self hosted home lab services

Read my writeup on Dashy dashboard here: Home lab dashboard with Dashy.

Pros:

  • Simplistic design ensures quick access to your most-used services.

  • Mobile-friendly out of the box.

  • Ability to integrate with multiple users.

Cons:

  • May be overwhelming to setup for beginners

  • Dependence on active internet connectivity for external access

Docker Compose:

version: "3.8"
services:
  dashy:
    # To build from source, replace 'image: lissy93/dashy' with 'build: .'
    # build: .
    image: lissy93/dashy
    container_name: Dashy
    # Pass in your config file below, by specifying the path on your host machine
    # volumes:
      # - /root/my-config.yml:/app/public/conf.yml
    ports:
      - 4000:80
    # Set any environmental variables
    environment:
      - NODE_ENV=production
    # Specify your user ID and group ID. You can find this by running `id -u` and `id -g`
    #  - UID=1000
    #  - GID=1000
    # Specify restart policy
    restart: unless-stopped
    # Configure healthchecks
    healthcheck:
      test: ['CMD', 'node', '/app/services/healthcheck']
      interval: 1m30s
      timeout: 10s
      retries: 3
      start_period: 40s

11. Homarr

Like Dashy, Homarr provides a visually appealing and efficient way to manage and monitor your self-hosted apps from one place. It is designed for users with numerous self-hosted services and gives you complete control over how your dashboard looks and functions.

11 homarr dashboard for home lab services
11 homarr dashboard for home lab services

Pros:

  • At-a-glance overview of all your services in one unified platform.

  • Supports integration with multiple users

  • Frequent updates and an active community behind it.

Cons:

  • It might be overkill for those with only a few services.

  • Some setup is required to maximize what it can do.

Docker Compose:

version: '3'
#---------------------------------------------------------------------#
#     Homarr - A simple, yet powerful dashboard for your server.     #
#---------------------------------------------------------------------#
services:
  homarr:
    container_name: homarr
    image: ghcr.io/ajnart/homarr:latest
    restart: unless-stopped
    volumes:
      - ./homarr/configs:/app/data/configs
      - ./homarr/icons:/app/public/icons
    ports:
      - '7575:7575'

12. Uptime Kuma

Uptime Kuma lets you track the uptime of your services, making sure you are always aware of any downtime or issues. Think of it as your personal watchdog for your hosted apps and services.

12 uptime kuma monitoring of self hosted services
12 uptime kuma monitoring of self hosted services

Pros:

  • Provides detailed reports, including historical data.

  • Supports multiple notification methods.

  • Two-factor authentication for added security.

Cons:

  • Requires a dedicated local server or cloud instance to run.

  • It might be redundant if you are using other monitoring tools.

Docker Compose:

version: '3.8'

services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    volumes:
      - uptime-kuma:/app/data
    ports:
      - "3001:3001"  # <Host Port>:<Container Port>
    restart: always

volumes:
  uptime-kuma:

13. RSS

A simple RSS feed aggregator that supports RSS and ATOM formats, auto-fetching, custom feed names and colors, the ability to hide feed posts by default, etc.

13 rss is a self hosted rss feed aggregator
13 rss is a self hosted rss feed aggregator

Pros:

  • Feed-based tags for categorization

  • 3 different post layout modes (card, list, compact).

  • Cross-device synchronization ensures you pick up where you left off.

Cons:

  • No import of full post/article content.

  • No authentication or authorization built-in.

Docker Compose:

version: "2"
services:
    rss:
        image: ghcr.io/ssddanbrown/rss:latest
        container_name: rss
        environment:
            - APP_NAME=RSS
        volumes:
            - ./rss-files:/app/storage
        ports:
            - "8080:80"
        restart: always

14. Appwrite

For those looking to easily manage backend services and databases, Appwrite is a great self-hosted end-to-end server for web and mobile developers.

14 appwrite is a self hosted tool for writing apps
14 appwrite is a self hosted tool for writing apps

Pros:

  • All-in-one platform: database, authentication, cloud functions, and more.

  • Supports multiple users, ideal for collaborative projects.

  • Regular updates with new features and security patches.

Cons:

  • Might require a steeper learning curve for those unfamiliar with backend development.

  • Requires regular maintenance to ensure optimal performance.

Docker:

docker run -it --rm 
    --volume /var/run/docker.sock:/var/run/docker.sock 
    --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw 
    --entrypoint="install" 
    appwrite/appwrite:1.4.5

15. Bookstack

Bookstack is a knowledge management Wiki for creating documentation. It offers a platform to create, organize, and store documentation with a WYSIWYG editor. It is powered by SQL and includes Markdown support.

15 bookstack is an open source self hosted wiki
15 bookstack is an open source self hosted wiki

Pros:

  • Hierarchical structure: books, chapters, and pages.

  • Rich text editor with Markdown support.

  • Integrates easily with services like Google Analytics for traffic insights.

Cons:

  • The interface might seem complex to some users.

  • Requires regular backups to prevent potential data loss.

Docker Compose:

---
version: "2"
services:
  bookstack:
    image: lscr.io/linuxserver/bookstack
    container_name: bookstack
    environment:
      - PUID=1000
      - PGID=1000
      - APP_URL=https://bookstack.example.com
      - DB_HOST=bookstack_db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=<yourdbpass>
      - DB_DATABASE=bookstackapp
    volumes:
      - ./bookstack_app_data:/config
    ports:
      - 6875:80
    restart: unless-stopped
    depends_on:
      - bookstack_db
  bookstack_db:
    image: lscr.io/linuxserver/mariadb
    container_name: bookstack_db
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=<yourdbpass>
      - TZ=Europe/London
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=<yourdbpass>
    volumes:
      - ./bookstack_db_data:/config
    restart: unless-stopped

16. Audiobookshelf

Audiobookshelf is a media server tailored for audiobook and podcast enthusiasts. The app lets users stream their audiobook collection from anywhere, transforming devices into personal libraries.

16 audiobookshelf is a self hosted solution for audio and podcast enthusiasts
16 audiobookshelf is a self hosted solution for audio and podcast enthusiasts

Pros:

  • Supports multiple users with individual progress tracking.

  • Integration with Google Analytics offers insights into listening habits.

  • Web player allows for streaming across devices.

Cons:

  • Limited to audio content, unlike other comprehensive media servers.

  • Reliant on proper metadata for efficient book management.

Docker Compose:

version: "3.7"
services:
  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    ports:
      - 13378:80
    volumes:
      - </path/to/audiobooks>:/audiobooks
      - </path/to/podcasts>:/podcasts
      - </path/to/config>:/config
      - </path/to/metadata>:/metadata

17. Pi-hole

Pi-hole is the de facto standard in ad-blocking at home for those who self-host services. It stands out by offering network-wide ad-blocking rather than just blocking ads in your browser. It makes sure devices connected to the network are free from advertisements and trackers and also helps to block malicious sites and malware.

17 pihole is a premier self hosted ad blocking solution
17 pihole is a premier self hosted ad blocking solution

Pros:

  • Network-wide blocking ensures no device is left out.

  • Detailed dashboards allow users to track blocked requests.

  • Can be installed on lightweight devices like a Raspberry Pi, offering energy-efficient operation.

Cons:

  • Requires a constant local server connection.

  • It might occasionally block non-ad websites if not correctly configured.

Docker Compose:

version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    # For DHCP it is recommended to remove these ports and instead add: network_mode: "host"
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp" # Only required if you are using Pi-hole as your DHCP server
      - "80:80/tcp"
    environment:
      TZ: 'America/Chicago'
      # WEBPASSWORD: 'set a secure password here or it will be random'
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN # Required if you are using Pi-hole as your DHCP server, else not needed
    restart: always

18. Adguard Home

Similar in concept to Pi-hole, Adguard Home offers self-hosters a way to secure their local network. It blocks advertisements and protects against phishing websites and malicious domains.

Read my full write up on Adguard Home here: Adguard Home Docker Compose with Traefik Ingress.

18 adguard home is another great self hosted ad blocking solution
18 adguard home is another great self hosted ad blocking solution

Pros:

  • Advanced security features to protect devices on the network.

  • User-friendly interface with detailed statistics.

  • Flexible configuration options, including custom filtering rules.

Cons:

  • Slightly more resource-intensive compared to Pi-hole.

  • Needs regular updating to keep the malicious domain list current.

Docker Compose:

version: '3.3'

services:
  traefik2:
    image: traefik:latest
    restart: always
    command:
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
    ports:
      - 80:80
      - 443:443
    networks:
      traefik:
        ipv4_address: 172.19.0.10
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    container_name: traefik

  adguard:
    image: adguard/adguardhome
    restart: always
    ports:
      - 53:53/tcp
      - 53:53/udp
      - 67:67/udp
      - 853:853/tcp
      - 853:853/udp
      - 5443:5443/tcp
      - 5443:5443/udp
      - 8853:8853/udp
    networks:
      traefik:
        ipv4_address: 172.19.0.53
    volumes:
      - '~/homelabservices/adguard/work:/opt/adguardhome/work'
      - '~/homelabservices/adguard/conf:/opt/adguardhome/conf'
    container_name: adguard
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.adguard.rule=Host(`adguardtest.cloud.local`)"
      - "traefik.http.routers.adguard.tls=true"
      - "traefik.http.routers.adguard.entrypoints=websecure"
      - "traefik.http.services.adguard.loadbalancer.server.port=3000"

networks:
  traefik:
    driver: bridge
    name: traefik
    ipam:
      driver: default
      config:
        - subnet: 172.19.0.0/16

19. Wazuh

Wazuh is an excellent open-source security platform, designed to offer a security solution for home labs and businesses. With Wazuh, you can efficiently log and have visibility to security events, helping SecOps with network security.

Read my recent Wuzah write-up here: Wazuh Open Source SIEM: XDR for Enterprise and Home Lab.

19 wazuh is a self hosted security solution with an enterprise feel
19 wazuh is a self hosted security solution with an enterprise feel

Pros:

  • Great security features and capabilities

  • Modern interface with an enterprise feel for open-source software

  • Supports multiple users, facilitating team collaboration.

Cons:

  • Initial setup may be complex to get things dialed in

  • Security tools require some knowledge base of how to use them

Docker Compose: Wazuh uses an installation script instead of Docker Compose code:

curl -sO https://packages.wazuh.com/4.5/wazuh-install.sh && sudo bash ./wazuh-install.sh -a

20. Mailrise

Mailrise is built on the Apprise notification framework and allows you to have access to modern notification systems, including push notifications, even for legacy SMTP-enabled devices. It translates SMTP notification into push notifications.

20 mailrise is an excellent solution to migrate from legacy smtp to modern push notifications
20 mailrise is an excellent solution to migrate from legacy smtp to modern push notifications

Read my writeup on Mailrise here: IoT Notification System Push Notifications for Home Lab no SMTP required.

Pros:

  • Easy to setup in a Docker container

  • Provides integrations to over 50+ notification services

  • Requires no additional setup on your devices aside from pointing SMTP notifications to the mailrise server

Cons:

  • May be more complicated for some who are not technical

  • Services like Pushover do require a subscription

Docker Compose:

version: '3'
services:
  mailrise:
    image: yoryan/mailrise
    ports:
      - "8025:8025"
    volumes:
      - ~/mailrise/etc/mailrise.conf:/etc/mailrise.conf

Wrapping up

These are only 20 of the best self-hosted apps in 2023 that you can run. You may have other favorites in your self-hosted environment and home lab. Let me know in the comments if you have favorites that weren’t included in the list and let me know what you are running. There are so many apps out there that provide tremendous value to the community and the self-hosted environment.

Subscribe to VirtualizationHowto via Email ๐Ÿ””

Enter your email address to subscribe to this blog and receive notifications of new posts by email.



Brandon Lee

Brandon Lee is the Senior Writer, Engineer and owner at Virtualizationhowto.com, and a 7-time VMware vExpert, with over two decades of experience in Information Technology. Having worked for numerous Fortune 500 companies as well as in various industries, He has extensive experience in various IT segments and is a strong advocate for open source technologies. Brandon holds many industry certifications, loves the outdoors and spending time with family. Also, he goes through the effort of testing and troubleshooting issues, so you don't have to.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.